This patch modifies the expression parser to allow it
to execute expressions even in the absence of a process. This allows expressions to run in situations where the target cannot run -- e.g., to perform calculations based on type information, or to inspect a binary's static data. This modification touches the following files: lldb-private-enumerations.h Introduce a new enum specifying the policy for processing an expression. Some expressions should always be JITted, for example if they are functions that will be used over and over again. Some expressions should always be interpreted, for example if the target is unsafe to run. For most, it is acceptable to JIT them, but interpretation is preferable when possible. Target.[h,cpp] Have EvaluateExpression now accept the new enum. ClangExpressionDeclMap.[cpp,h] Add support for the IR interpreter and also make the ClangExpressionDeclMap more robust in the absence of a process. ClangFunction.[cpp,h] Add support for the new enum. IRInterpreter.[cpp,h] New implementation. ClangUserExpression.[cpp,h] Add support for the new enum, and for running expressions in the absence of a process. ClangExpression.h Remove references to the old DWARF-based method of evaluating expressions, because it has been superseded for now. ClangUtilityFunction.[cpp,h] Add support for the new enum. ClangExpressionParser.[cpp,h] Add support for the new enum, remove references to DWARF, and add support for checking whether the expression could be evaluated statically. IRForTarget.[h,cpp] Add support for the new enum, and add utility functions to support the interpreter. IRToDWARF.cpp Removed CommandObjectExpression.cpp Remove references to the obsolete -i option. Process.cpp Modify calls to ClangUserExpression::Evaluate to pass the correct enum (for dlopen/dlclose) SBValue.cpp Add support for the new enum. SBFrame.cpp Add support for he new enum. BreakpointOptions.cpp Add support for the new enum. llvm-svn: 139772
This commit is contained in:
parent
5acab501de
commit
3bfdaa2a47
|
@ -97,13 +97,6 @@ public:
|
|||
virtual clang::ASTConsumer *
|
||||
ASTTransformer (clang::ASTConsumer *passthrough) = 0;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the stream that the parser should use to write DWARF
|
||||
/// opcodes.
|
||||
//------------------------------------------------------------------
|
||||
virtual StreamString &
|
||||
DwarfOpcodeStream () = 0;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Flags
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -348,6 +348,130 @@ public:
|
|||
lldb::addr_t
|
||||
GetSymbolAddress (const ConstString &name);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// [Used by IRInterpreter] Get basic target information.
|
||||
///
|
||||
/// @param[out] byte_order
|
||||
/// The byte order of the target.
|
||||
///
|
||||
/// @param[out] address_byte_size
|
||||
/// The size of a pointer in bytes.
|
||||
///
|
||||
/// @return
|
||||
/// True if the information could be determined; false
|
||||
/// otherwise.
|
||||
//------------------------------------------------------------------
|
||||
struct TargetInfo
|
||||
{
|
||||
lldb::ByteOrder byte_order;
|
||||
size_t address_byte_size;
|
||||
|
||||
TargetInfo() :
|
||||
byte_order(lldb::eByteOrderInvalid),
|
||||
address_byte_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsValid()
|
||||
{
|
||||
return (byte_order != lldb::eByteOrderInvalid &&
|
||||
address_byte_size != 0);
|
||||
}
|
||||
};
|
||||
TargetInfo GetTargetInfo();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// [Used by IRInterpreter] Write to the target.
|
||||
///
|
||||
/// @param[in] addr
|
||||
/// The address to write to.
|
||||
///
|
||||
/// @param[in] data
|
||||
/// The address of the data buffer to read from.
|
||||
///
|
||||
/// @param[in] length
|
||||
/// The amount of data to write, in bytes.
|
||||
///
|
||||
/// @return
|
||||
/// True if the write could be performed; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
WriteTarget (lldb_private::Value &value,
|
||||
const uint8_t *data,
|
||||
size_t length);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// [Used by IRInterpreter] Read from the target.
|
||||
///
|
||||
/// @param[in] data
|
||||
/// The address of the data buffer to write to.
|
||||
///
|
||||
/// @param[in] addr
|
||||
/// The address to read from.
|
||||
///
|
||||
/// @param[in] length
|
||||
/// The amount of data to read, in bytes.
|
||||
///
|
||||
/// @return
|
||||
/// True if the read could be performed; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
ReadTarget (uint8_t *data,
|
||||
lldb_private::Value &value,
|
||||
size_t length);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// [Used by IRInterpreter] Get the Value for a NamedDecl.
|
||||
///
|
||||
/// @param[in] decl
|
||||
/// The Decl whose value is to be found.
|
||||
///
|
||||
/// @return
|
||||
/// The value, or NULL.
|
||||
//------------------------------------------------------------------
|
||||
lldb_private::Value
|
||||
LookupDecl (clang::NamedDecl *decl);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// [Used by IRInterpreter] Returns true if the result is a
|
||||
/// reference to data in the target, meaning it must be
|
||||
/// dereferenced once more to get its data.
|
||||
///
|
||||
/// @param[in] name
|
||||
/// The name of the result.
|
||||
///
|
||||
/// @return
|
||||
/// True if the result is a reference; false otherwise (or on
|
||||
/// error).
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
ResultIsReference (const ConstString &name);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// [Used by IRInterpreter] Find the result persistent variable,
|
||||
/// propagate the given value to it, and return it.
|
||||
///
|
||||
/// @param[out] valobj
|
||||
/// Set to the complete object.
|
||||
///
|
||||
/// @param[in] value
|
||||
/// A value indicating the location of the value's contents.
|
||||
///
|
||||
/// @param[in] name
|
||||
/// The name of the result.
|
||||
///
|
||||
/// @param[in] type
|
||||
/// The type of the data.
|
||||
///
|
||||
/// @return
|
||||
/// True on success; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
CompleteResultVariable (lldb::ClangExpressionVariableSP &valobj,
|
||||
lldb_private::Value &value,
|
||||
const ConstString &name,
|
||||
lldb_private::TypeFromParser type);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// [Used by CommandObjectExpression] Materialize the entire struct
|
||||
/// at a given address, which should be aligned as specified by
|
||||
|
@ -596,6 +720,7 @@ private:
|
|||
bool m_enable_lookups; ///< Set to true during parsing if we have found the first "$__lldb" name.
|
||||
bool m_ignore_lookups; ///< True during an import when we should be ignoring type lookups.
|
||||
std::auto_ptr<ClangASTImporter> m_ast_importer; ///< The importer used to import types on the parser's behalf.
|
||||
TargetInfo m_target_info; ///< Basic information about the target.
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN (ParserVars);
|
||||
};
|
||||
|
@ -741,6 +866,29 @@ private:
|
|||
FindGlobalDataSymbol (Target &target,
|
||||
const ConstString &name);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Given a target, find a variable that matches the given name and
|
||||
/// type.
|
||||
///
|
||||
/// @param[in] target
|
||||
/// The target to use as a basis for finding the variable.
|
||||
///
|
||||
/// @param[in] name
|
||||
/// The name as a plain C string.
|
||||
///
|
||||
/// @param[in] type
|
||||
/// The required type for the variable. This function may be called
|
||||
/// during parsing, in which case we don't know its type; hence the
|
||||
/// default.
|
||||
///
|
||||
/// @return
|
||||
/// The LLDB Variable found, or NULL if none was found.
|
||||
//------------------------------------------------------------------
|
||||
lldb::VariableSP
|
||||
FindGlobalVariable (Target &target,
|
||||
const char *name,
|
||||
TypeFromUser *type = NULL);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Get the value of a variable in a given execution context and return
|
||||
/// the associated Types if needed.
|
||||
|
|
|
@ -73,20 +73,8 @@ public:
|
|||
Parse (Stream &stream);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Convert the IR for an already-parsed expression to DWARF if possible.
|
||||
///
|
||||
/// @param[in] dwarf_opcode_strm
|
||||
/// The stream to place the resulting DWARF code into.
|
||||
///
|
||||
/// @return
|
||||
/// An error code indicating the success or failure of the operation.
|
||||
/// Test with Success().
|
||||
//------------------------------------------------------------------
|
||||
Error
|
||||
MakeDWARF ();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// JIT-compile the IR for an already-parsed expression.
|
||||
/// Ready an already-parsed expression for execution, possibly
|
||||
/// evaluating it statically.
|
||||
///
|
||||
/// @param[out] func_allocation_addr
|
||||
/// The address which can be used to deallocate the code for this
|
||||
|
@ -104,30 +92,36 @@ public:
|
|||
/// The execution context to write the function into.
|
||||
///
|
||||
/// @param[in] data_allocator
|
||||
/// If non-NULL, he static data allocator to use for literal strings.
|
||||
/// If non-NULL, the static data allocator to use for literal strings.
|
||||
///
|
||||
/// @param[out] evaluated_statically
|
||||
/// Set to true if the expression could be interpreted statically;
|
||||
/// untouched otherwise.
|
||||
///
|
||||
/// @param[out] const_result
|
||||
/// If the result of the expression is constant, and the
|
||||
/// expression has no side effects, this is set to the result of the
|
||||
/// expression.
|
||||
///
|
||||
/// @param[in] jit_only_if_needed
|
||||
/// True if the expression must be compiled, regardless of whether a
|
||||
/// constant result could be extracted from the IR or no.
|
||||
/// @param[in] execution_policy
|
||||
/// Determines whether the expression must be JIT-compiled, must be
|
||||
/// evaluated statically, or whether this decision may be made
|
||||
/// opportunistically.
|
||||
///
|
||||
/// @return
|
||||
/// An error code indicating the success or failure of the operation.
|
||||
/// Test with Success().
|
||||
//------------------------------------------------------------------
|
||||
Error
|
||||
MakeJIT (lldb::addr_t &func_allocation_addr,
|
||||
lldb::addr_t &func_addr,
|
||||
lldb::addr_t &func_end,
|
||||
ExecutionContext &exe_ctx,
|
||||
IRForTarget::StaticDataAllocator *data_allocator,
|
||||
lldb::ClangExpressionVariableSP &const_result,
|
||||
bool jit_only_if_needed = false);
|
||||
|
||||
PrepareForExecution (lldb::addr_t &func_allocation_addr,
|
||||
lldb::addr_t &func_addr,
|
||||
lldb::addr_t &func_end,
|
||||
ExecutionContext &exe_ctx,
|
||||
IRForTarget::StaticDataAllocator *data_allocator,
|
||||
bool &evaluated_statically,
|
||||
lldb::ClangExpressionVariableSP &const_result,
|
||||
lldb_private::ExecutionPolicy execution_policy);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Disassemble the machine code for a JITted function from the target
|
||||
/// process's memory and print the result to a stream.
|
||||
|
|
|
@ -573,16 +573,6 @@ public:
|
|||
clang::ASTConsumer *
|
||||
ASTTransformer (clang::ASTConsumer *passthrough);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the stream that the parser should use to write DWARF
|
||||
/// opcodes.
|
||||
//------------------------------------------------------------------
|
||||
StreamString &
|
||||
DwarfOpcodeStream ()
|
||||
{
|
||||
return *((StreamString*)0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return true if validation code should be inserted into the
|
||||
/// expression.
|
||||
|
|
|
@ -83,6 +83,9 @@ public:
|
|||
/// The type that the expression should be coerced to. If NULL,
|
||||
/// inferred from the expression itself.
|
||||
///
|
||||
/// @param[in] execution_policy
|
||||
/// Determines whether interpretation is possible or mandatory.
|
||||
///
|
||||
/// @param[in] keep_result_in_memory
|
||||
/// True if the resulting persistent variable should reside in
|
||||
/// target memory, if applicable.
|
||||
|
@ -94,6 +97,7 @@ public:
|
|||
Parse (Stream &error_stream,
|
||||
ExecutionContext &exe_ctx,
|
||||
TypeFromUser desired_type,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
bool keep_result_in_memory);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
@ -226,13 +230,6 @@ public:
|
|||
clang::ASTConsumer *
|
||||
ASTTransformer (clang::ASTConsumer *passthrough);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the stream that the parser should use to write DWARF
|
||||
/// opcodes.
|
||||
//------------------------------------------------------------------
|
||||
StreamString &
|
||||
DwarfOpcodeStream ();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return true if validation code should be inserted into the
|
||||
/// expression.
|
||||
|
@ -259,6 +256,10 @@ public:
|
|||
/// @param[in] exe_ctx
|
||||
/// The execution context to use when evaluating the expression.
|
||||
///
|
||||
/// @param[in] execution_policy
|
||||
/// Determines whether or not to try using the IR interpreter to
|
||||
/// avoid running the expression on the parser.
|
||||
///
|
||||
/// @param[in] discard_on_error
|
||||
/// True if the thread's state should be restored in the case
|
||||
/// of an error.
|
||||
|
@ -277,14 +278,16 @@ public:
|
|||
/// A Process::ExecutionResults value. eExecutionCompleted for success.
|
||||
//------------------------------------------------------------------
|
||||
static ExecutionResults
|
||||
Evaluate (ExecutionContext &exe_ctx,
|
||||
Evaluate (ExecutionContext &exe_ctx,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
bool discard_on_error,
|
||||
const char *expr_cstr,
|
||||
const char *expr_prefix,
|
||||
lldb::ValueObjectSP &result_valobj_sp);
|
||||
|
||||
static ExecutionResults
|
||||
EvaluateWithError (ExecutionContext &exe_ctx,
|
||||
EvaluateWithError (ExecutionContext &exe_ctx,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
bool discard_on_error,
|
||||
const char *expr_cstr,
|
||||
const char *expr_prefix,
|
||||
|
@ -307,6 +310,12 @@ private:
|
|||
lldb::addr_t &object_ptr,
|
||||
lldb::addr_t &cmd_ptr);
|
||||
|
||||
bool
|
||||
EvaluatedStatically ()
|
||||
{
|
||||
return m_evaluated_statically;
|
||||
}
|
||||
|
||||
std::string m_expr_text; ///< The text of the expression, as typed by the user
|
||||
std::string m_expr_prefix; ///< The text of the translation-level definitions, as provided by the user
|
||||
std::string m_transformed_text; ///< The text of the expression, as send to the parser
|
||||
|
@ -314,7 +323,6 @@ private:
|
|||
|
||||
std::auto_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression.
|
||||
std::auto_ptr<ClangExpressionVariableList> m_local_variables; ///< The local expression variables, if the expression is DWARF.
|
||||
std::auto_ptr<StreamString> m_dwarf_opcodes; ///< The DWARF opcodes for the expression. May be NULL.
|
||||
std::auto_ptr<ProcessDataAllocator> m_data_allocator; ///< The allocator that the parser uses to place strings for use by JIT-compiled code.
|
||||
|
||||
bool m_cplusplus; ///< True if the expression is compiled as a C++ member function (true if it was parsed when exe_ctx was in a C++ method).
|
||||
|
@ -323,6 +331,7 @@ private:
|
|||
bool m_const_object; ///< True if "this" is const.
|
||||
Target *m_target; ///< The target for storing persistent data like types and variables.
|
||||
|
||||
bool m_evaluated_statically; ///< True if the expression could be evaluated statically; false otherwise.
|
||||
lldb::ClangExpressionVariableSP m_const_result; ///< The statically-computed result of the expression. NULL if it could not be computed statically or the expression has side effects.
|
||||
};
|
||||
|
||||
|
|
|
@ -148,16 +148,6 @@ public:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the stream that the parser should use to write DWARF
|
||||
/// opcodes.
|
||||
//------------------------------------------------------------------
|
||||
StreamString &
|
||||
DwarfOpcodeStream ()
|
||||
{
|
||||
return *((StreamString*)NULL);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return true if validation code should be inserted into the
|
||||
/// expression.
|
||||
|
|
|
@ -73,6 +73,10 @@ public:
|
|||
/// variables) should be resolved. If not, only external functions
|
||||
/// are resolved.
|
||||
///
|
||||
/// @param[in] execution_policy
|
||||
/// Determines whether an IR interpreter can be used to statically
|
||||
/// evaluate the expression.
|
||||
///
|
||||
/// @param[in] const_result
|
||||
/// This variable is populated with the statically-computed result
|
||||
/// of the function, if it has no side-effects and the result can
|
||||
|
@ -89,6 +93,7 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map,
|
||||
bool resolve_vars,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
lldb::ClangExpressionVariableSP &const_result,
|
||||
StaticDataAllocator *data_allocator,
|
||||
lldb_private::Stream *error_stream,
|
||||
|
@ -133,6 +138,18 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
virtual llvm::PassManagerType
|
||||
getPotentialPassManagerType() const;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Checks whether the IR interpreter successfully interpreted the
|
||||
/// expression.
|
||||
///
|
||||
/// Returns true if it did; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
interpretSuccess ()
|
||||
{
|
||||
return m_interpret_success;
|
||||
}
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
|
@ -236,16 +253,22 @@ private:
|
|||
//------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Set the constant result variable m_const_result to the provided
|
||||
/// constant, assuming it can be evaluated. The result variable
|
||||
/// will be reset to NULL later if the expression has side effects.
|
||||
/// Find the NamedDecl corresponding to a Value. This interface is
|
||||
/// exposed for the IR interpreter.
|
||||
///
|
||||
/// @param[in] module
|
||||
/// The module containing metadata to search
|
||||
///
|
||||
/// @param[in] global
|
||||
/// The global entity to search for
|
||||
///
|
||||
/// @return
|
||||
/// The corresponding variable declaration
|
||||
//------------------------------------------------------------------
|
||||
//------------------------------------------------------------------
|
||||
public:
|
||||
static clang::NamedDecl *
|
||||
DeclForGlobal (const llvm::GlobalValue *global_val, llvm::Module *module);
|
||||
private:
|
||||
clang::NamedDecl *
|
||||
DeclForGlobal (llvm::GlobalValue *global);
|
||||
|
||||
|
@ -549,8 +572,11 @@ private:
|
|||
|
||||
/// Flags
|
||||
bool m_resolve_vars; ///< True if external variable references and persistent variable references should be resolved
|
||||
lldb_private::ExecutionPolicy m_execution_policy; ///< True if the interpreter should be used to attempt to get a static result
|
||||
bool m_interpret_success; ///< True if the interpreter successfully handled the whole expression
|
||||
std::string m_func_name; ///< The name of the function to translate
|
||||
lldb_private::ConstString m_result_name; ///< The name of the result variable ($0, $1, ...)
|
||||
lldb_private::TypeFromParser m_result_type; ///< The type of the result variable.
|
||||
llvm::Module *m_module; ///< The module being processed, or NULL if that has not been determined yet.
|
||||
lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls
|
||||
StaticDataAllocator *m_data_allocator; ///< If non-NULL, the allocator to use for constant strings
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
//===-- IRInterpreter.h -----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_IRInterpreter_h_
|
||||
#define liblldb_IRInterpreter_h_
|
||||
|
||||
#include "lldb/lldb-public.h"
|
||||
#include "lldb/Core/ConstString.h"
|
||||
#include "lldb/Core/Stream.h"
|
||||
#include "lldb/Symbol/TaggedASTType.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
class Function;
|
||||
class Module;
|
||||
}
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
class ClangExpressionDeclMap;
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/// @class IRInterpreter IRInterpreter.h "lldb/Expression/IRInterpreter.h"
|
||||
/// @brief Attempt to interpret the function's code if it does not require
|
||||
/// running the target.
|
||||
///
|
||||
/// In some cases, the IR for an expression can be evaluated entirely
|
||||
/// in the debugger, manipulating variables but not executing any code
|
||||
/// in the target. The IRInterpreter attempts to do this.
|
||||
//----------------------------------------------------------------------
|
||||
class IRInterpreter
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------
|
||||
/// Constructor
|
||||
///
|
||||
/// @param[in] decl_map
|
||||
/// The list of externally-referenced variables for the expression,
|
||||
/// for use in looking up globals and allocating the argument
|
||||
/// struct. See the documentation for ClangExpressionDeclMap.
|
||||
///
|
||||
/// @param[in] error_stream
|
||||
/// If non-NULL, a stream on which errors can be printed.
|
||||
//------------------------------------------------------------------
|
||||
IRInterpreter(lldb_private::ClangExpressionDeclMap &decl_map,
|
||||
lldb_private::Stream *error_stream);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Destructor
|
||||
//------------------------------------------------------------------
|
||||
~IRInterpreter();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Run the IR interpreter on a single function
|
||||
///
|
||||
/// @param[in] result
|
||||
/// This variable is populated with the return value of the
|
||||
/// function, if it could be interpreted completely.
|
||||
///
|
||||
/// @param[in] result_name
|
||||
/// The name of the result in the IR. If this name got a
|
||||
/// value written to it as part of execution, then that value
|
||||
/// will be used to create the result variable.
|
||||
///
|
||||
/// @param[in] result_type
|
||||
/// The type of the result.
|
||||
///
|
||||
/// @param[in] llvm_function
|
||||
/// The function to interpret.
|
||||
///
|
||||
/// @param[in] llvm_module
|
||||
/// The module containing the function.
|
||||
///
|
||||
/// @return
|
||||
/// True on success; false otherwise
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
maybeRunOnFunction (lldb::ClangExpressionVariableSP &result,
|
||||
const lldb_private::ConstString &result_name,
|
||||
lldb_private::TypeFromParser result_type,
|
||||
llvm::Function &llvm_function,
|
||||
llvm::Module &llvm_module);
|
||||
private:
|
||||
/// Flags
|
||||
lldb_private::ClangExpressionDeclMap &m_decl_map; ///< The DeclMap containing the Decls
|
||||
lldb_private::Stream *m_error_stream;
|
||||
|
||||
bool
|
||||
supportsFunction (llvm::Function &llvm_function);
|
||||
|
||||
bool
|
||||
runOnFunction (lldb::ClangExpressionVariableSP &result,
|
||||
const lldb_private::ConstString &result_name,
|
||||
lldb_private::TypeFromParser result_type,
|
||||
llvm::Function &llvm_function,
|
||||
llvm::Module &llvm_module);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -600,6 +600,7 @@ public:
|
|||
ExecutionResults
|
||||
EvaluateExpression (const char *expression,
|
||||
StackFrame *frame,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
bool unwind_on_error,
|
||||
bool keep_in_memory,
|
||||
lldb::DynamicValueType use_dynamic,
|
||||
|
|
|
@ -214,6 +214,15 @@ typedef enum FormatCategoryItem
|
|||
eFormatCategoryItemRegexSynth = 0x0020
|
||||
} FormatCategoryItem;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Expression execution policies
|
||||
//------------------------------------------------------------------
|
||||
typedef enum {
|
||||
eExecutionPolicyOnlyWhenNeeded,
|
||||
eExecutionPolicyNever,
|
||||
eExecutionPolicyAlways
|
||||
} ExecutionPolicy;
|
||||
|
||||
} // namespace lldb
|
||||
|
||||
|
||||
|
|
|
@ -179,7 +179,6 @@
|
|||
2689006913353E0E00698AC0 /* ASTStructExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491193501226386000578B7F /* ASTStructExtractor.cpp */; };
|
||||
2689006A13353E0E00698AC0 /* IRDynamicChecks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */; };
|
||||
2689006B13353E0E00698AC0 /* IRForTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49307AAD11DEA4D90081F992 /* IRForTarget.cpp */; };
|
||||
2689006C13353E0E00698AC0 /* IRToDWARF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DA742F11DE6A5A006AEF7E /* IRToDWARF.cpp */; };
|
||||
2689006D13353E0E00698AC0 /* RecordingMemoryManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */; };
|
||||
2689006E13353E1A00698AC0 /* File.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C6EA213011581005E16B0 /* File.cpp */; };
|
||||
2689006F13353E1A00698AC0 /* FileSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26FA43171301048600E71120 /* FileSpec.cpp */; };
|
||||
|
@ -330,7 +329,6 @@
|
|||
2689FFFB13353DB600698AC0 /* BreakpointLocationList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E1010F1B83100F91463 /* BreakpointLocationList.cpp */; };
|
||||
2689FFFD13353DB600698AC0 /* BreakpointOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E1110F1B83100F91463 /* BreakpointOptions.cpp */; };
|
||||
2689FFFF13353DB600698AC0 /* BreakpointResolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E1210F1B83100F91463 /* BreakpointResolver.cpp */; };
|
||||
268ED0A5140FF54200DE830F /* DataEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 268ED0A4140FF54200DE830F /* DataEncoder.cpp */; };
|
||||
268F9D53123AA15200B91E9B /* SBSymbolContextList.h in Headers */ = {isa = PBXBuildFile; fileRef = 268F9D52123AA15200B91E9B /* SBSymbolContextList.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
268F9D55123AA16600B91E9B /* SBSymbolContextList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 268F9D54123AA16600B91E9B /* SBSymbolContextList.cpp */; };
|
||||
2690B3711381D5C300ECFBAE /* Memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2690B3701381D5C300ECFBAE /* Memory.cpp */; };
|
||||
|
@ -396,6 +394,9 @@
|
|||
26F5C37510F3F61B009D5894 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C37410F3F61B009D5894 /* libobjc.dylib */; };
|
||||
26F5C39110F3FA26009D5894 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C39010F3FA26009D5894 /* CoreFoundation.framework */; };
|
||||
26F73062139D8FDB00FD51C7 /* History.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26F73061139D8FDB00FD51C7 /* History.cpp */; };
|
||||
496B015B1406DEB100F830D5 /* IRInterpreter.h in Headers */ = {isa = PBXBuildFile; fileRef = 496B015A1406DEB100F830D5 /* IRInterpreter.h */; };
|
||||
49A71FE7141FFA5C00D59478 /* IRInterpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 496B01581406DE8900F830D5 /* IRInterpreter.cpp */; };
|
||||
49A71FE8141FFACF00D59478 /* DataEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 268ED0A4140FF54200DE830F /* DataEncoder.cpp */; };
|
||||
49C8507C1384A786007DB519 /* ProcessDataAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49C850781384A0CA007DB519 /* ProcessDataAllocator.cpp */; };
|
||||
49D8FB3913B5598F00411094 /* ClangASTImporter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49D8FB3513B558DE00411094 /* ClangASTImporter.cpp */; };
|
||||
4C74CB6312288704006A8171 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C74CB6212288704006A8171 /* Carbon.framework */; };
|
||||
|
@ -1104,6 +1105,8 @@
|
|||
49445E341225AB6A00C11A81 /* ClangUserExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangUserExpression.h; path = include/lldb/Expression/ClangUserExpression.h; sourceTree = "<group>"; };
|
||||
495BBACB119A0DBE00418BEA /* PathMappingList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PathMappingList.cpp; path = source/Target/PathMappingList.cpp; sourceTree = "<group>"; };
|
||||
495BBACF119A0DE700418BEA /* PathMappingList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PathMappingList.h; path = include/lldb/Target/PathMappingList.h; sourceTree = "<group>"; };
|
||||
496B01581406DE8900F830D5 /* IRInterpreter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRInterpreter.cpp; path = source/Expression/IRInterpreter.cpp; sourceTree = "<group>"; };
|
||||
496B015A1406DEB100F830D5 /* IRInterpreter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRInterpreter.h; path = include/lldb/Expression/IRInterpreter.h; sourceTree = "<group>"; };
|
||||
497C86BD122823D800B54702 /* ClangUtilityFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangUtilityFunction.cpp; path = source/Expression/ClangUtilityFunction.cpp; sourceTree = "<group>"; };
|
||||
497C86C1122823F300B54702 /* ClangUtilityFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangUtilityFunction.h; path = include/lldb/Expression/ClangUtilityFunction.h; sourceTree = "<group>"; };
|
||||
497E7B331188ED300065CCA1 /* ABI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ABI.h; path = include/lldb/Target/ABI.h; sourceTree = "<group>"; };
|
||||
|
@ -1123,8 +1126,6 @@
|
|||
49D7072811B5AD11001AD875 /* ClangASTSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangASTSource.cpp; path = source/Expression/ClangASTSource.cpp; sourceTree = "<group>"; };
|
||||
49D8FB3513B558DE00411094 /* ClangASTImporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangASTImporter.cpp; path = source/Symbol/ClangASTImporter.cpp; sourceTree = "<group>"; };
|
||||
49D8FB3713B5594900411094 /* ClangASTImporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangASTImporter.h; path = include/lldb/Symbol/ClangASTImporter.h; sourceTree = "<group>"; };
|
||||
49DA742F11DE6A5A006AEF7E /* IRToDWARF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRToDWARF.cpp; path = source/Expression/IRToDWARF.cpp; sourceTree = "<group>"; };
|
||||
49DA743411DE6BB2006AEF7E /* IRToDWARF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRToDWARF.h; path = include/lldb/Expression/IRToDWARF.h; sourceTree = "<group>"; };
|
||||
49E45FA911F660DC008F7B28 /* ClangASTType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangASTType.h; path = include/lldb/Symbol/ClangASTType.h; sourceTree = "<group>"; };
|
||||
49E45FAD11F660FE008F7B28 /* ClangASTType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangASTType.cpp; path = source/Symbol/ClangASTType.cpp; sourceTree = "<group>"; };
|
||||
49EC3E98118F90AC00B1265E /* ThreadPlanCallFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanCallFunction.cpp; path = source/Target/ThreadPlanCallFunction.cpp; sourceTree = "<group>"; };
|
||||
|
@ -2280,8 +2281,8 @@
|
|||
49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */,
|
||||
49307AB111DEA4F20081F992 /* IRForTarget.h */,
|
||||
49307AAD11DEA4D90081F992 /* IRForTarget.cpp */,
|
||||
49DA743411DE6BB2006AEF7E /* IRToDWARF.h */,
|
||||
49DA742F11DE6A5A006AEF7E /* IRToDWARF.cpp */,
|
||||
496B015A1406DEB100F830D5 /* IRInterpreter.h */,
|
||||
496B01581406DE8900F830D5 /* IRInterpreter.cpp */,
|
||||
4C98D3E1118FB98F00E575D0 /* RecordingMemoryManager.h */,
|
||||
4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */,
|
||||
49C850761384A02F007DB519 /* ProcessDataAllocator.h */,
|
||||
|
@ -2760,6 +2761,7 @@
|
|||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
496B015B1406DEB100F830D5 /* IRInterpreter.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -3151,7 +3153,6 @@
|
|||
2689006913353E0E00698AC0 /* ASTStructExtractor.cpp in Sources */,
|
||||
2689006A13353E0E00698AC0 /* IRDynamicChecks.cpp in Sources */,
|
||||
2689006B13353E0E00698AC0 /* IRForTarget.cpp in Sources */,
|
||||
2689006C13353E0E00698AC0 /* IRToDWARF.cpp in Sources */,
|
||||
2689006D13353E0E00698AC0 /* RecordingMemoryManager.cpp in Sources */,
|
||||
2689006E13353E1A00698AC0 /* File.cpp in Sources */,
|
||||
2689006F13353E1A00698AC0 /* FileSpec.cpp in Sources */,
|
||||
|
@ -3361,11 +3362,12 @@
|
|||
26274FA714030F79006BA130 /* DynamicLoaderDarwinKernel.cpp in Sources */,
|
||||
94FA3DE01405D50400833217 /* ValueObjectConstResultChild.cpp in Sources */,
|
||||
949ADF031406F648004833E1 /* ValueObjectConstResultImpl.cpp in Sources */,
|
||||
268ED0A5140FF54200DE830F /* DataEncoder.cpp in Sources */,
|
||||
26A0DA4E140F7226006DA411 /* HashedNameToDIE.cpp in Sources */,
|
||||
B27318421416AC12006039C8 /* WatchpointLocationList.cpp in Sources */,
|
||||
26E152261419CAD4007967D0 /* ObjectFilePECOFF.cpp in Sources */,
|
||||
B2462247141AD37D00F3D409 /* OptionGroupWatchpoint.cpp in Sources */,
|
||||
49A71FE7141FFA5C00D59478 /* IRInterpreter.cpp in Sources */,
|
||||
49A71FE8141FFACF00D59478 /* DataEncoder.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -759,7 +759,8 @@ SBFrame::EvaluateExpression (const char *expr, lldb::DynamicValueType fetch_dyna
|
|||
const bool keep_in_memory = false;
|
||||
|
||||
exe_results = m_opaque_sp->GetThread().GetProcess().GetTarget().EvaluateExpression(expr,
|
||||
m_opaque_sp.get(),
|
||||
m_opaque_sp.get(),
|
||||
eExecutionPolicyOnlyWhenNeeded,
|
||||
unwind_on_error,
|
||||
keep_in_memory,
|
||||
fetch_dynamic_value,
|
||||
|
|
|
@ -379,7 +379,10 @@ SBValue::CreateValueFromExpression (const char *name, const char* expression)
|
|||
ValueObjectSP result_valobj_sp;
|
||||
m_opaque_sp->GetUpdatePoint().GetTargetSP()->EvaluateExpression (expression,
|
||||
m_opaque_sp->GetUpdatePoint().GetExecutionContextScope()->CalculateStackFrame(),
|
||||
true, true, eNoDynamicValues,
|
||||
eExecutionPolicyAlways,
|
||||
true, // unwind on error
|
||||
true, // keep in memory
|
||||
eNoDynamicValues,
|
||||
result_valobj_sp);
|
||||
result_valobj_sp->SetName(ConstString(name));
|
||||
result = SBValue(result_valobj_sp);
|
||||
|
|
|
@ -199,7 +199,9 @@ BreakpointOptions::GetThreadPlanToTestCondition (ExecutionContext &exe_ctx,
|
|||
ClangASTContext *ast_context = exe_ctx.target->GetScratchClangASTContext();
|
||||
TypeFromUser bool_type(ast_context->GetBuiltInType_bool(), ast_context->getASTContext());
|
||||
|
||||
if (!m_condition_ap->Parse (error_stream, exe_ctx, bool_type, false /* keep_in_memory */))
|
||||
const bool keep_in_memory = false;
|
||||
|
||||
if (!m_condition_ap->Parse (error_stream, exe_ctx, bool_type, eExecutionPolicyAlways, keep_in_memory))
|
||||
{
|
||||
// Errors mean we should stop.
|
||||
return NULL;
|
||||
|
|
|
@ -95,12 +95,13 @@ CommandObjectExpression::CommandOptions::SetOptionValue (uint32_t option_idx, co
|
|||
break;
|
||||
|
||||
case 'u':
|
||||
bool success;
|
||||
unwind_on_error = Args::StringToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat("Could not convert \"%s\" to a boolean value.", option_arg);
|
||||
break;
|
||||
|
||||
{
|
||||
bool success;
|
||||
unwind_on_error = Args::StringToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat("Could not convert \"%s\" to a boolean value.", option_arg);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
|
||||
break;
|
||||
|
@ -292,7 +293,13 @@ CommandObjectExpression::EvaluateExpression
|
|||
break;
|
||||
}
|
||||
|
||||
exe_results = m_exe_ctx.target->EvaluateExpression(expr, m_exe_ctx.frame, m_options.unwind_on_error, keep_in_memory, use_dynamic, result_valobj_sp);
|
||||
exe_results = m_exe_ctx.target->EvaluateExpression(expr,
|
||||
m_exe_ctx.frame,
|
||||
eExecutionPolicyOnlyWhenNeeded,
|
||||
m_options.unwind_on_error,
|
||||
keep_in_memory,
|
||||
use_dynamic,
|
||||
result_valobj_sp);
|
||||
|
||||
if (exe_results == eExecutionInterrupted && !m_options.unwind_on_error)
|
||||
{
|
||||
|
@ -488,7 +495,6 @@ CommandObjectExpression::CommandOptions::g_option_table[] =
|
|||
{ LLDB_OPT_SET_2, false, "dynamic-value", 'd', required_argument, NULL, 0, eArgTypeBoolean, "Upcast the value resulting from the expression to its dynamic type if available."},
|
||||
{ LLDB_OPT_SET_ALL, false, "unwind-on-error", 'u', required_argument, NULL, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, breakpoint hit or signal."},
|
||||
{ LLDB_OPT_SET_ALL, false, "debug", 'g', no_argument, NULL, 0, eArgTypeNone, "Enable verbose debug logging of the expression parsing and evaluation."},
|
||||
{ LLDB_OPT_SET_ALL, false, "use-ir", 'i', no_argument, NULL, 0, eArgTypeNone, "[Temporary] Instructs the expression evaluator to use IR instead of ASTs."},
|
||||
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
||||
|
|
|
@ -82,6 +82,8 @@ ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx)
|
|||
if (exe_ctx.target && !exe_ctx.target->GetScratchClangASTContext())
|
||||
return false;
|
||||
|
||||
m_parser_vars->m_target_info = GetTargetInfo();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -118,6 +120,29 @@ ClangExpressionDeclMap::DidParse()
|
|||
|
||||
// Interface for IRForTarget
|
||||
|
||||
ClangExpressionDeclMap::TargetInfo
|
||||
ClangExpressionDeclMap::GetTargetInfo()
|
||||
{
|
||||
assert (m_parser_vars.get());
|
||||
|
||||
TargetInfo ret;
|
||||
|
||||
ExecutionContext *exe_ctx = m_parser_vars->m_exe_ctx;
|
||||
|
||||
if (exe_ctx->process)
|
||||
{
|
||||
ret.byte_order = exe_ctx->process->GetByteOrder();
|
||||
ret.address_byte_size = exe_ctx->process->GetAddressByteSize();
|
||||
}
|
||||
else if (exe_ctx->target)
|
||||
{
|
||||
ret.byte_order = exe_ctx->target->GetArchitecture().GetByteOrder();
|
||||
ret.address_byte_size = exe_ctx->target->GetArchitecture().GetAddressByteSize();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const ConstString &
|
||||
ClangExpressionDeclMap::GetPersistentResultName ()
|
||||
{
|
||||
|
@ -146,12 +171,12 @@ ClangExpressionDeclMap::BuildIntegerVariable (const ConstString &name,
|
|||
type.GetASTContext(),
|
||||
type.GetOpaqueQualType()),
|
||||
context);
|
||||
|
||||
|
||||
if (!m_parser_vars->m_persistent_vars->CreatePersistentVariable (exe_ctx->GetBestExecutionContextScope (),
|
||||
name,
|
||||
user_type,
|
||||
exe_ctx->process->GetByteOrder(),
|
||||
exe_ctx->process->GetAddressByteSize()))
|
||||
m_parser_vars->m_target_info.byte_order,
|
||||
m_parser_vars->m_target_info.address_byte_size))
|
||||
return lldb::ClangExpressionVariableSP();
|
||||
|
||||
ClangExpressionVariableSP pvar_sp (m_parser_vars->m_persistent_vars->GetVariable(name));
|
||||
|
@ -164,9 +189,7 @@ ClangExpressionDeclMap::BuildIntegerVariable (const ConstString &name,
|
|||
return lldb::ClangExpressionVariableSP();
|
||||
|
||||
uint64_t value64 = value.getLimitedValue();
|
||||
|
||||
ByteOrder byte_order = exe_ctx->process->GetByteOrder();
|
||||
|
||||
|
||||
size_t num_val_bytes = sizeof(value64);
|
||||
size_t num_data_bytes = pvar_sp->GetByteSize();
|
||||
|
||||
|
@ -182,7 +205,7 @@ ClangExpressionDeclMap::BuildIntegerVariable (const ConstString &name,
|
|||
uint64_t mask = 0xffll << shift;
|
||||
uint8_t cur_byte = (uint8_t)((value64 & mask) >> shift);
|
||||
|
||||
switch (byte_order)
|
||||
switch (m_parser_vars->m_target_info.byte_order)
|
||||
{
|
||||
case eByteOrderBig:
|
||||
// High Low
|
||||
|
@ -276,6 +299,59 @@ ClangExpressionDeclMap::BuildCastVariable (const ConstString &name,
|
|||
return pvar_sp;
|
||||
}
|
||||
|
||||
bool
|
||||
ClangExpressionDeclMap::ResultIsReference (const ConstString &name)
|
||||
{
|
||||
ClangExpressionVariableSP pvar_sp = m_parser_vars->m_persistent_vars->GetVariable(name);
|
||||
|
||||
return (pvar_sp->m_flags & ClangExpressionVariable::EVIsProgramReference);
|
||||
}
|
||||
|
||||
bool
|
||||
ClangExpressionDeclMap::CompleteResultVariable (lldb::ClangExpressionVariableSP &valobj,
|
||||
lldb_private::Value &value,
|
||||
const ConstString &name,
|
||||
lldb_private::TypeFromParser type)
|
||||
{
|
||||
assert (m_parser_vars.get());
|
||||
|
||||
ClangExpressionVariableSP pvar_sp = m_parser_vars->m_persistent_vars->GetVariable(name);
|
||||
|
||||
if (!pvar_sp)
|
||||
return false;
|
||||
|
||||
if (pvar_sp->m_flags & ClangExpressionVariable::EVIsProgramReference &&
|
||||
!pvar_sp->m_live_sp)
|
||||
{
|
||||
// The reference comes from the program. We need to set up a live SP for it.
|
||||
|
||||
pvar_sp->m_live_sp = ValueObjectConstResult::Create(m_parser_vars->m_exe_ctx->GetBestExecutionContextScope(),
|
||||
pvar_sp->GetTypeFromUser().GetASTContext(),
|
||||
pvar_sp->GetTypeFromUser().GetOpaqueQualType(),
|
||||
pvar_sp->GetName(),
|
||||
value.GetScalar().ULongLong(),
|
||||
value.GetValueAddressType(),
|
||||
pvar_sp->GetByteSize());
|
||||
}
|
||||
|
||||
if (pvar_sp->m_flags & ClangExpressionVariable::EVNeedsFreezeDry)
|
||||
{
|
||||
pvar_sp->ValueUpdated();
|
||||
|
||||
const size_t pvar_byte_size = pvar_sp->GetByteSize();
|
||||
uint8_t *pvar_data = pvar_sp->GetValueBytes();
|
||||
|
||||
if (!ReadTarget(pvar_data, value, pvar_byte_size))
|
||||
return false;
|
||||
|
||||
pvar_sp->m_flags &= ~(ClangExpressionVariable::EVNeedsFreezeDry);
|
||||
}
|
||||
|
||||
valobj = pvar_sp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ClangExpressionDeclMap::AddPersistentVariable
|
||||
(
|
||||
|
@ -297,12 +373,15 @@ ClangExpressionDeclMap::AddPersistentVariable
|
|||
parser_type.GetASTContext(),
|
||||
parser_type.GetOpaqueQualType()),
|
||||
context);
|
||||
|
||||
if (!m_parser_vars->m_target_info.IsValid())
|
||||
return false;
|
||||
|
||||
if (!m_parser_vars->m_persistent_vars->CreatePersistentVariable (exe_ctx->GetBestExecutionContextScope (),
|
||||
name,
|
||||
user_type,
|
||||
exe_ctx->process->GetByteOrder(),
|
||||
exe_ctx->process->GetAddressByteSize()))
|
||||
m_parser_vars->m_target_info.byte_order,
|
||||
m_parser_vars->m_target_info.address_byte_size))
|
||||
return false;
|
||||
|
||||
ClangExpressionVariableSP var_sp (m_parser_vars->m_persistent_vars->GetVariable(name));
|
||||
|
@ -653,6 +732,204 @@ ClangExpressionDeclMap::GetSymbolAddress (const ConstString &name)
|
|||
return GetSymbolAddress(*m_parser_vars->m_exe_ctx->target, name);
|
||||
}
|
||||
|
||||
// Interface for IRInterpreter
|
||||
|
||||
bool
|
||||
ClangExpressionDeclMap::WriteTarget (lldb_private::Value &value,
|
||||
const uint8_t *data,
|
||||
size_t length)
|
||||
{
|
||||
assert (m_parser_vars.get());
|
||||
|
||||
ExecutionContext *exe_ctx = m_parser_vars->m_exe_ctx;
|
||||
|
||||
if (value.GetContextType() == Value::eContextTypeRegisterInfo)
|
||||
{
|
||||
if (!exe_ctx->process)
|
||||
return false;
|
||||
|
||||
RegisterContext *reg_ctx = exe_ctx->GetRegisterContext();
|
||||
RegisterInfo *reg_info = value.GetRegisterInfo();
|
||||
|
||||
if (!reg_ctx)
|
||||
return false;
|
||||
|
||||
lldb_private::RegisterValue reg_value;
|
||||
Error err;
|
||||
|
||||
if (!reg_value.SetFromMemoryData (reg_info, data, length, exe_ctx->process->GetByteOrder(), err))
|
||||
return false;
|
||||
|
||||
return reg_ctx->WriteRegister(reg_info, reg_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (value.GetValueType())
|
||||
{
|
||||
default:
|
||||
return false;
|
||||
case Value::eValueTypeFileAddress:
|
||||
{
|
||||
if (!exe_ctx->process)
|
||||
return false;
|
||||
|
||||
Address file_addr;
|
||||
|
||||
if (!exe_ctx->target->GetImages().ResolveFileAddress((lldb::addr_t)value.GetScalar().ULongLong(), file_addr))
|
||||
return false;
|
||||
|
||||
lldb::addr_t load_addr = file_addr.GetLoadAddress(exe_ctx->target);
|
||||
|
||||
Error err;
|
||||
exe_ctx->process->WriteMemory(load_addr, data, length, err);
|
||||
|
||||
return err.Success();
|
||||
}
|
||||
case Value::eValueTypeLoadAddress:
|
||||
{
|
||||
if (!exe_ctx->process)
|
||||
return false;
|
||||
|
||||
Error err;
|
||||
exe_ctx->process->WriteMemory((lldb::addr_t)value.GetScalar().ULongLong(), data, length, err);
|
||||
|
||||
return err.Success();
|
||||
}
|
||||
case Value::eValueTypeHostAddress:
|
||||
memcpy ((void *)value.GetScalar().ULongLong(), data, length);
|
||||
return true;
|
||||
case Value::eValueTypeScalar:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ClangExpressionDeclMap::ReadTarget (uint8_t *data,
|
||||
lldb_private::Value &value,
|
||||
size_t length)
|
||||
{
|
||||
assert (m_parser_vars.get());
|
||||
|
||||
ExecutionContext *exe_ctx = m_parser_vars->m_exe_ctx;
|
||||
|
||||
if (value.GetContextType() == Value::eContextTypeRegisterInfo)
|
||||
{
|
||||
if (!exe_ctx->process)
|
||||
return false;
|
||||
|
||||
RegisterContext *reg_ctx = exe_ctx->GetRegisterContext();
|
||||
RegisterInfo *reg_info = value.GetRegisterInfo();
|
||||
|
||||
if (!reg_ctx)
|
||||
return false;
|
||||
|
||||
lldb_private::RegisterValue reg_value;
|
||||
Error err;
|
||||
|
||||
if (!reg_ctx->ReadRegister(reg_info, reg_value))
|
||||
return false;
|
||||
|
||||
return reg_value.GetAsMemoryData(reg_info, data, length, exe_ctx->process->GetByteOrder(), err);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (value.GetValueType())
|
||||
{
|
||||
default:
|
||||
return false;
|
||||
case Value::eValueTypeFileAddress:
|
||||
{
|
||||
if (!exe_ctx->target)
|
||||
return false;
|
||||
|
||||
Address file_addr;
|
||||
|
||||
if (!exe_ctx->target->GetImages().ResolveFileAddress((lldb::addr_t)value.GetScalar().ULongLong(), file_addr))
|
||||
return false;
|
||||
|
||||
Error err;
|
||||
exe_ctx->target->ReadMemory(file_addr, true, data, length, err);
|
||||
|
||||
return err.Success();
|
||||
}
|
||||
case Value::eValueTypeLoadAddress:
|
||||
{
|
||||
if (!exe_ctx->process)
|
||||
return false;
|
||||
|
||||
Error err;
|
||||
exe_ctx->process->ReadMemory((lldb::addr_t)value.GetScalar().ULongLong(), data, length, err);
|
||||
|
||||
return err.Success();
|
||||
}
|
||||
case Value::eValueTypeHostAddress:
|
||||
memcpy (data, (const void *)value.GetScalar().ULongLong(), length);
|
||||
return true;
|
||||
case Value::eValueTypeScalar:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lldb_private::Value
|
||||
ClangExpressionDeclMap::LookupDecl (clang::NamedDecl *decl)
|
||||
{
|
||||
assert (m_parser_vars.get());
|
||||
|
||||
ExecutionContext exe_ctx = *m_parser_vars->m_exe_ctx;
|
||||
|
||||
ClangExpressionVariableSP expr_var_sp (m_found_entities.GetVariable(decl));
|
||||
ClangExpressionVariableSP persistent_var_sp (m_parser_vars->m_persistent_vars->GetVariable(decl));
|
||||
|
||||
if (expr_var_sp)
|
||||
{
|
||||
const ConstString &name(expr_var_sp->GetName());
|
||||
TypeFromUser type(expr_var_sp->GetTypeFromUser());
|
||||
|
||||
if (m_parser_vars->m_exe_ctx->frame)
|
||||
{
|
||||
VariableSP var(FindVariableInScope (*exe_ctx.frame, name, &type));
|
||||
|
||||
if (var)
|
||||
return *GetVariableValue(exe_ctx, var, NULL);
|
||||
}
|
||||
|
||||
if (m_parser_vars->m_exe_ctx->target)
|
||||
{
|
||||
VariableSP global(FindGlobalVariable (*exe_ctx.target, name.GetCString(), &type));
|
||||
|
||||
if (global)
|
||||
return *GetVariableValue(exe_ctx, global, NULL);
|
||||
|
||||
lldb::addr_t location_load_addr = GetSymbolAddress(*exe_ctx.target, name);
|
||||
|
||||
if (location_load_addr != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
lldb_private::Value ret;
|
||||
ret.SetValueType(Value::eValueTypeLoadAddress);
|
||||
ret.SetContext(Value::eContextTypeInvalid, NULL);
|
||||
ret.GetScalar() = location_load_addr;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return Value();
|
||||
}
|
||||
else if (persistent_var_sp)
|
||||
{
|
||||
lldb_private::Value ret;
|
||||
ret.SetValueType(Value::eValueTypeHostAddress);
|
||||
ret.SetContext(Value::eContextTypeInvalid, NULL);
|
||||
ret.GetScalar() = (lldb::addr_t)persistent_var_sp->GetValueBytes();
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Value();
|
||||
}
|
||||
}
|
||||
|
||||
// Interface for CommandObjectExpression
|
||||
|
||||
bool
|
||||
|
@ -1630,8 +1907,8 @@ ClangExpressionDeclMap::FindGlobalDataSymbol
|
|||
SymbolContextList sc_list;
|
||||
|
||||
target.GetImages().FindSymbolsWithNameAndType(name,
|
||||
eSymbolTypeData,
|
||||
sc_list);
|
||||
eSymbolTypeData,
|
||||
sc_list);
|
||||
|
||||
if (sc_list.GetSize())
|
||||
{
|
||||
|
@ -1644,7 +1921,67 @@ ClangExpressionDeclMap::FindGlobalDataSymbol
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// This is a callback used with Variable::GetValuesForVariableExpressionPath
|
||||
|
||||
static uint32_t GetVariableCallback (void *baton,
|
||||
const char *name,
|
||||
VariableList &variable_list)
|
||||
{
|
||||
Target *target = static_cast<Target *>(baton);
|
||||
if (target)
|
||||
{
|
||||
return target->GetImages().FindGlobalVariables (ConstString(name),
|
||||
true,
|
||||
UINT32_MAX,
|
||||
variable_list);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
lldb::VariableSP
|
||||
ClangExpressionDeclMap::FindGlobalVariable
|
||||
(
|
||||
Target &target,
|
||||
const char *name,
|
||||
TypeFromUser *type
|
||||
)
|
||||
{
|
||||
VariableList vars;
|
||||
ValueObjectList valobjs;
|
||||
|
||||
Error error (Variable::GetValuesForVariableExpressionPath (name,
|
||||
&target,
|
||||
GetVariableCallback,
|
||||
&target,
|
||||
vars,
|
||||
valobjs));
|
||||
|
||||
if (vars.GetSize())
|
||||
{
|
||||
if (type)
|
||||
{
|
||||
for (size_t i = 0; i < vars.GetSize(); ++i)
|
||||
{
|
||||
VariableSP var_sp = vars.GetVariableAtIndex(i);
|
||||
|
||||
if (type->GetASTContext() == var_sp->GetType()->GetClangAST())
|
||||
{
|
||||
if (ClangASTContext::AreTypesSame(type->GetASTContext(), type->GetOpaqueQualType(), var_sp->GetType()->GetClangFullType()))
|
||||
return var_sp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return vars.GetVariableAtIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
return VariableSP();
|
||||
}
|
||||
|
||||
// Interface for ClangASTSource
|
||||
|
||||
void
|
||||
ClangExpressionDeclMap::GetDecls (NameSearchContext &context, const ConstString &name)
|
||||
{
|
||||
|
@ -1656,10 +1993,6 @@ ClangExpressionDeclMap::GetDecls (NameSearchContext &context, const ConstString
|
|||
if (log)
|
||||
log->Printf("Hunting for a definition for '%s'", name.GetCString());
|
||||
|
||||
// Back out in all cases where we're not fully initialized
|
||||
if (m_parser_vars->m_exe_ctx->frame == NULL)
|
||||
return;
|
||||
|
||||
if (m_parser_vars->m_ignore_lookups)
|
||||
{
|
||||
if (log)
|
||||
|
@ -1740,19 +2073,37 @@ ClangExpressionDeclMap::GetDecls (NameSearchContext &context, const ConstString
|
|||
ValueObjectSP valobj;
|
||||
VariableSP var;
|
||||
Error err;
|
||||
bool found = false;
|
||||
|
||||
valobj = m_parser_vars->m_exe_ctx->frame->GetValueForVariableExpressionPath(name_unique_cstr,
|
||||
eNoDynamicValues,
|
||||
StackFrame::eExpressionPathOptionCheckPtrVsMember,
|
||||
var,
|
||||
err);
|
||||
|
||||
// If we found a variable in scope, no need to pull up function names
|
||||
if (err.Success() && var != NULL)
|
||||
if (m_parser_vars->m_exe_ctx->frame)
|
||||
{
|
||||
AddOneVariable(context, var);
|
||||
valobj = m_parser_vars->m_exe_ctx->frame->GetValueForVariableExpressionPath(name_unique_cstr,
|
||||
eNoDynamicValues,
|
||||
StackFrame::eExpressionPathOptionCheckPtrVsMember,
|
||||
var,
|
||||
err);
|
||||
|
||||
// If we found a variable in scope, no need to pull up function names
|
||||
if (err.Success() && var != NULL)
|
||||
{
|
||||
AddOneVariable(context, var);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (m_parser_vars->m_exe_ctx->target)
|
||||
{
|
||||
var = FindGlobalVariable(*m_parser_vars->m_exe_ctx->target,
|
||||
name_unique_cstr,
|
||||
NULL);
|
||||
|
||||
if (var)
|
||||
{
|
||||
AddOneVariable(context, var);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
const bool include_symbols = true;
|
||||
const bool append = false;
|
||||
|
@ -1781,6 +2132,7 @@ ClangExpressionDeclMap::GetDecls (NameSearchContext &context, const ConstString
|
|||
if (!found_specific)
|
||||
AddOneFunction(context, sym_ctx.function, NULL);
|
||||
found_specific = true;
|
||||
found = true;
|
||||
}
|
||||
else if (sym_ctx.symbol)
|
||||
{
|
||||
|
@ -1794,12 +2146,19 @@ ClangExpressionDeclMap::GetDecls (NameSearchContext &context, const ConstString
|
|||
if (!found_specific)
|
||||
{
|
||||
if (generic_symbol)
|
||||
{
|
||||
AddOneFunction (context, NULL, generic_symbol);
|
||||
found = true;
|
||||
}
|
||||
else if (non_extern_symbol)
|
||||
{
|
||||
AddOneFunction (context, NULL, non_extern_symbol);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (!found)
|
||||
{
|
||||
// We couldn't find a variable or function for this. Now we'll hunt for a generic
|
||||
// data symbol, and -- if it is found -- treat it as a variable.
|
||||
|
@ -1807,7 +2166,10 @@ ClangExpressionDeclMap::GetDecls (NameSearchContext &context, const ConstString
|
|||
Symbol *data_symbol = FindGlobalDataSymbol(*m_parser_vars->m_exe_ctx->target, name);
|
||||
|
||||
if (data_symbol)
|
||||
{
|
||||
AddOneGenericVariable(context, *data_symbol);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1829,15 +2191,19 @@ ClangExpressionDeclMap::GetDecls (NameSearchContext &context, const ConstString
|
|||
NamespaceDecl *clang_namespace_decl = AddNamespace(context, namespace_decl);
|
||||
if (clang_namespace_decl)
|
||||
clang_namespace_decl->setHasExternalLexicalStorage();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static ConstString g_lldb_class_name ("$__lldb_class");
|
||||
|
||||
if (name == g_lldb_class_name)
|
||||
{
|
||||
// Clang is looking for the type of "this"
|
||||
|
||||
if (!m_parser_vars->m_exe_ctx->frame)
|
||||
return;
|
||||
|
||||
VariableList *vars = m_parser_vars->m_exe_ctx->frame->GetVariableList(false);
|
||||
|
||||
if (!vars)
|
||||
|
@ -1900,6 +2266,9 @@ ClangExpressionDeclMap::GetDecls (NameSearchContext &context, const ConstString
|
|||
{
|
||||
// Clang is looking for the type of "*self"
|
||||
|
||||
if (!m_parser_vars->m_exe_ctx->frame)
|
||||
return;
|
||||
|
||||
VariableList *vars = m_parser_vars->m_exe_ctx->frame->GetVariableList(false);
|
||||
|
||||
if (!vars)
|
||||
|
@ -2213,8 +2582,11 @@ ClangExpressionDeclMap::GetVariableValue
|
|||
|
||||
lldb::addr_t load_addr = so_addr.GetLoadAddress(exe_ctx.target);
|
||||
|
||||
var_location->GetScalar() = load_addr;
|
||||
var_location->SetValueType(Value::eValueTypeLoadAddress);
|
||||
if (load_addr != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
var_location->GetScalar() = load_addr;
|
||||
var_location->SetValueType(Value::eValueTypeLoadAddress);
|
||||
}
|
||||
}
|
||||
|
||||
if (user_type)
|
||||
|
@ -2229,7 +2601,7 @@ ClangExpressionDeclMap::AddOneVariable (NameSearchContext &context, VariableSP v
|
|||
assert (m_parser_vars.get());
|
||||
|
||||
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
||||
|
||||
TypeFromUser ut;
|
||||
TypeFromParser pt;
|
||||
|
||||
|
@ -2248,8 +2620,8 @@ ClangExpressionDeclMap::AddOneVariable (NameSearchContext &context, VariableSP v
|
|||
ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx->GetBestExecutionContextScope (),
|
||||
entity_name,
|
||||
ut,
|
||||
m_parser_vars->m_exe_ctx->process->GetByteOrder(),
|
||||
m_parser_vars->m_exe_ctx->process->GetAddressByteSize()));
|
||||
m_parser_vars->m_target_info.byte_order,
|
||||
m_parser_vars->m_target_info.address_byte_size));
|
||||
assert (entity.get());
|
||||
entity->EnableParserVars();
|
||||
entity->m_parser_vars->m_parser_type = pt;
|
||||
|
@ -2331,8 +2703,8 @@ ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context,
|
|||
ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx->GetBestExecutionContextScope (),
|
||||
entity_name,
|
||||
user_type,
|
||||
m_parser_vars->m_exe_ctx->process->GetByteOrder(),
|
||||
m_parser_vars->m_exe_ctx->process->GetAddressByteSize()));
|
||||
m_parser_vars->m_target_info.byte_order,
|
||||
m_parser_vars->m_target_info.address_byte_size));
|
||||
assert (entity.get());
|
||||
|
||||
std::auto_ptr<Value> symbol_location(new Value);
|
||||
|
@ -2449,8 +2821,8 @@ ClangExpressionDeclMap::AddOneRegister (NameSearchContext &context,
|
|||
NamedDecl *var_decl = context.AddVarDecl(parser_type.GetOpaqueQualType());
|
||||
|
||||
ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx->GetBestExecutionContextScope(),
|
||||
m_parser_vars->m_exe_ctx->process->GetByteOrder(),
|
||||
m_parser_vars->m_exe_ctx->process->GetAddressByteSize()));
|
||||
m_parser_vars->m_target_info.byte_order,
|
||||
m_parser_vars->m_target_info.address_byte_size));
|
||||
assert (entity.get());
|
||||
std::string decl_name(context.m_decl_name.getAsString());
|
||||
entity->SetName (ConstString (decl_name.c_str()));
|
||||
|
@ -2547,8 +2919,8 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
|
|||
fun_location->GetScalar() = load_addr;
|
||||
|
||||
ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx->GetBestExecutionContextScope (),
|
||||
m_parser_vars->m_exe_ctx->process->GetByteOrder(),
|
||||
m_parser_vars->m_exe_ctx->process->GetAddressByteSize()));
|
||||
m_parser_vars->m_target_info.byte_order,
|
||||
m_parser_vars->m_target_info.address_byte_size));
|
||||
assert (entity.get());
|
||||
std::string decl_name(context.m_decl_name.getAsString());
|
||||
entity->SetName(ConstString(decl_name.c_str()));
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "lldb/Expression/ClangExpression.h"
|
||||
#include "lldb/Expression/ClangExpressionDeclMap.h"
|
||||
#include "lldb/Expression/IRDynamicChecks.h"
|
||||
#include "lldb/Expression/IRToDWARF.h"
|
||||
#include "lldb/Expression/RecordingMemoryManager.h"
|
||||
#include "lldb/Target/ExecutionContext.h"
|
||||
#include "lldb/Target/ObjCLanguageRuntime.h"
|
||||
|
@ -418,66 +417,14 @@ static bool FindFunctionInModule (std::string &mangled_name,
|
|||
}
|
||||
|
||||
Error
|
||||
ClangExpressionParser::MakeDWARF ()
|
||||
{
|
||||
Error err;
|
||||
|
||||
llvm::Module *module = m_code_generator->GetModule();
|
||||
|
||||
if (!module)
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("IR doesn't contain a module");
|
||||
return err;
|
||||
}
|
||||
|
||||
ClangExpressionVariableList *local_variables = m_expr.LocalVariables();
|
||||
ClangExpressionDeclMap *decl_map = m_expr.DeclMap();
|
||||
|
||||
if (!local_variables)
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Can't convert an expression without a VariableList to DWARF");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!decl_map)
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Can't convert an expression without a DeclMap to DWARF");
|
||||
return err;
|
||||
}
|
||||
|
||||
std::string function_name;
|
||||
|
||||
if (!FindFunctionInModule(function_name, module, m_expr.FunctionName()))
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName());
|
||||
return err;
|
||||
}
|
||||
|
||||
IRToDWARF ir_to_dwarf(*local_variables, decl_map, m_expr.DwarfOpcodeStream(), function_name.c_str());
|
||||
|
||||
if (!ir_to_dwarf.runOnModule(*module))
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Couldn't convert the expression to DWARF");
|
||||
return err;
|
||||
}
|
||||
|
||||
err.Clear();
|
||||
return err;
|
||||
}
|
||||
|
||||
Error
|
||||
ClangExpressionParser::MakeJIT (lldb::addr_t &func_allocation_addr,
|
||||
lldb::addr_t &func_addr,
|
||||
lldb::addr_t &func_end,
|
||||
ExecutionContext &exe_ctx,
|
||||
IRForTarget::StaticDataAllocator *data_allocator,
|
||||
lldb::ClangExpressionVariableSP &const_result,
|
||||
bool jit_only_if_needed)
|
||||
ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_allocation_addr,
|
||||
lldb::addr_t &func_addr,
|
||||
lldb::addr_t &func_end,
|
||||
ExecutionContext &exe_ctx,
|
||||
IRForTarget::StaticDataAllocator *data_allocator,
|
||||
bool &evaluated_statically,
|
||||
lldb::ClangExpressionVariableSP &const_result,
|
||||
ExecutionPolicy execution_policy)
|
||||
{
|
||||
func_allocation_addr = LLDB_INVALID_ADDRESS;
|
||||
func_addr = LLDB_INVALID_ADDRESS;
|
||||
|
@ -520,8 +467,9 @@ ClangExpressionParser::MakeJIT (lldb::addr_t &func_allocation_addr,
|
|||
if (exe_ctx.target)
|
||||
error_stream = &exe_ctx.target->GetDebugger().GetErrorStream();
|
||||
|
||||
IRForTarget ir_for_target(decl_map,
|
||||
IRForTarget ir_for_target(decl_map,
|
||||
m_expr.NeedsVariableResolution(),
|
||||
execution_policy,
|
||||
const_result,
|
||||
data_allocator,
|
||||
error_stream,
|
||||
|
@ -530,17 +478,25 @@ ClangExpressionParser::MakeJIT (lldb::addr_t &func_allocation_addr,
|
|||
if (!ir_for_target.runOnModule(*module))
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Couldn't convert the expression to DWARF");
|
||||
err.SetErrorString("Couldn't prepare the expression for execution in the target");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (jit_only_if_needed && const_result.get())
|
||||
if (execution_policy != eExecutionPolicyAlways && ir_for_target.interpretSuccess())
|
||||
{
|
||||
evaluated_statically = true;
|
||||
err.Clear();
|
||||
return err;
|
||||
}
|
||||
|
||||
if (m_expr.NeedsValidation() && exe_ctx.process->GetDynamicCheckers())
|
||||
if (!exe_ctx.process || execution_policy == eExecutionPolicyNever)
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Execution needed to run in the target, but the target can't be run");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (m_expr.NeedsValidation() && exe_ctx.process && exe_ctx.process->GetDynamicCheckers())
|
||||
{
|
||||
IRDynamicChecks ir_dynamic_checks(*exe_ctx.process->GetDynamicCheckers(), function_name.c_str());
|
||||
|
||||
|
|
|
@ -253,7 +253,16 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors)
|
|||
|
||||
lldb::ClangExpressionVariableSP const_result;
|
||||
|
||||
Error jit_error (m_parser->MakeJIT (m_jit_alloc, m_jit_start_addr, m_jit_end_addr, exe_ctx, NULL, const_result));
|
||||
bool evaluated_statically = false; // should stay that way
|
||||
|
||||
Error jit_error (m_parser->PrepareForExecution (m_jit_alloc,
|
||||
m_jit_start_addr,
|
||||
m_jit_end_addr,
|
||||
exe_ctx,
|
||||
NULL,
|
||||
evaluated_statically,
|
||||
const_result,
|
||||
eExecutionPolicyAlways));
|
||||
|
||||
if (!jit_error.Success())
|
||||
return false;
|
||||
|
|
|
@ -53,6 +53,7 @@ ClangUserExpression::ClangUserExpression (const char *expr,
|
|||
m_objectivec (false),
|
||||
m_needs_object_ptr (false),
|
||||
m_const_object (false),
|
||||
m_evaluated_statically (false),
|
||||
m_const_result (),
|
||||
m_target (NULL)
|
||||
{
|
||||
|
@ -167,6 +168,7 @@ bool
|
|||
ClangUserExpression::Parse (Stream &error_stream,
|
||||
ExecutionContext &exe_ctx,
|
||||
TypeFromUser desired_type,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
bool keep_result_in_memory)
|
||||
{
|
||||
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
@ -279,39 +281,23 @@ ClangUserExpression::Parse (Stream &error_stream,
|
|||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// Convert the output of the parser to DWARF
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Prepare the output of the parser for execution, evaluating it statically if possible
|
||||
//
|
||||
|
||||
m_dwarf_opcodes.reset(new StreamString);
|
||||
m_dwarf_opcodes->SetByteOrder (lldb::endian::InlHostByteOrder());
|
||||
m_dwarf_opcodes->GetFlags ().Set (Stream::eBinary);
|
||||
|
||||
m_local_variables.reset(new ClangExpressionVariableList());
|
||||
|
||||
Error dwarf_error = parser.MakeDWARF ();
|
||||
|
||||
if (dwarf_error.Success())
|
||||
{
|
||||
if (log)
|
||||
log->Printf("Code can be interpreted.");
|
||||
|
||||
m_expr_decl_map->DidParse();
|
||||
|
||||
return true;
|
||||
}
|
||||
if (execution_policy != eExecutionPolicyNever && exe_ctx.process)
|
||||
m_data_allocator.reset(new ProcessDataAllocator(*exe_ctx.process));
|
||||
|
||||
//////////////////////////////////
|
||||
// JIT the output of the parser
|
||||
//
|
||||
Error jit_error = parser.PrepareForExecution (m_jit_alloc,
|
||||
m_jit_start_addr,
|
||||
m_jit_end_addr,
|
||||
exe_ctx,
|
||||
m_data_allocator.get(),
|
||||
m_evaluated_statically,
|
||||
m_const_result,
|
||||
execution_policy);
|
||||
|
||||
m_dwarf_opcodes.reset();
|
||||
|
||||
m_data_allocator.reset(new ProcessDataAllocator(*exe_ctx.process));
|
||||
|
||||
Error jit_error = parser.MakeJIT (m_jit_alloc, m_jit_start_addr, m_jit_end_addr, exe_ctx, m_data_allocator.get(), m_const_result, true);
|
||||
|
||||
if (log)
|
||||
if (log && m_data_allocator.get())
|
||||
{
|
||||
StreamString dump_string;
|
||||
m_data_allocator->Dump(dump_string);
|
||||
|
@ -505,15 +491,7 @@ ClangUserExpression::Execute (Stream &error_stream,
|
|||
// expression, it's quite convenient to have these logs come out with the STEP log as well.
|
||||
lldb::LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
|
||||
|
||||
if (m_dwarf_opcodes.get())
|
||||
{
|
||||
// TODO execute the JITted opcodes
|
||||
|
||||
error_stream.Printf("We don't currently support executing DWARF expressions");
|
||||
|
||||
return eExecutionSetupError;
|
||||
}
|
||||
else if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
|
||||
if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
lldb::addr_t struct_address;
|
||||
|
||||
|
@ -594,38 +572,31 @@ ClangUserExpression::Execute (Stream &error_stream,
|
|||
}
|
||||
else
|
||||
{
|
||||
error_stream.Printf("Expression can't be run; neither DWARF nor a JIT compiled function is present");
|
||||
error_stream.Printf("Expression can't be run, because there is no JIT compiled function");
|
||||
return eExecutionSetupError;
|
||||
}
|
||||
}
|
||||
|
||||
StreamString &
|
||||
ClangUserExpression::DwarfOpcodeStream ()
|
||||
{
|
||||
if (!m_dwarf_opcodes.get())
|
||||
m_dwarf_opcodes.reset(new StreamString());
|
||||
|
||||
return *m_dwarf_opcodes.get();
|
||||
}
|
||||
|
||||
ExecutionResults
|
||||
ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
|
||||
ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
bool discard_on_error,
|
||||
const char *expr_cstr,
|
||||
const char *expr_prefix,
|
||||
lldb::ValueObjectSP &result_valobj_sp)
|
||||
{
|
||||
Error error;
|
||||
return EvaluateWithError (exe_ctx, discard_on_error, expr_cstr, expr_prefix, result_valobj_sp, error);
|
||||
return EvaluateWithError (exe_ctx, execution_policy, discard_on_error, expr_cstr, expr_prefix, result_valobj_sp, error);
|
||||
}
|
||||
|
||||
ExecutionResults
|
||||
ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
|
||||
bool discard_on_error,
|
||||
const char *expr_cstr,
|
||||
const char *expr_prefix,
|
||||
lldb::ValueObjectSP &result_valobj_sp,
|
||||
Error &error)
|
||||
ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
bool discard_on_error,
|
||||
const char *expr_cstr,
|
||||
const char *expr_prefix,
|
||||
lldb::ValueObjectSP &result_valobj_sp,
|
||||
Error &error)
|
||||
{
|
||||
lldb::LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
|
||||
|
||||
|
@ -633,13 +604,18 @@ ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
|
|||
|
||||
if (exe_ctx.process == NULL || exe_ctx.process->GetState() != lldb::eStateStopped)
|
||||
{
|
||||
error.SetErrorString ("must have a stopped process to evaluate expressions.");
|
||||
if (execution_policy == eExecutionPolicyAlways)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant ==");
|
||||
|
||||
result_valobj_sp = ValueObjectConstResult::Create (NULL, error);
|
||||
return eExecutionSetupError;
|
||||
error.SetErrorString ("expression needed to run but couldn't");
|
||||
|
||||
return execution_results;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exe_ctx.process->GetDynamicCheckers())
|
||||
|
||||
if (execution_policy != eExecutionPolicyNever && !exe_ctx.process->GetDynamicCheckers())
|
||||
{
|
||||
if (log)
|
||||
log->Printf("== [ClangUserExpression::Evaluate] Installing dynamic checkers ==");
|
||||
|
@ -672,7 +648,9 @@ ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
|
|||
if (log)
|
||||
log->Printf("== [ClangUserExpression::Evaluate] Parsing expression %s ==", expr_cstr);
|
||||
|
||||
if (!user_expression_sp->Parse (error_stream, exe_ctx, TypeFromUser(NULL, NULL), true))
|
||||
const bool keep_expression_in_memory = true;
|
||||
|
||||
if (!user_expression_sp->Parse (error_stream, exe_ctx, TypeFromUser(NULL, NULL), execution_policy, keep_expression_in_memory))
|
||||
{
|
||||
if (error_stream.GetString().empty())
|
||||
error.SetErrorString ("expression failed to parse, unknown error");
|
||||
|
@ -683,14 +661,26 @@ ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
|
|||
{
|
||||
lldb::ClangExpressionVariableSP expr_result;
|
||||
|
||||
if (user_expression_sp->m_const_result.get())
|
||||
if (user_expression_sp->EvaluatedStatically())
|
||||
{
|
||||
if (log)
|
||||
log->Printf("== [ClangUserExpression::Evaluate] Expression evaluated as a constant ==");
|
||||
|
||||
result_valobj_sp = user_expression_sp->m_const_result->GetValueObject();
|
||||
if (user_expression_sp->m_const_result)
|
||||
result_valobj_sp = user_expression_sp->m_const_result->GetValueObject();
|
||||
else
|
||||
error.SetError(ClangUserExpression::kNoResult, lldb::eErrorTypeGeneric);
|
||||
|
||||
execution_results = eExecutionCompleted;
|
||||
}
|
||||
else if (execution_policy == eExecutionPolicyNever)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant ==");
|
||||
|
||||
if (error_stream.GetString().empty())
|
||||
error.SetErrorString ("expression needed to run but couldn't");
|
||||
}
|
||||
else
|
||||
{
|
||||
error_stream.GetString().clear();
|
||||
|
|
|
@ -128,8 +128,16 @@ ClangUtilityFunction::Install (Stream &error_stream,
|
|||
|
||||
lldb::ClangExpressionVariableSP const_result;
|
||||
|
||||
|
||||
Error jit_error = parser.MakeJIT (m_jit_alloc, m_jit_start_addr, m_jit_end_addr, exe_ctx, m_data_allocator.get(), const_result);
|
||||
bool evaluated_statically = false; // should stay that way
|
||||
|
||||
Error jit_error = parser.PrepareForExecution (m_jit_alloc,
|
||||
m_jit_start_addr,
|
||||
m_jit_end_addr,
|
||||
exe_ctx,
|
||||
m_data_allocator.get(),
|
||||
evaluated_statically,
|
||||
const_result,
|
||||
eExecutionPolicyAlways);
|
||||
|
||||
if (log)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===-- IRForTarget.cpp -------------------------------------------*- C++ -*-===//
|
||||
//===-- IRForTarget.cpp -----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -26,6 +26,7 @@
|
|||
#include "lldb/Core/Scalar.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Expression/ClangExpressionDeclMap.h"
|
||||
#include "lldb/Expression/IRInterpreter.h"
|
||||
#include "lldb/Host/Endian.h"
|
||||
#include "lldb/Symbol/ClangASTContext.h"
|
||||
|
||||
|
@ -45,12 +46,15 @@ IRForTarget::StaticDataAllocator::~StaticDataAllocator()
|
|||
|
||||
IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
|
||||
bool resolve_vars,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
lldb::ClangExpressionVariableSP &const_result,
|
||||
StaticDataAllocator *data_allocator,
|
||||
lldb_private::Stream *error_stream,
|
||||
const char *func_name) :
|
||||
ModulePass(ID),
|
||||
m_resolve_vars(resolve_vars),
|
||||
m_execution_policy(execution_policy),
|
||||
m_interpret_success(false),
|
||||
m_func_name(func_name),
|
||||
m_module(NULL),
|
||||
m_decl_map(decl_map),
|
||||
|
@ -309,12 +313,13 @@ IRForTarget::ResolveFunctionPointers(llvm::Module &llvm_module,
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
clang::NamedDecl *
|
||||
IRForTarget::DeclForGlobal (GlobalValue *global_val)
|
||||
IRForTarget::DeclForGlobal (const GlobalValue *global_val, Module *module)
|
||||
{
|
||||
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
||||
NamedMDNode *named_metadata = m_module->getNamedMetadata("clang.global.decl.ptrs");
|
||||
NamedMDNode *named_metadata = module->getNamedMetadata("clang.global.decl.ptrs");
|
||||
|
||||
if (!named_metadata)
|
||||
return NULL;
|
||||
|
@ -350,6 +355,12 @@ IRForTarget::DeclForGlobal (GlobalValue *global_val)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
clang::NamedDecl *
|
||||
IRForTarget::DeclForGlobal (GlobalValue *global_val)
|
||||
{
|
||||
return DeclForGlobal(global_val, m_module);
|
||||
}
|
||||
|
||||
void
|
||||
IRForTarget::MaybeSetConstantResult (llvm::Constant *initializer,
|
||||
const lldb_private::ConstString &name,
|
||||
|
@ -553,9 +564,7 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
|
|||
|
||||
// Get the next available result name from m_decl_map and create the persistent
|
||||
// variable for it
|
||||
|
||||
lldb_private::TypeFromParser result_decl_type;
|
||||
|
||||
|
||||
// If the result is an Lvalue, it is emitted as a pointer; see
|
||||
// ASTResultSynthesizer::SynthesizeBodyResult.
|
||||
if (m_result_is_pointer)
|
||||
|
@ -577,19 +586,19 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
|
|||
|
||||
clang::QualType element_qual_type = pointer_pointertype->getPointeeType();
|
||||
|
||||
result_decl_type = lldb_private::TypeFromParser(element_qual_type.getAsOpaquePtr(),
|
||||
m_result_type = lldb_private::TypeFromParser(element_qual_type.getAsOpaquePtr(),
|
||||
&result_decl->getASTContext());
|
||||
}
|
||||
else
|
||||
{
|
||||
result_decl_type = lldb_private::TypeFromParser(result_var->getType().getAsOpaquePtr(),
|
||||
m_result_type = lldb_private::TypeFromParser(result_var->getType().getAsOpaquePtr(),
|
||||
&result_decl->getASTContext());
|
||||
}
|
||||
|
||||
if (log)
|
||||
{
|
||||
lldb_private::StreamString type_desc_stream;
|
||||
result_decl_type.DumpTypeDescription(&type_desc_stream);
|
||||
m_result_type.DumpTypeDescription(&type_desc_stream);
|
||||
|
||||
log->Printf("Result decl type: \"%s\"", type_desc_stream.GetString().c_str());
|
||||
}
|
||||
|
@ -665,7 +674,7 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
|
|||
{
|
||||
MaybeSetConstantResult (initializer,
|
||||
m_result_name,
|
||||
result_decl_type);
|
||||
m_result_type);
|
||||
}
|
||||
|
||||
StoreInst *synthesized_store = new StoreInst(initializer,
|
||||
|
@ -677,9 +686,9 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!m_has_side_effects && lldb_private::ClangASTContext::IsPointerType (result_decl_type.GetOpaqueQualType()))
|
||||
if (!m_has_side_effects && lldb_private::ClangASTContext::IsPointerType (m_result_type.GetOpaqueQualType()))
|
||||
{
|
||||
MaybeSetCastResult (result_decl_type);
|
||||
MaybeSetCastResult (m_result_type);
|
||||
}
|
||||
|
||||
result_global->replaceAllUsesWith(new_result_global);
|
||||
|
@ -688,7 +697,7 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
|
|||
if (!m_const_result)
|
||||
m_decl_map->AddPersistentVariable(result_decl,
|
||||
m_result_name,
|
||||
result_decl_type,
|
||||
m_result_type,
|
||||
true,
|
||||
m_result_is_pointer);
|
||||
|
||||
|
@ -2247,6 +2256,9 @@ IRForTarget::BuildRelocation(llvm::Type *type,
|
|||
bool
|
||||
IRForTarget::CompleteDataAllocation ()
|
||||
{
|
||||
if (!m_data_allocator)
|
||||
return true;
|
||||
|
||||
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
||||
if (!m_data_allocator->GetStream().GetSize())
|
||||
|
@ -2335,9 +2347,49 @@ IRForTarget::runOnModule (Module &llvm_module)
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_const_result)
|
||||
|
||||
if (m_const_result && m_execution_policy != lldb_private::eExecutionPolicyAlways)
|
||||
{
|
||||
m_interpret_success = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (bbi = function->begin();
|
||||
bbi != function->end();
|
||||
++bbi)
|
||||
{
|
||||
if (!RemoveGuards(*bbi))
|
||||
{
|
||||
if (log)
|
||||
log->Printf("RemoveGuards() failed");
|
||||
|
||||
// RemoveGuards() reports its own errors, so we don't do so here
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!RewritePersistentAllocs(*bbi))
|
||||
{
|
||||
if (log)
|
||||
log->Printf("RewritePersistentAllocs() failed");
|
||||
|
||||
// RewritePersistentAllocs() reports its own errors, so we don't do so here
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_decl_map && m_execution_policy != lldb_private::eExecutionPolicyAlways)
|
||||
{
|
||||
IRInterpreter interpreter (*m_decl_map,
|
||||
m_error_stream);
|
||||
|
||||
if (interpreter.maybeRunOnFunction(m_const_result, m_result_name, m_result_type, *function, llvm_module))
|
||||
{
|
||||
m_interpret_success = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (log)
|
||||
{
|
||||
|
@ -2379,34 +2431,10 @@ IRForTarget::runOnModule (Module &llvm_module)
|
|||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
// Run basic-block level passes
|
||||
//
|
||||
|
||||
for (bbi = function->begin();
|
||||
bbi != function->end();
|
||||
++bbi)
|
||||
{
|
||||
if (!RemoveGuards(*bbi))
|
||||
{
|
||||
if (log)
|
||||
log->Printf("RemoveGuards() failed");
|
||||
|
||||
// RemoveGuards() reports its own errors, so we don't do so here
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!RewritePersistentAllocs(*bbi))
|
||||
{
|
||||
if (log)
|
||||
log->Printf("RewritePersistentAllocs() failed");
|
||||
|
||||
// RewritePersistentAllocs() reports its own errors, so we don't do so here
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!RewriteObjCSelectors(*bbi))
|
||||
{
|
||||
if (log)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,219 +0,0 @@
|
|||
//===-- IRToDWARF.cpp -------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lldb/Expression/IRToDWARF.h"
|
||||
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/InstrTypes.h"
|
||||
#include "llvm/Module.h"
|
||||
|
||||
#include "lldb/Core/dwarf.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Core/Scalar.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Expression/ClangExpressionDeclMap.h"
|
||||
#include "lldb/Expression/ClangExpressionVariable.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static char ID;
|
||||
|
||||
IRToDWARF::IRToDWARF(lldb_private::ClangExpressionVariableList &local_vars,
|
||||
lldb_private::ClangExpressionDeclMap *decl_map,
|
||||
lldb_private::StreamString &strm,
|
||||
const char *func_name) :
|
||||
ModulePass(ID),
|
||||
m_func_name(func_name),
|
||||
m_local_vars(local_vars),
|
||||
m_decl_map(decl_map),
|
||||
m_strm(strm)
|
||||
{
|
||||
}
|
||||
|
||||
IRToDWARF::~IRToDWARF()
|
||||
{
|
||||
}
|
||||
|
||||
class Relocator
|
||||
{
|
||||
public:
|
||||
Relocator()
|
||||
{
|
||||
}
|
||||
|
||||
~Relocator()
|
||||
{
|
||||
}
|
||||
|
||||
void MarkBasicBlock(BasicBlock *bb, uint16_t offset)
|
||||
{
|
||||
m_basic_blocks[bb] = offset;
|
||||
}
|
||||
|
||||
bool BasicBlockIsMarked(BasicBlock *bb)
|
||||
{
|
||||
return m_basic_blocks.find(bb) != m_basic_blocks.end();
|
||||
}
|
||||
|
||||
void MarkRelocation(BasicBlock *bb, uint16_t offset)
|
||||
{
|
||||
m_relocations[offset] = bb;
|
||||
}
|
||||
|
||||
bool ResolveRelocations(lldb_private::StreamString &strm)
|
||||
{
|
||||
std::map<uint16_t, BasicBlock*>::const_iterator iter;
|
||||
|
||||
lldb_private::StreamString swapper(0, 32, strm.GetByteOrder());
|
||||
|
||||
// This array must be delete [] d at every exit
|
||||
size_t temporary_bufsize = strm.GetSize();
|
||||
uint8_t *temporary_buffer(new uint8_t[temporary_bufsize]);
|
||||
|
||||
memcpy(temporary_buffer, strm.GetData(), temporary_bufsize);
|
||||
|
||||
for (iter = m_relocations.begin();
|
||||
iter != m_relocations.end();
|
||||
++iter)
|
||||
{
|
||||
const std::pair<uint16_t, BasicBlock*> &pair = *iter;
|
||||
|
||||
uint16_t off = pair.first;
|
||||
BasicBlock *bb = pair.second;
|
||||
|
||||
if (m_basic_blocks.find(bb) == m_basic_blocks.end())
|
||||
{
|
||||
delete [] temporary_buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t target_off = m_basic_blocks[bb];
|
||||
|
||||
int16_t relative = (int16_t)target_off - (int16_t)off;
|
||||
|
||||
swapper.Clear();
|
||||
swapper << relative;
|
||||
|
||||
// off is intended to be the offset of the branch opcode (which is
|
||||
// what the relative location is added to) so
|
||||
// (temporary_buffer + off + 1) skips the opcode and writes to the
|
||||
// relative location
|
||||
memcpy(temporary_buffer + off + 1, swapper.GetData(), sizeof(uint16_t));
|
||||
}
|
||||
|
||||
strm.Clear();
|
||||
strm.Write(temporary_buffer, temporary_bufsize);
|
||||
|
||||
delete [] temporary_buffer;
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
std::map<BasicBlock*, uint16_t> m_basic_blocks;
|
||||
std::map<uint16_t, BasicBlock*> m_relocations;
|
||||
};
|
||||
|
||||
bool
|
||||
IRToDWARF::runOnBasicBlock(BasicBlock &BB, Relocator &R)
|
||||
{
|
||||
///////////////////////////////////////
|
||||
// Mark the current block as visited
|
||||
//
|
||||
|
||||
size_t stream_size = m_strm.GetSize();
|
||||
|
||||
if (stream_size > 0xffff)
|
||||
return false;
|
||||
|
||||
uint16_t offset = stream_size & 0xffff;
|
||||
|
||||
R.MarkBasicBlock(&BB, offset);
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// Translate the current basic block to DWARF
|
||||
//
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Visit all successors we haven't visited yet
|
||||
//
|
||||
|
||||
TerminatorInst *arnold = BB.getTerminator();
|
||||
|
||||
if (!arnold)
|
||||
return false;
|
||||
|
||||
unsigned successor_index;
|
||||
unsigned num_successors = arnold->getNumSuccessors();
|
||||
|
||||
for (successor_index = 0;
|
||||
successor_index < num_successors;
|
||||
++successor_index)
|
||||
{
|
||||
BasicBlock *successor = arnold->getSuccessor(successor_index);
|
||||
|
||||
if (!R.BasicBlockIsMarked(successor))
|
||||
{
|
||||
if (!runOnBasicBlock(*successor, R))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IRToDWARF::runOnModule(Module &M)
|
||||
{
|
||||
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
||||
llvm::Function* function = M.getFunction(StringRef(m_func_name.c_str()));
|
||||
|
||||
if (!function)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("Couldn't find %s() in the module", m_func_name.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Relocator relocator;
|
||||
|
||||
if (!runOnBasicBlock(function->getEntryBlock(), relocator))
|
||||
return false;
|
||||
|
||||
if (log && log->GetVerbose())
|
||||
{
|
||||
std::string s;
|
||||
raw_string_ostream oss(s);
|
||||
|
||||
M.print(oss, NULL);
|
||||
|
||||
oss.flush();
|
||||
|
||||
log->Printf ("Module being translated to DWARF: \n%s", s.c_str());
|
||||
}
|
||||
|
||||
// TEMPORARY: Fail in order to force execution in the target.
|
||||
return false;
|
||||
|
||||
return relocator.ResolveRelocations(m_strm);
|
||||
}
|
||||
|
||||
void
|
||||
IRToDWARF::assignPassManager(PMStack &PMS,
|
||||
PassManagerType T)
|
||||
{
|
||||
}
|
||||
|
||||
PassManagerType
|
||||
IRToDWARF::getPotentialPassManagerType() const
|
||||
{
|
||||
return PMT_ModulePassManager;
|
||||
}
|
|
@ -117,7 +117,8 @@ clang::Decl
|
|||
{
|
||||
ObjCInterfaceDecl *to_interface_decl = dyn_cast<ObjCInterfaceDecl>(to);
|
||||
|
||||
to_interface_decl->setExternallyCompleted();
|
||||
if (!to_interface_decl->isForwardDecl())
|
||||
to_interface_decl->setExternallyCompleted();
|
||||
}
|
||||
|
||||
return clang::ASTImporter::Imported(from, to);
|
||||
|
|
|
@ -1154,7 +1154,7 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)
|
|||
expr.Printf("dlopen (\"%s\", 2)", path);
|
||||
const char *prefix = "extern \"C\" void* dlopen (const char *path, int mode);\n";
|
||||
lldb::ValueObjectSP result_valobj_sp;
|
||||
ClangUserExpression::Evaluate (exe_ctx, unwind_on_error, expr.GetData(), prefix, result_valobj_sp);
|
||||
ClangUserExpression::Evaluate (exe_ctx, eExecutionPolicyAlways, unwind_on_error, expr.GetData(), prefix, result_valobj_sp);
|
||||
error = result_valobj_sp->GetError();
|
||||
if (error.Success())
|
||||
{
|
||||
|
@ -1218,7 +1218,7 @@ Process::UnloadImage (uint32_t image_token)
|
|||
expr.Printf("dlclose ((void *)0x%llx)", image_addr);
|
||||
const char *prefix = "extern \"C\" int dlclose(void* handle);\n";
|
||||
lldb::ValueObjectSP result_valobj_sp;
|
||||
ClangUserExpression::Evaluate (exe_ctx, unwind_on_error, expr.GetData(), prefix, result_valobj_sp);
|
||||
ClangUserExpression::Evaluate (exe_ctx, eExecutionPolicyAlways, unwind_on_error, expr.GetData(), prefix, result_valobj_sp);
|
||||
if (result_valobj_sp->GetError().Success())
|
||||
{
|
||||
Scalar scalar;
|
||||
|
|
|
@ -194,11 +194,12 @@ public:
|
|||
const bool discard_on_error = true;
|
||||
Error error;
|
||||
result_code = ClangUserExpression::EvaluateWithError (context.exe_ctx,
|
||||
discard_on_error,
|
||||
bp_loc_sp->GetConditionText(),
|
||||
NULL,
|
||||
result_value_sp,
|
||||
error);
|
||||
eExecutionPolicyAlways,
|
||||
discard_on_error,
|
||||
bp_loc_sp->GetConditionText(),
|
||||
NULL,
|
||||
result_value_sp,
|
||||
error);
|
||||
if (result_code == eExecutionCompleted)
|
||||
{
|
||||
if (result_value_sp)
|
||||
|
|
|
@ -1133,6 +1133,7 @@ Target::EvaluateExpression
|
|||
(
|
||||
const char *expr_cstr,
|
||||
StackFrame *frame,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
bool unwind_on_error,
|
||||
bool keep_in_memory,
|
||||
lldb::DynamicValueType use_dynamic,
|
||||
|
@ -1242,8 +1243,9 @@ Target::EvaluateExpression
|
|||
else
|
||||
{
|
||||
const char *prefix = GetExpressionPrefixContentsAsCString();
|
||||
|
||||
|
||||
execution_results = ClangUserExpression::Evaluate (exe_ctx,
|
||||
execution_policy,
|
||||
unwind_on_error,
|
||||
expr_cstr,
|
||||
prefix,
|
||||
|
|
Loading…
Reference in New Issue