2011-05-23 21:40:23 +00:00
|
|
|
//===-- ClangUserExpression.cpp ---------------------------------*- C++ -*-===//
|
This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
llvm-svn: 112249
2010-08-27 01:01:44 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
llvm-svn: 112249
2010-08-27 01:01:44 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#if HAVE_SYS_TYPES_H
|
2016-09-06 20:57:50 +00:00
|
|
|
#include <sys/types.h>
|
This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
llvm-svn: 112249
2010-08-27 01:01:44 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <map>
|
2016-09-06 20:57:50 +00:00
|
|
|
#include <string>
|
This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
llvm-svn: 112249
2010-08-27 01:01:44 +00:00
|
|
|
|
2015-09-25 20:35:58 +00:00
|
|
|
#include "ClangUserExpression.h"
|
|
|
|
|
|
|
|
#include "ASTResultSynthesizer.h"
|
2016-09-06 20:57:50 +00:00
|
|
|
#include "ClangDiagnostic.h"
|
2015-09-25 20:35:58 +00:00
|
|
|
#include "ClangExpressionDeclMap.h"
|
|
|
|
#include "ClangExpressionParser.h"
|
2019-03-06 22:43:25 +00:00
|
|
|
#include "ClangExpressionSourceCode.h"
|
2015-09-25 20:35:58 +00:00
|
|
|
#include "ClangModulesDeclVendor.h"
|
|
|
|
#include "ClangPersistentVariables.h"
|
|
|
|
|
2016-06-22 17:32:17 +00:00
|
|
|
#include "lldb/Core/Debugger.h"
|
2014-03-24 23:10:19 +00:00
|
|
|
#include "lldb/Core/Module.h"
|
2011-01-18 19:36:39 +00:00
|
|
|
#include "lldb/Core/StreamFile.h"
|
2010-10-05 03:13:51 +00:00
|
|
|
#include "lldb/Core/ValueObjectConstResult.h"
|
2011-09-26 18:45:31 +00:00
|
|
|
#include "lldb/Expression/ExpressionSourceCode.h"
|
2013-04-16 23:25:35 +00:00
|
|
|
#include "lldb/Expression/IRExecutionUnit.h"
|
This commit changes the way LLDB executes user
expressions.
Previously, ClangUserExpression assumed that if
there was a constant result for an expression
then it could be determined during parsing. In
particular, the IRInterpreter ran while parser
state (in particular, ClangExpressionDeclMap)
was present. This approach is flawed, because
the IRInterpreter actually is capable of using
external variables, and hence the result might
be different each run. Until now, we papered
over this flaw by re-parsing the expression each
time we ran it.
I have rewritten the IRInterpreter to be
completely independent of the ClangExpressionDeclMap.
Instead of special-casing external variable lookup,
which ties the IRInterpreter closely to LLDB,
we now interpret the exact same IR that the JIT
would see. This IR assumes that materialization
has occurred; hence the recent implementation of the
Materializer, which does not require parser state
(in the form of ClangExpressionDeclMap) to be
present.
Materialization, interpretation, and dematerialization
are now all independent of parsing. This means that
in theory we can parse expressions once and run them
many times. I have three outstanding tasks before
shutting this down:
- First, I will ensure that all of this works with
core files. Core files have a Process but do not
allow allocating memory, which currently confuses
materialization.
- Second, I will make expression breakpoint
conditions remember their ClangUserExpression and
re-use it.
- Third, I will tear out all the redundant code
(for example, materialization logic in
ClangExpressionDeclMap) that is no longer used.
While implementing this fix, I also found a bug in
IRForTarget's handling of floating-point constants.
This should be fixed.
llvm-svn: 179801
2013-04-18 22:06:33 +00:00
|
|
|
#include "lldb/Expression/IRInterpreter.h"
|
2013-04-11 00:09:05 +00:00
|
|
|
#include "lldb/Expression/Materializer.h"
|
2014-08-19 17:18:29 +00:00
|
|
|
#include "lldb/Host/HostInfo.h"
|
<rdar://problem/11757916>
Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes:
- Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file".
- modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly
- Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was.
- modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile()
Cleaned up header includes a bit as well.
llvm-svn: 162860
2012-08-29 21:13:06 +00:00
|
|
|
#include "lldb/Symbol/Block.h"
|
2012-10-30 23:35:54 +00:00
|
|
|
#include "lldb/Symbol/ClangASTContext.h"
|
2016-09-06 20:57:50 +00:00
|
|
|
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
|
2012-10-30 23:35:54 +00:00
|
|
|
#include "lldb/Symbol/Function.h"
|
2014-03-24 23:10:19 +00:00
|
|
|
#include "lldb/Symbol/ObjectFile.h"
|
|
|
|
#include "lldb/Symbol/SymbolVendor.h"
|
2012-10-30 23:35:54 +00:00
|
|
|
#include "lldb/Symbol/Type.h"
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 00:44:12 +00:00
|
|
|
#include "lldb/Symbol/VariableList.h"
|
This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
llvm-svn: 112249
2010-08-27 01:01:44 +00:00
|
|
|
#include "lldb/Target/ExecutionContext.h"
|
2010-11-04 01:54:29 +00:00
|
|
|
#include "lldb/Target/Process.h"
|
2013-11-04 09:33:30 +00:00
|
|
|
#include "lldb/Target/StackFrame.h"
|
This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
llvm-svn: 112249
2010-08-27 01:01:44 +00:00
|
|
|
#include "lldb/Target/Target.h"
|
2010-11-30 02:22:11 +00:00
|
|
|
#include "lldb/Target/ThreadPlan.h"
|
|
|
|
#include "lldb/Target/ThreadPlanCallUserExpression.h"
|
2017-02-02 21:39:50 +00:00
|
|
|
#include "lldb/Utility/ConstString.h"
|
2017-03-03 20:56:28 +00:00
|
|
|
#include "lldb/Utility/Log.h"
|
2017-02-02 21:39:50 +00:00
|
|
|
#include "lldb/Utility/StreamString.h"
|
This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
llvm-svn: 112249
2010-08-27 01:01:44 +00:00
|
|
|
|
2011-08-05 23:43:37 +00:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
|
|
|
#include "clang/AST/DeclObjC.h"
|
|
|
|
|
This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
llvm-svn: 112249
2010-08-27 01:01:44 +00:00
|
|
|
using namespace lldb_private;
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
ClangUserExpression::ClangUserExpression(
|
2016-11-08 04:52:16 +00:00
|
|
|
ExecutionContextScope &exe_scope, llvm::StringRef expr,
|
|
|
|
llvm::StringRef prefix, lldb::LanguageType language,
|
2019-02-05 09:14:36 +00:00
|
|
|
ResultType desired_type, const EvaluateExpressionOptions &options,
|
|
|
|
ValueObject *ctx_obj)
|
2016-11-08 04:52:16 +00:00
|
|
|
: LLVMUserExpression(exe_scope, expr, prefix, language, desired_type,
|
2016-09-06 20:57:50 +00:00
|
|
|
options),
|
2019-02-12 03:47:39 +00:00
|
|
|
m_type_system_helper(*m_target_wp.lock(), options.GetExecutionPolicy() ==
|
|
|
|
eExecutionPolicyTopLevel),
|
|
|
|
m_result_delegate(exe_scope.CalculateTarget()), m_ctx_obj(ctx_obj) {
|
2016-09-06 20:57:50 +00:00
|
|
|
switch (m_language) {
|
|
|
|
case lldb::eLanguageTypeC_plus_plus:
|
|
|
|
m_allow_cxx = true;
|
|
|
|
break;
|
|
|
|
case lldb::eLanguageTypeObjC:
|
|
|
|
m_allow_objc = true;
|
|
|
|
break;
|
|
|
|
case lldb::eLanguageTypeObjC_plus_plus:
|
|
|
|
default:
|
|
|
|
m_allow_cxx = true;
|
|
|
|
m_allow_objc = true;
|
|
|
|
break;
|
|
|
|
}
|
This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
llvm-svn: 112249
2010-08-27 01:01:44 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
ClangUserExpression::~ClangUserExpression() {}
|
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) {
|
2016-09-06 20:57:50 +00:00
|
|
|
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
|
This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
llvm-svn: 112249
2010-08-27 01:01:44 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (log)
|
|
|
|
log->Printf("ClangUserExpression::ScanContext()");
|
2012-12-01 00:08:33 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
m_target = exe_ctx.GetTargetPtr();
|
|
|
|
|
|
|
|
if (!(m_allow_cxx || m_allow_objc)) {
|
2012-12-01 00:08:33 +00:00
|
|
|
if (log)
|
2016-09-06 20:57:50 +00:00
|
|
|
log->Printf(" [CUE::SC] Settings inhibit C++ and Objective-C");
|
|
|
|
return;
|
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
StackFrame *frame = exe_ctx.GetFramePtr();
|
|
|
|
if (frame == NULL) {
|
|
|
|
if (log)
|
|
|
|
log->Printf(" [CUE::SC] Null stack frame");
|
|
|
|
return;
|
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction |
|
|
|
|
lldb::eSymbolContextBlock);
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (!sym_ctx.function) {
|
|
|
|
if (log)
|
|
|
|
log->Printf(" [CUE::SC] Null function");
|
|
|
|
return;
|
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
// Find the block that defines the function represented by "sym_ctx"
|
|
|
|
Block *function_block = sym_ctx.GetFunctionBlock();
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (!function_block) {
|
|
|
|
if (log)
|
|
|
|
log->Printf(" [CUE::SC] Null function block");
|
|
|
|
return;
|
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
CompilerDeclContext decl_context = function_block->GetDeclContext();
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (!decl_context) {
|
|
|
|
if (log)
|
|
|
|
log->Printf(" [CUE::SC] Null decl context");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-05 09:14:36 +00:00
|
|
|
if (m_ctx_obj) {
|
|
|
|
switch (m_ctx_obj->GetObjectRuntimeLanguage()) {
|
|
|
|
case lldb::eLanguageTypeC:
|
|
|
|
case lldb::eLanguageTypeC89:
|
|
|
|
case lldb::eLanguageTypeC99:
|
|
|
|
case lldb::eLanguageTypeC11:
|
|
|
|
case lldb::eLanguageTypeC_plus_plus:
|
|
|
|
case lldb::eLanguageTypeC_plus_plus_03:
|
|
|
|
case lldb::eLanguageTypeC_plus_plus_11:
|
|
|
|
case lldb::eLanguageTypeC_plus_plus_14:
|
|
|
|
m_in_cplusplus_method = true;
|
|
|
|
break;
|
|
|
|
case lldb::eLanguageTypeObjC:
|
|
|
|
case lldb::eLanguageTypeObjC_plus_plus:
|
|
|
|
m_in_objectivec_method = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
m_needs_object_ptr = true;
|
|
|
|
} else if (clang::CXXMethodDecl *method_decl =
|
2016-09-06 20:57:50 +00:00
|
|
|
ClangASTContext::DeclContextGetAsCXXMethodDecl(decl_context)) {
|
|
|
|
if (m_allow_cxx && method_decl->isInstance()) {
|
|
|
|
if (m_enforce_valid_object) {
|
|
|
|
lldb::VariableListSP variable_list_sp(
|
|
|
|
function_block->GetBlockVariableList(true));
|
|
|
|
|
|
|
|
const char *thisErrorString = "Stopped in a C++ method, but 'this' "
|
|
|
|
"isn't available; pretending we are in a "
|
|
|
|
"generic context";
|
|
|
|
|
|
|
|
if (!variable_list_sp) {
|
|
|
|
err.SetErrorString(thisErrorString);
|
|
|
|
return;
|
|
|
|
}
|
2012-07-14 00:53:55 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
lldb::VariableSP this_var_sp(
|
|
|
|
variable_list_sp->FindVariable(ConstString("this")));
|
|
|
|
|
|
|
|
if (!this_var_sp || !this_var_sp->IsInScope(frame) ||
|
|
|
|
!this_var_sp->LocationIsValidForFrame(frame)) {
|
|
|
|
err.SetErrorString(thisErrorString);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2012-07-14 00:53:55 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
m_in_cplusplus_method = true;
|
|
|
|
m_needs_object_ptr = true;
|
2012-12-01 00:08:33 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
} else if (clang::ObjCMethodDecl *method_decl =
|
|
|
|
ClangASTContext::DeclContextGetAsObjCMethodDecl(
|
|
|
|
decl_context)) {
|
|
|
|
if (m_allow_objc) {
|
|
|
|
if (m_enforce_valid_object) {
|
|
|
|
lldb::VariableListSP variable_list_sp(
|
|
|
|
function_block->GetBlockVariableList(true));
|
|
|
|
|
|
|
|
const char *selfErrorString = "Stopped in an Objective-C method, but "
|
|
|
|
"'self' isn't available; pretending we "
|
|
|
|
"are in a generic context";
|
|
|
|
|
|
|
|
if (!variable_list_sp) {
|
|
|
|
err.SetErrorString(selfErrorString);
|
|
|
|
return;
|
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
lldb::VariableSP self_variable_sp =
|
|
|
|
variable_list_sp->FindVariable(ConstString("self"));
|
|
|
|
|
|
|
|
if (!self_variable_sp || !self_variable_sp->IsInScope(frame) ||
|
|
|
|
!self_variable_sp->LocationIsValidForFrame(frame)) {
|
|
|
|
err.SetErrorString(selfErrorString);
|
|
|
|
return;
|
2010-12-01 21:35:54 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m_in_objectivec_method = true;
|
|
|
|
m_needs_object_ptr = true;
|
|
|
|
|
|
|
|
if (!method_decl->isInstanceMethod())
|
|
|
|
m_in_static_method = true;
|
2010-12-01 21:35:54 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
} else if (clang::FunctionDecl *function_decl =
|
|
|
|
ClangASTContext::DeclContextGetAsFunctionDecl(decl_context)) {
|
|
|
|
// We might also have a function that said in the debug information that it
|
2018-04-30 16:49:04 +00:00
|
|
|
// captured an object pointer. The best way to deal with getting to the
|
|
|
|
// ivars at present is by pretending that this is a method of a class in
|
|
|
|
// whatever runtime the debug info says the object pointer belongs to. Do
|
|
|
|
// that here.
|
2016-09-06 20:57:50 +00:00
|
|
|
|
|
|
|
ClangASTMetadata *metadata =
|
|
|
|
ClangASTContext::DeclContextGetMetaData(decl_context, function_decl);
|
|
|
|
if (metadata && metadata->HasObjectPtr()) {
|
|
|
|
lldb::LanguageType language = metadata->GetObjectPtrLanguage();
|
|
|
|
if (language == lldb::eLanguageTypeC_plus_plus) {
|
|
|
|
if (m_enforce_valid_object) {
|
|
|
|
lldb::VariableListSP variable_list_sp(
|
|
|
|
function_block->GetBlockVariableList(true));
|
|
|
|
|
|
|
|
const char *thisErrorString = "Stopped in a context claiming to "
|
|
|
|
"capture a C++ object pointer, but "
|
|
|
|
"'this' isn't available; pretending we "
|
|
|
|
"are in a generic context";
|
|
|
|
|
|
|
|
if (!variable_list_sp) {
|
|
|
|
err.SetErrorString(thisErrorString);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
lldb::VariableSP this_var_sp(
|
|
|
|
variable_list_sp->FindVariable(ConstString("this")));
|
|
|
|
|
|
|
|
if (!this_var_sp || !this_var_sp->IsInScope(frame) ||
|
|
|
|
!this_var_sp->LocationIsValidForFrame(frame)) {
|
|
|
|
err.SetErrorString(thisErrorString);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
m_in_cplusplus_method = true;
|
|
|
|
m_needs_object_ptr = true;
|
|
|
|
} else if (language == lldb::eLanguageTypeObjC) {
|
|
|
|
if (m_enforce_valid_object) {
|
|
|
|
lldb::VariableListSP variable_list_sp(
|
|
|
|
function_block->GetBlockVariableList(true));
|
|
|
|
|
|
|
|
const char *selfErrorString =
|
|
|
|
"Stopped in a context claiming to capture an Objective-C object "
|
|
|
|
"pointer, but 'self' isn't available; pretending we are in a "
|
|
|
|
"generic context";
|
|
|
|
|
|
|
|
if (!variable_list_sp) {
|
|
|
|
err.SetErrorString(selfErrorString);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
lldb::VariableSP self_variable_sp =
|
|
|
|
variable_list_sp->FindVariable(ConstString("self"));
|
|
|
|
|
|
|
|
if (!self_variable_sp || !self_variable_sp->IsInScope(frame) ||
|
|
|
|
!self_variable_sp->LocationIsValidForFrame(frame)) {
|
|
|
|
err.SetErrorString(selfErrorString);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Type *self_type = self_variable_sp->GetType();
|
|
|
|
|
|
|
|
if (!self_type) {
|
|
|
|
err.SetErrorString(selfErrorString);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CompilerType self_clang_type = self_type->GetForwardCompilerType();
|
|
|
|
|
|
|
|
if (!self_clang_type) {
|
|
|
|
err.SetErrorString(selfErrorString);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ClangASTContext::IsObjCClassType(self_clang_type)) {
|
|
|
|
return;
|
|
|
|
} else if (ClangASTContext::IsObjCObjectPointerType(
|
|
|
|
self_clang_type)) {
|
2015-07-01 00:54:02 +00:00
|
|
|
m_in_objectivec_method = true;
|
2011-09-26 18:45:31 +00:00
|
|
|
m_needs_object_ptr = true;
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
|
|
|
err.SetErrorString(selfErrorString);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
m_in_objectivec_method = true;
|
|
|
|
m_needs_object_ptr = true;
|
2012-10-30 23:35:54 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2012-10-30 23:35:54 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 00:44:12 +00:00
|
|
|
}
|
|
|
|
|
2018-04-30 16:49:04 +00:00
|
|
|
// This is a really nasty hack, meant to fix Objective-C expressions of the
|
|
|
|
// form (int)[myArray count]. Right now, because the type information for
|
|
|
|
// count is not available, [myArray count] returns id, which can't be directly
|
|
|
|
// cast to int without causing a clang error.
|
2016-09-06 20:57:50 +00:00
|
|
|
static void ApplyObjcCastHack(std::string &expr) {
|
2010-10-22 23:25:16 +00:00
|
|
|
#define OBJC_CAST_HACK_FROM "(int)["
|
2016-09-06 20:57:50 +00:00
|
|
|
#define OBJC_CAST_HACK_TO "(int)(long long)["
|
2010-10-22 23:25:16 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
size_t from_offset;
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
while ((from_offset = expr.find(OBJC_CAST_HACK_FROM)) != expr.npos)
|
|
|
|
expr.replace(from_offset, sizeof(OBJC_CAST_HACK_FROM) - 1,
|
|
|
|
OBJC_CAST_HACK_TO);
|
2010-10-22 23:25:16 +00:00
|
|
|
|
|
|
|
#undef OBJC_CAST_HACK_TO
|
|
|
|
#undef OBJC_CAST_HACK_FROM
|
|
|
|
}
|
|
|
|
|
2018-06-19 21:25:59 +00:00
|
|
|
namespace {
|
|
|
|
// Utility guard that calls a callback when going out of scope.
|
|
|
|
class OnExit {
|
|
|
|
public:
|
|
|
|
typedef std::function<void(void)> Callback;
|
|
|
|
|
|
|
|
OnExit(Callback const &callback) : m_callback(callback) {}
|
|
|
|
|
|
|
|
~OnExit() { m_callback(); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
Callback m_callback;
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
2018-07-10 22:12:39 +00:00
|
|
|
bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_manager,
|
|
|
|
ExecutionContext &exe_ctx) {
|
2016-09-06 20:57:50 +00:00
|
|
|
if (Target *target = exe_ctx.GetTargetPtr()) {
|
|
|
|
if (PersistentExpressionState *persistent_state =
|
|
|
|
target->GetPersistentExpressionStateForLanguage(
|
|
|
|
lldb::eLanguageTypeC)) {
|
|
|
|
m_result_delegate.RegisterPersistentState(persistent_state);
|
|
|
|
} else {
|
2016-11-12 19:12:56 +00:00
|
|
|
diagnostic_manager.PutString(
|
2016-09-06 20:57:50 +00:00
|
|
|
eDiagnosticSeverityError,
|
|
|
|
"couldn't start parsing (no persistent data)");
|
|
|
|
return false;
|
2015-10-03 09:09:01 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
2016-11-12 19:12:56 +00:00
|
|
|
diagnostic_manager.PutString(eDiagnosticSeverityError,
|
|
|
|
"error: couldn't start parsing (no target)");
|
2016-09-06 20:57:50 +00:00
|
|
|
return false;
|
|
|
|
}
|
2018-07-10 22:12:39 +00:00
|
|
|
return true;
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2018-07-10 22:12:39 +00:00
|
|
|
static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target) {
|
2016-09-06 20:57:50 +00:00
|
|
|
if (ClangModulesDeclVendor *decl_vendor =
|
2018-07-10 22:12:39 +00:00
|
|
|
target->GetClangModulesDeclVendor()) {
|
2016-09-06 20:57:50 +00:00
|
|
|
const ClangModulesDeclVendor::ModuleVector &hand_imported_modules =
|
|
|
|
llvm::cast<ClangPersistentVariables>(
|
2018-07-10 22:12:39 +00:00
|
|
|
target->GetPersistentExpressionStateForLanguage(
|
2016-09-06 20:57:50 +00:00
|
|
|
lldb::eLanguageTypeC))
|
|
|
|
->GetHandLoadedClangModules();
|
|
|
|
ClangModulesDeclVendor::ModuleVector modules_for_macros;
|
|
|
|
|
|
|
|
for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) {
|
|
|
|
modules_for_macros.push_back(module);
|
2015-10-03 09:09:01 +00:00
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2018-07-10 22:12:39 +00:00
|
|
|
if (target->GetEnableAutoImportClangModules()) {
|
2016-09-06 20:57:50 +00:00
|
|
|
if (StackFrame *frame = exe_ctx.GetFramePtr()) {
|
|
|
|
if (Block *block = frame->GetFrameBlock()) {
|
|
|
|
SymbolContext sc;
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
block->CalculateSymbolContext(&sc);
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (sc.comp_unit) {
|
|
|
|
StreamString error_stream;
|
2015-04-20 16:31:29 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
decl_vendor->AddModulesForCompileUnit(
|
|
|
|
*sc.comp_unit, modules_for_macros, error_stream);
|
|
|
|
}
|
2015-04-20 16:31:29 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-04-14 18:36:17 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2018-07-10 22:12:39 +00:00
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2018-09-27 10:12:54 +00:00
|
|
|
void ClangUserExpression::UpdateLanguageForExpr(
|
2018-07-10 22:12:39 +00:00
|
|
|
DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
|
2018-09-27 10:12:54 +00:00
|
|
|
m_expr_lang = lldb::LanguageType::eLanguageTypeUnknown;
|
2018-07-10 22:12:39 +00:00
|
|
|
|
|
|
|
std::string prefix = m_expr_prefix;
|
2016-03-29 22:00:08 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {
|
|
|
|
m_transformed_text = m_expr_text;
|
|
|
|
} else {
|
2019-03-06 22:43:25 +00:00
|
|
|
std::unique_ptr<ClangExpressionSourceCode> source_code(
|
|
|
|
ClangExpressionSourceCode::CreateWrapped(prefix.c_str(),
|
2016-09-06 20:57:50 +00:00
|
|
|
m_expr_text.c_str()));
|
|
|
|
|
|
|
|
if (m_in_cplusplus_method)
|
2018-09-27 10:12:54 +00:00
|
|
|
m_expr_lang = lldb::eLanguageTypeC_plus_plus;
|
2016-09-06 20:57:50 +00:00
|
|
|
else if (m_in_objectivec_method)
|
2018-09-27 10:12:54 +00:00
|
|
|
m_expr_lang = lldb::eLanguageTypeObjC;
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 00:44:12 +00:00
|
|
|
else
|
2018-09-27 10:12:54 +00:00
|
|
|
m_expr_lang = lldb::eLanguageTypeC;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2018-09-27 10:12:54 +00:00
|
|
|
if (!source_code->GetText(m_transformed_text, m_expr_lang,
|
2019-02-05 09:14:36 +00:00
|
|
|
m_in_static_method, exe_ctx,
|
|
|
|
!m_ctx_obj)) {
|
2016-11-12 19:12:56 +00:00
|
|
|
diagnostic_manager.PutString(eDiagnosticSeverityError,
|
|
|
|
"couldn't construct expression body");
|
2018-09-27 10:12:54 +00:00
|
|
|
return;
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 00:44:12 +00:00
|
|
|
}
|
2018-08-30 17:29:37 +00:00
|
|
|
|
|
|
|
// Find and store the start position of the original code inside the
|
|
|
|
// transformed code. We need this later for the code completion.
|
|
|
|
std::size_t original_start;
|
|
|
|
std::size_t original_end;
|
|
|
|
bool found_bounds = source_code->GetOriginalBodyBounds(
|
2018-09-27 10:12:54 +00:00
|
|
|
m_transformed_text, m_expr_lang, original_start, original_end);
|
2018-08-30 17:29:37 +00:00
|
|
|
if (found_bounds) {
|
|
|
|
m_user_expression_start_pos = original_start;
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2018-07-10 22:12:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ClangUserExpression::PrepareForParsing(
|
|
|
|
DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
|
|
|
|
InstallContext(exe_ctx);
|
|
|
|
|
|
|
|
if (!SetupPersistentState(diagnostic_manager, exe_ctx))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Status err;
|
|
|
|
ScanContext(exe_ctx, err);
|
|
|
|
|
|
|
|
if (!err.Success()) {
|
|
|
|
diagnostic_manager.PutString(eDiagnosticSeverityWarning, err.AsCString());
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////
|
|
|
|
// Generate the expression
|
|
|
|
//
|
|
|
|
|
|
|
|
ApplyObjcCastHack(m_expr_text);
|
|
|
|
|
|
|
|
SetupDeclVendor(exe_ctx, m_target);
|
2018-09-27 10:12:54 +00:00
|
|
|
|
|
|
|
UpdateLanguageForExpr(diagnostic_manager, exe_ctx);
|
2018-07-10 22:12:39 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
|
|
|
|
ExecutionContext &exe_ctx,
|
|
|
|
lldb_private::ExecutionPolicy execution_policy,
|
|
|
|
bool keep_result_in_memory,
|
|
|
|
bool generate_debug_info) {
|
|
|
|
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
|
|
|
|
|
|
|
|
if (!PrepareForParsing(diagnostic_manager, exe_ctx))
|
|
|
|
return false;
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (log)
|
|
|
|
log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str());
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
////////////////////////////////////
|
|
|
|
// Set up the target and compiler
|
|
|
|
//
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
Target *target = exe_ctx.GetTargetPtr();
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (!target) {
|
2016-11-12 19:12:56 +00:00
|
|
|
diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target");
|
2016-09-06 20:57:50 +00:00
|
|
|
return false;
|
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
//////////////////////////
|
|
|
|
// Parse the expression
|
|
|
|
//
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2019-02-13 06:25:41 +00:00
|
|
|
m_materializer_up.reset(new Materializer());
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory);
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
OnExit on_exit([this]() { ResetDeclMap(); });
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2019-02-13 06:25:41 +00:00
|
|
|
if (!DeclMap()->WillParse(exe_ctx, m_materializer_up.get())) {
|
2016-11-12 19:12:56 +00:00
|
|
|
diagnostic_manager.PutString(
|
2016-09-06 20:57:50 +00:00
|
|
|
eDiagnosticSeverityError,
|
|
|
|
"current process state is unsuitable for expression parsing");
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-22 21:05:51 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {
|
|
|
|
DeclMap()->SetLookupsEnabled(true);
|
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
Process *process = exe_ctx.GetProcessPtr();
|
|
|
|
ExecutionContextScope *exe_scope = process;
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (!exe_scope)
|
|
|
|
exe_scope = exe_ctx.GetTargetPtr();
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
// We use a shared pointer here so we can use the original parser - if it
|
2018-04-30 16:49:04 +00:00
|
|
|
// succeeds or the rewrite parser we might make if it fails. But the
|
|
|
|
// parser_sp will never be empty.
|
2016-09-06 20:57:50 +00:00
|
|
|
|
|
|
|
ClangExpressionParser parser(exe_scope, *this, generate_debug_info);
|
|
|
|
|
|
|
|
unsigned num_errors = parser.Parse(diagnostic_manager);
|
|
|
|
|
|
|
|
// Check here for FixItHints. If there are any try to apply the fixits and
|
2018-04-30 16:49:04 +00:00
|
|
|
// set the fixed text in m_fixed_text before returning an error.
|
2016-09-06 20:57:50 +00:00
|
|
|
if (num_errors) {
|
|
|
|
if (diagnostic_manager.HasFixIts()) {
|
|
|
|
if (parser.RewriteExpression(diagnostic_manager)) {
|
|
|
|
size_t fixed_start;
|
|
|
|
size_t fixed_end;
|
|
|
|
const std::string &fixed_expression =
|
|
|
|
diagnostic_manager.GetFixedExpression();
|
2019-03-06 22:43:25 +00:00
|
|
|
if (ClangExpressionSourceCode::GetOriginalBodyBounds(
|
2018-09-27 10:12:54 +00:00
|
|
|
fixed_expression, m_expr_lang, fixed_start, fixed_end))
|
2016-09-06 20:57:50 +00:00
|
|
|
m_fixed_text =
|
|
|
|
fixed_expression.substr(fixed_start, fixed_end - fixed_start);
|
|
|
|
}
|
2016-03-22 21:05:51 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
2018-04-30 16:49:04 +00:00
|
|
|
// Prepare the output of the parser for execution, evaluating it statically
|
|
|
|
// if possible
|
2016-09-06 20:57:50 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
{
|
2017-05-12 04:51:55 +00:00
|
|
|
Status jit_error = parser.PrepareForExecution(
|
2016-09-06 20:57:50 +00:00
|
|
|
m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,
|
|
|
|
m_can_interpret, execution_policy);
|
|
|
|
|
|
|
|
if (!jit_error.Success()) {
|
|
|
|
const char *error_cstr = jit_error.AsCString();
|
|
|
|
if (error_cstr && error_cstr[0])
|
2016-11-12 19:12:56 +00:00
|
|
|
diagnostic_manager.PutString(eDiagnosticSeverityError, error_cstr);
|
2016-09-06 20:57:50 +00:00
|
|
|
else
|
2016-11-12 19:12:56 +00:00
|
|
|
diagnostic_manager.PutString(eDiagnosticSeverityError,
|
|
|
|
"expression can't be interpreted or run");
|
2016-09-06 20:57:50 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (exe_ctx.GetProcessPtr() && execution_policy == eExecutionPolicyTopLevel) {
|
2017-05-12 04:51:55 +00:00
|
|
|
Status static_init_error =
|
2016-09-06 20:57:50 +00:00
|
|
|
parser.RunStaticInitializers(m_execution_unit_sp, exe_ctx);
|
|
|
|
|
|
|
|
if (!static_init_error.Success()) {
|
|
|
|
const char *error_cstr = static_init_error.AsCString();
|
|
|
|
if (error_cstr && error_cstr[0])
|
|
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError,
|
|
|
|
"couldn't run static initializers: %s\n",
|
|
|
|
error_cstr);
|
|
|
|
else
|
2016-11-12 19:12:56 +00:00
|
|
|
diagnostic_manager.PutString(eDiagnosticSeverityError,
|
|
|
|
"couldn't run static initializers\n");
|
2016-09-06 20:57:50 +00:00
|
|
|
return false;
|
2016-03-22 21:05:51 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2016-03-22 21:05:51 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (m_execution_unit_sp) {
|
|
|
|
bool register_execution_unit = false;
|
2016-03-22 21:05:51 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {
|
|
|
|
register_execution_unit = true;
|
|
|
|
}
|
2016-03-22 21:05:51 +00:00
|
|
|
|
2018-04-30 16:49:04 +00:00
|
|
|
// If there is more than one external function in the execution unit, it
|
|
|
|
// needs to keep living even if it's not top level, because the result
|
|
|
|
// could refer to that function.
|
2016-09-06 20:57:50 +00:00
|
|
|
|
|
|
|
if (m_execution_unit_sp->GetJittedFunctions().size() > 1) {
|
|
|
|
register_execution_unit = true;
|
2016-03-22 21:05:51 +00:00
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (register_execution_unit) {
|
|
|
|
llvm::cast<PersistentExpressionState>(
|
|
|
|
exe_ctx.GetTargetPtr()->GetPersistentExpressionStateForLanguage(
|
|
|
|
m_language))
|
|
|
|
->RegisterExecutionUnit(m_execution_unit_sp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (generate_debug_info) {
|
|
|
|
lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule());
|
|
|
|
|
|
|
|
if (jit_module_sp) {
|
|
|
|
ConstString const_func_name(FunctionName());
|
|
|
|
FileSpec jit_file;
|
|
|
|
jit_file.GetFilename() = const_func_name;
|
|
|
|
jit_module_sp->SetFileSpecAndObjectName(jit_file, ConstString());
|
|
|
|
m_jit_module_wp = jit_module_sp;
|
|
|
|
target->GetImages().Append(jit_module_sp);
|
2014-03-24 23:10:19 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS)
|
|
|
|
m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
|
|
|
|
return true;
|
This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
llvm-svn: 112249
2010-08-27 01:01:44 +00:00
|
|
|
}
|
|
|
|
|
2018-08-30 17:29:37 +00:00
|
|
|
//------------------------------------------------------------------
|
|
|
|
/// Converts an absolute position inside a given code string into
|
|
|
|
/// a column/line pair.
|
|
|
|
///
|
|
|
|
/// @param[in] abs_pos
|
|
|
|
/// A absolute position in the code string that we want to convert
|
|
|
|
/// to a column/line pair.
|
|
|
|
///
|
|
|
|
/// @param[in] code
|
|
|
|
/// A multi-line string usually representing source code.
|
|
|
|
///
|
|
|
|
/// @param[out] line
|
|
|
|
/// The line in the code that contains the given absolute position.
|
|
|
|
/// The first line in the string is indexed as 1.
|
|
|
|
///
|
|
|
|
/// @param[out] column
|
|
|
|
/// The column in the line that contains the absolute position.
|
|
|
|
/// The first character in a line is indexed as 0.
|
|
|
|
//------------------------------------------------------------------
|
2018-09-22 13:33:08 +00:00
|
|
|
static void AbsPosToLineColumnPos(size_t abs_pos, llvm::StringRef code,
|
2018-08-30 17:29:37 +00:00
|
|
|
unsigned &line, unsigned &column) {
|
|
|
|
// Reset to code position to beginning of the file.
|
|
|
|
line = 0;
|
|
|
|
column = 0;
|
|
|
|
|
|
|
|
assert(abs_pos <= code.size() && "Absolute position outside code string?");
|
|
|
|
|
|
|
|
// We have to walk up to the position and count lines/columns.
|
|
|
|
for (std::size_t i = 0; i < abs_pos; ++i) {
|
|
|
|
// If we hit a line break, we go back to column 0 and enter a new line.
|
|
|
|
// We only handle \n because that's what we internally use to make new
|
|
|
|
// lines for our temporary code strings.
|
|
|
|
if (code[i] == '\n') {
|
|
|
|
++line;
|
|
|
|
column = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
++column;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ClangUserExpression::Complete(ExecutionContext &exe_ctx,
|
2018-08-30 21:26:32 +00:00
|
|
|
CompletionRequest &request,
|
|
|
|
unsigned complete_pos) {
|
2018-08-30 17:29:37 +00:00
|
|
|
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
|
|
|
|
|
|
|
|
// We don't want any visible feedback when completing an expression. Mostly
|
|
|
|
// because the results we get from an incomplete invocation are probably not
|
|
|
|
// correct.
|
|
|
|
DiagnosticManager diagnostic_manager;
|
|
|
|
|
|
|
|
if (!PrepareForParsing(diagnostic_manager, exe_ctx))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (log)
|
|
|
|
log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str());
|
|
|
|
|
|
|
|
//////////////////////////
|
|
|
|
// Parse the expression
|
|
|
|
//
|
|
|
|
|
2019-02-13 06:25:41 +00:00
|
|
|
m_materializer_up.reset(new Materializer());
|
2018-08-30 17:29:37 +00:00
|
|
|
|
|
|
|
ResetDeclMap(exe_ctx, m_result_delegate, /*keep result in memory*/ true);
|
|
|
|
|
|
|
|
OnExit on_exit([this]() { ResetDeclMap(); });
|
|
|
|
|
2019-02-13 06:25:41 +00:00
|
|
|
if (!DeclMap()->WillParse(exe_ctx, m_materializer_up.get())) {
|
2018-08-30 17:29:37 +00:00
|
|
|
diagnostic_manager.PutString(
|
|
|
|
eDiagnosticSeverityError,
|
|
|
|
"current process state is unsuitable for expression parsing");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {
|
|
|
|
DeclMap()->SetLookupsEnabled(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
Process *process = exe_ctx.GetProcessPtr();
|
|
|
|
ExecutionContextScope *exe_scope = process;
|
|
|
|
|
|
|
|
if (!exe_scope)
|
|
|
|
exe_scope = exe_ctx.GetTargetPtr();
|
|
|
|
|
|
|
|
ClangExpressionParser parser(exe_scope, *this, false);
|
|
|
|
|
|
|
|
// We have to find the source code location where the user text is inside
|
|
|
|
// the transformed expression code. When creating the transformed text, we
|
|
|
|
// already stored the absolute position in the m_transformed_text string. The
|
|
|
|
// only thing left to do is to transform it into the line:column format that
|
|
|
|
// Clang expects.
|
|
|
|
|
|
|
|
// The line and column of the user expression inside the transformed source
|
|
|
|
// code.
|
|
|
|
unsigned user_expr_line, user_expr_column;
|
|
|
|
if (m_user_expression_start_pos.hasValue())
|
|
|
|
AbsPosToLineColumnPos(*m_user_expression_start_pos, m_transformed_text,
|
|
|
|
user_expr_line, user_expr_column);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// The actual column where we have to complete is the start column of the
|
|
|
|
// user expression + the offset inside the user code that we were given.
|
|
|
|
const unsigned completion_column = user_expr_column + complete_pos;
|
2018-08-30 21:26:32 +00:00
|
|
|
parser.Complete(request, user_expr_line, completion_column, complete_pos);
|
2018-08-30 17:29:37 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx,
|
|
|
|
std::vector<lldb::addr_t> &args,
|
|
|
|
lldb::addr_t struct_address,
|
|
|
|
DiagnosticManager &diagnostic_manager) {
|
|
|
|
lldb::addr_t object_ptr = LLDB_INVALID_ADDRESS;
|
|
|
|
lldb::addr_t cmd_ptr = LLDB_INVALID_ADDRESS;
|
|
|
|
|
|
|
|
if (m_needs_object_ptr) {
|
|
|
|
lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP();
|
|
|
|
if (!frame_sp)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
ConstString object_name;
|
|
|
|
|
|
|
|
if (m_in_cplusplus_method) {
|
|
|
|
object_name.SetCString("this");
|
|
|
|
} else if (m_in_objectivec_method) {
|
|
|
|
object_name.SetCString("self");
|
|
|
|
} else {
|
2016-11-12 19:12:56 +00:00
|
|
|
diagnostic_manager.PutString(
|
2016-09-06 20:57:50 +00:00
|
|
|
eDiagnosticSeverityError,
|
|
|
|
"need object pointer but don't know the language");
|
|
|
|
return false;
|
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
Status object_ptr_error;
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2019-02-05 09:14:36 +00:00
|
|
|
if (m_ctx_obj) {
|
|
|
|
AddressType address_type;
|
|
|
|
object_ptr = m_ctx_obj->GetAddressOf(false, &address_type);
|
|
|
|
if (object_ptr == LLDB_INVALID_ADDRESS ||
|
|
|
|
address_type != eAddressTypeLoad)
|
|
|
|
object_ptr_error.SetErrorString("Can't get context object's "
|
|
|
|
"debuggee address");
|
|
|
|
} else
|
|
|
|
object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error);
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (!object_ptr_error.Success()) {
|
|
|
|
exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Printf(
|
2017-02-21 05:09:26 +00:00
|
|
|
"warning: `%s' is not accessible (substituting 0)\n",
|
2016-09-06 20:57:50 +00:00
|
|
|
object_name.AsCString());
|
|
|
|
object_ptr = 0;
|
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (m_in_objectivec_method) {
|
|
|
|
ConstString cmd_name("_cmd");
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
cmd_ptr = GetObjectPointer(frame_sp, cmd_name, object_ptr_error);
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (!object_ptr_error.Success()) {
|
|
|
|
diagnostic_manager.Printf(
|
|
|
|
eDiagnosticSeverityWarning,
|
|
|
|
"couldn't get cmd pointer (substituting NULL): %s",
|
|
|
|
object_ptr_error.AsCString());
|
|
|
|
cmd_ptr = 0;
|
|
|
|
}
|
|
|
|
}
|
This commit changes the way LLDB executes user
expressions.
Previously, ClangUserExpression assumed that if
there was a constant result for an expression
then it could be determined during parsing. In
particular, the IRInterpreter ran while parser
state (in particular, ClangExpressionDeclMap)
was present. This approach is flawed, because
the IRInterpreter actually is capable of using
external variables, and hence the result might
be different each run. Until now, we papered
over this flaw by re-parsing the expression each
time we ran it.
I have rewritten the IRInterpreter to be
completely independent of the ClangExpressionDeclMap.
Instead of special-casing external variable lookup,
which ties the IRInterpreter closely to LLDB,
we now interpret the exact same IR that the JIT
would see. This IR assumes that materialization
has occurred; hence the recent implementation of the
Materializer, which does not require parser state
(in the form of ClangExpressionDeclMap) to be
present.
Materialization, interpretation, and dematerialization
are now all independent of parsing. This means that
in theory we can parse expressions once and run them
many times. I have three outstanding tasks before
shutting this down:
- First, I will ensure that all of this works with
core files. Core files have a Process but do not
allow allocating memory, which currently confuses
materialization.
- Second, I will make expression breakpoint
conditions remember their ClangUserExpression and
re-use it.
- Third, I will tear out all the redundant code
(for example, materialization logic in
ClangExpressionDeclMap) that is no longer used.
While implementing this fix, I also found a bug in
IRForTarget's handling of floating-point constants.
This should be fixed.
llvm-svn: 179801
2013-04-18 22:06:33 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
args.push_back(object_ptr);
|
This commit changes the way LLDB executes user
expressions.
Previously, ClangUserExpression assumed that if
there was a constant result for an expression
then it could be determined during parsing. In
particular, the IRInterpreter ran while parser
state (in particular, ClangExpressionDeclMap)
was present. This approach is flawed, because
the IRInterpreter actually is capable of using
external variables, and hence the result might
be different each run. Until now, we papered
over this flaw by re-parsing the expression each
time we ran it.
I have rewritten the IRInterpreter to be
completely independent of the ClangExpressionDeclMap.
Instead of special-casing external variable lookup,
which ties the IRInterpreter closely to LLDB,
we now interpret the exact same IR that the JIT
would see. This IR assumes that materialization
has occurred; hence the recent implementation of the
Materializer, which does not require parser state
(in the form of ClangExpressionDeclMap) to be
present.
Materialization, interpretation, and dematerialization
are now all independent of parsing. This means that
in theory we can parse expressions once and run them
many times. I have three outstanding tasks before
shutting this down:
- First, I will ensure that all of this works with
core files. Core files have a Process but do not
allow allocating memory, which currently confuses
materialization.
- Second, I will make expression breakpoint
conditions remember their ClangUserExpression and
re-use it.
- Third, I will tear out all the redundant code
(for example, materialization logic in
ClangExpressionDeclMap) that is no longer used.
While implementing this fix, I also found a bug in
IRForTarget's handling of floating-point constants.
This should be fixed.
llvm-svn: 179801
2013-04-18 22:06:33 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (m_in_objectivec_method)
|
|
|
|
args.push_back(cmd_ptr);
|
|
|
|
|
|
|
|
args.push_back(struct_address);
|
|
|
|
} else {
|
|
|
|
args.push_back(struct_address);
|
|
|
|
}
|
|
|
|
return true;
|
This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
llvm-svn: 112249
2010-08-27 01:01:44 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
lldb::ExpressionVariableSP ClangUserExpression::GetResultAfterDematerialization(
|
|
|
|
ExecutionContextScope *exe_scope) {
|
|
|
|
return m_result_delegate.GetVariable();
|
2015-10-03 09:09:01 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap(
|
|
|
|
ExecutionContext &exe_ctx,
|
|
|
|
Materializer::PersistentVariableDelegate &delegate,
|
2019-02-05 09:14:36 +00:00
|
|
|
bool keep_result_in_memory,
|
|
|
|
ValueObject *ctx_obj) {
|
2016-09-06 20:57:50 +00:00
|
|
|
m_expr_decl_map_up.reset(
|
2019-02-05 09:14:36 +00:00
|
|
|
new ClangExpressionDeclMap(keep_result_in_memory, &delegate, exe_ctx,
|
|
|
|
ctx_obj));
|
2015-09-15 21:13:50 +00:00
|
|
|
}
|
2014-07-06 17:54:58 +00:00
|
|
|
|
2015-09-15 21:13:50 +00:00
|
|
|
clang::ASTConsumer *
|
2016-09-06 20:57:50 +00:00
|
|
|
ClangUserExpression::ClangUserExpressionHelper::ASTTransformer(
|
|
|
|
clang::ASTConsumer *passthrough) {
|
|
|
|
m_result_synthesizer_up.reset(
|
|
|
|
new ASTResultSynthesizer(passthrough, m_top_level, m_target));
|
2010-10-05 03:13:51 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
return m_result_synthesizer_up.get();
|
2010-10-29 20:19:44 +00:00
|
|
|
}
|
2015-09-15 21:13:50 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
void ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() {
|
2019-02-12 03:47:39 +00:00
|
|
|
if (m_result_synthesizer_up) {
|
2016-09-06 20:57:50 +00:00
|
|
|
m_result_synthesizer_up->CommitPersistentDecls();
|
|
|
|
}
|
2016-03-22 21:05:51 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
ConstString ClangUserExpression::ResultDelegate::GetName() {
|
2018-04-30 23:59:17 +00:00
|
|
|
auto prefix = m_persistent_state->GetPersistentVariablePrefix();
|
|
|
|
return m_persistent_state->GetNextPersistentVariableName(*m_target_sp,
|
|
|
|
prefix);
|
2015-10-03 09:09:01 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
void ClangUserExpression::ResultDelegate::DidDematerialize(
|
|
|
|
lldb::ExpressionVariableSP &variable) {
|
|
|
|
m_variable = variable;
|
2015-10-03 09:09:01 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
void ClangUserExpression::ResultDelegate::RegisterPersistentState(
|
|
|
|
PersistentExpressionState *persistent_state) {
|
|
|
|
m_persistent_state = persistent_state;
|
2015-10-03 09:09:01 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
lldb::ExpressionVariableSP &ClangUserExpression::ResultDelegate::GetVariable() {
|
|
|
|
return m_variable;
|
2015-10-03 09:09:01 +00:00
|
|
|
}
|