forked from OSchip/llvm-project
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
This commit is contained in:
parent
526560a553
commit
1582ee6840
|
@ -114,8 +114,7 @@ public:
|
|||
lldb::addr_t &func_end,
|
||||
STD_UNIQUE_PTR(IRExecutionUnit) &execution_unit_ap,
|
||||
ExecutionContext &exe_ctx,
|
||||
bool &evaluated_statically,
|
||||
lldb::ClangExpressionVariableSP &const_result,
|
||||
bool &can_interpret,
|
||||
lldb_private::ExecutionPolicy execution_policy);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "lldb/Expression/ClangExpression.h"
|
||||
#include "lldb/Expression/ClangExpressionVariable.h"
|
||||
#include "lldb/Expression/IRForTarget.h"
|
||||
#include "lldb/Expression/Materializer.h"
|
||||
#include "lldb/Symbol/TaggedASTType.h"
|
||||
#include "lldb/Target/ExecutionContext.h"
|
||||
|
||||
|
@ -105,6 +106,12 @@ public:
|
|||
lldb_private::ExecutionPolicy execution_policy,
|
||||
bool keep_result_in_memory);
|
||||
|
||||
bool
|
||||
CanInterpret ()
|
||||
{
|
||||
return m_can_interpret;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Execute the parsed expression
|
||||
///
|
||||
|
@ -375,12 +382,6 @@ private:
|
|||
lldb::addr_t &object_ptr,
|
||||
lldb::addr_t &cmd_ptr);
|
||||
|
||||
bool
|
||||
EvaluatedStatically ()
|
||||
{
|
||||
return m_evaluated_statically;
|
||||
}
|
||||
|
||||
void
|
||||
InstallContext (ExecutionContext &exe_ctx)
|
||||
{
|
||||
|
@ -432,8 +433,9 @@ 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.
|
||||
bool m_can_interpret; ///< True if the expression could be evaluated statically; false otherwise.
|
||||
lldb::addr_t m_materialized_address; ///< The address at which the arguments to the expression have been materialized.
|
||||
Materializer::DematerializerSP m_dematerializer_sp; ///< The dematerializer.
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
|
|
@ -90,8 +90,6 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map,
|
||||
bool resolve_vars,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
lldb::ClangExpressionVariableSP &const_result,
|
||||
lldb_private::IRExecutionUnit &execution_unit,
|
||||
lldb_private::Stream *error_stream,
|
||||
const char* func_name = "$__lldb_expr");
|
||||
|
@ -139,18 +137,6 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
virtual llvm::PassManagerType
|
||||
getPotentialPassManagerType() const;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Checks whether the IR interpreter successfully interpreted the
|
||||
/// expression.
|
||||
///
|
||||
/// Returns true if it did; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
lldb_private::Error &
|
||||
getInterpreterError ()
|
||||
{
|
||||
return m_interpreter_error;
|
||||
}
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
|
@ -664,8 +650,6 @@ 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.
|
||||
|
@ -676,9 +660,7 @@ private:
|
|||
lldb_private::IRMemoryMap &m_memory_map; ///< The memory map to pass to the IR interpreter
|
||||
llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the appropriate function pointer type
|
||||
llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate function pointer type
|
||||
lldb::ClangExpressionVariableSP &m_const_result; ///< This value should be set to the return value of the expression if it is constant and the expression has no side effects
|
||||
lldb_private::Stream *m_error_stream; ///< If non-NULL, the stream on which errors should be printed
|
||||
lldb_private::Error m_interpreter_error; ///< The error result from the IR interpreter
|
||||
|
||||
bool m_has_side_effects; ///< True if the function's result cannot be simply determined statically
|
||||
llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that writes to the result variable. If m_has_side_effects is true, this is NULL.
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "lldb/Core/ConstString.h"
|
||||
#include "lldb/Core/Stream.h"
|
||||
#include "lldb/Symbol/TaggedASTType.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
|
@ -88,6 +89,7 @@ public:
|
|||
static bool
|
||||
Interpret (llvm::Module &module,
|
||||
llvm::Function &function,
|
||||
llvm::ArrayRef<lldb::addr_t> args,
|
||||
lldb_private::IRMemoryMap &memory_map,
|
||||
lldb_private::Error &error);
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
}
|
||||
|
||||
void Dematerialize (Error &err,
|
||||
lldb::ClangExpressionVariableSP &result_sp,
|
||||
lldb::addr_t frame_top,
|
||||
lldb::addr_t frame_bottom);
|
||||
|
||||
|
@ -75,11 +76,11 @@ public:
|
|||
typedef STD_SHARED_PTR(Dematerializer) DematerializerSP;
|
||||
typedef STD_WEAK_PTR(Dematerializer) DematerializerWP;
|
||||
|
||||
DematerializerSP Materialize (lldb::StackFrameSP &frame_sp, lldb::ClangExpressionVariableSP &result_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err);
|
||||
DematerializerSP Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err);
|
||||
|
||||
uint32_t AddPersistentVariable (lldb::ClangExpressionVariableSP &persistent_variable_sp, Error &err);
|
||||
uint32_t AddVariable (lldb::VariableSP &variable_sp, Error &err);
|
||||
uint32_t AddResultVariable (const ClangASTType &type, bool keep_in_memory, Error &err);
|
||||
uint32_t AddResultVariable (const TypeFromUser &type, bool is_lvalue, bool keep_in_memory, Error &err);
|
||||
uint32_t AddSymbol (const Symbol &symbol_sp, Error &err);
|
||||
uint32_t AddRegister (const RegisterInfo ®ister_info, Error &err);
|
||||
|
||||
|
@ -93,6 +94,14 @@ public:
|
|||
return m_current_offset;
|
||||
}
|
||||
|
||||
uint32_t GetResultOffset ()
|
||||
{
|
||||
if (m_result_entity)
|
||||
return m_result_entity->GetOffset();
|
||||
else
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
class Entity
|
||||
{
|
||||
public:
|
||||
|
@ -149,6 +158,7 @@ private:
|
|||
unsigned m_result_index;
|
||||
DematerializerWP m_dematerializer_wp;
|
||||
EntityVector m_entities;
|
||||
Entity *m_result_entity;
|
||||
uint32_t m_current_offset;
|
||||
uint32_t m_struct_alignment;
|
||||
};
|
||||
|
|
|
@ -459,6 +459,51 @@ ClangExpressionDeclMap::AddPersistentVariable
|
|||
{
|
||||
assert (m_parser_vars.get());
|
||||
|
||||
if (m_parser_vars->m_materializer && is_result)
|
||||
{
|
||||
Error err;
|
||||
|
||||
ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
|
||||
Target *target = exe_ctx.GetTargetPtr();
|
||||
if (target == NULL)
|
||||
return false;
|
||||
|
||||
ASTContext *context(target->GetScratchClangASTContext()->getASTContext());
|
||||
|
||||
TypeFromUser user_type(m_ast_importer->DeportType(context,
|
||||
parser_type.GetASTContext(),
|
||||
parser_type.GetOpaqueQualType()),
|
||||
context);
|
||||
|
||||
uint32_t offset = m_parser_vars->m_materializer->AddResultVariable(user_type, is_lvalue, m_keep_result_in_memory, err);
|
||||
|
||||
m_found_entities.CreateVariable(exe_ctx.GetBestExecutionContextScope(),
|
||||
name,
|
||||
user_type,
|
||||
m_parser_vars->m_target_info.byte_order,
|
||||
m_parser_vars->m_target_info.address_byte_size);
|
||||
|
||||
ClangExpressionVariableSP var_sp (m_found_entities.GetVariable(name));
|
||||
|
||||
if (!var_sp)
|
||||
return false;
|
||||
|
||||
var_sp->EnableParserVars(GetParserID());
|
||||
|
||||
ClangExpressionVariable::ParserVars *parser_vars = var_sp->GetParserVars(GetParserID());
|
||||
|
||||
parser_vars->m_named_decl = decl;
|
||||
parser_vars->m_parser_type = parser_type;
|
||||
|
||||
var_sp->EnableJITVars(GetParserID());
|
||||
|
||||
ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID());
|
||||
|
||||
jit_vars->m_offset = offset;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
|
||||
Target *target = exe_ctx.GetTargetPtr();
|
||||
|
@ -526,12 +571,6 @@ ClangExpressionDeclMap::AddPersistentVariable
|
|||
parser_vars->m_named_decl = decl;
|
||||
parser_vars->m_parser_type = parser_type;
|
||||
|
||||
if (m_parser_vars->m_materializer)
|
||||
{
|
||||
Error err;
|
||||
m_parser_vars->m_materializer->AddResultVariable(user_type, m_keep_result_in_memory, err);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -581,6 +620,14 @@ ClangExpressionDeclMap::AddValueToStruct
|
|||
|
||||
parser_vars->m_llvm_value = value;
|
||||
|
||||
if (ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID()))
|
||||
{
|
||||
// We already laid this out; do not touch
|
||||
|
||||
if (log)
|
||||
log->Printf("Already placed at 0x%llx", (unsigned long long)jit_vars->m_offset);
|
||||
}
|
||||
|
||||
var_sp->EnableJITVars(GetParserID());
|
||||
|
||||
ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID());
|
||||
|
@ -1593,7 +1640,9 @@ ClangExpressionDeclMap::DoMaterialize
|
|||
|
||||
bool ret = true;
|
||||
|
||||
m_material_vars->m_dematerializer_sp->Dematerialize(dematerialize_error, stack_frame_top, stack_frame_bottom);
|
||||
ClangExpressionVariableSP result;
|
||||
|
||||
m_material_vars->m_dematerializer_sp->Dematerialize(dematerialize_error, result, stack_frame_top, stack_frame_bottom);
|
||||
m_material_vars->m_dematerializer_sp.reset();
|
||||
|
||||
if (!dematerialize_error.Success())
|
||||
|
@ -1663,7 +1712,7 @@ ClangExpressionDeclMap::DoMaterialize
|
|||
|
||||
Error materialize_error;
|
||||
|
||||
m_material_vars->m_dematerializer_sp = m_parser_vars->m_materializer->Materialize(frame_sp, result_sp, map, m_material_vars->m_materialized_location, materialize_error);
|
||||
m_material_vars->m_dematerializer_sp = m_parser_vars->m_materializer->Materialize(frame_sp, map, m_material_vars->m_materialized_location, materialize_error);
|
||||
|
||||
if (!materialize_error.Success())
|
||||
{
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "lldb/Expression/ClangExpressionDeclMap.h"
|
||||
#include "lldb/Expression/IRExecutionUnit.h"
|
||||
#include "lldb/Expression/IRDynamicChecks.h"
|
||||
#include "lldb/Expression/IRInterpreter.h"
|
||||
#include "lldb/Target/ExecutionContext.h"
|
||||
#include "lldb/Target/ObjCLanguageRuntime.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
|
@ -464,8 +465,7 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
|
|||
lldb::addr_t &func_end,
|
||||
STD_UNIQUE_PTR(IRExecutionUnit) &execution_unit_ap,
|
||||
ExecutionContext &exe_ctx,
|
||||
bool &evaluated_statically,
|
||||
lldb::ClangExpressionVariableSP &const_result,
|
||||
bool &can_interpret,
|
||||
ExecutionPolicy execution_policy)
|
||||
{
|
||||
func_addr = LLDB_INVALID_ADDRESS;
|
||||
|
@ -518,50 +518,39 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
|
|||
|
||||
IRForTarget ir_for_target(decl_map,
|
||||
m_expr.NeedsVariableResolution(),
|
||||
execution_policy,
|
||||
const_result,
|
||||
*m_execution_unit,
|
||||
error_stream,
|
||||
function_name.AsCString());
|
||||
|
||||
bool ir_can_run = ir_for_target.runOnModule(*m_execution_unit->GetModule());
|
||||
|
||||
Error &interpreter_error(ir_for_target.getInterpreterError());
|
||||
Error interpret_error;
|
||||
|
||||
if (execution_policy != eExecutionPolicyAlways && interpreter_error.Success())
|
||||
{
|
||||
if (const_result)
|
||||
const_result->TransferAddress();
|
||||
evaluated_statically = true;
|
||||
err.Clear();
|
||||
return err;
|
||||
}
|
||||
can_interpret = IRInterpreter::CanInterpret(*m_execution_unit->GetModule(), *m_execution_unit->GetFunction(), interpret_error);
|
||||
|
||||
Process *process = exe_ctx.GetProcessPtr();
|
||||
|
||||
if (!process || execution_policy == eExecutionPolicyNever)
|
||||
|
||||
if (!ir_can_run)
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
if (execution_policy == eExecutionPolicyAlways)
|
||||
err.SetErrorString("Execution needed to run in the target, but the target can't be run");
|
||||
else
|
||||
err.SetErrorStringWithFormat("Interpreting the expression locally failed: %s", interpreter_error.AsCString());
|
||||
|
||||
return err;
|
||||
}
|
||||
else if (!ir_can_run)
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("The expression could not be prepared to run in the target");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
if (execution_policy != eExecutionPolicyNever &&
|
||||
m_expr.NeedsValidation() &&
|
||||
process)
|
||||
if (!can_interpret && execution_policy == eExecutionPolicyNever)
|
||||
{
|
||||
if (!process->GetDynamicCheckers())
|
||||
err.SetErrorStringWithFormat("Can't run the expression locally: %s", interpret_error.AsCString());
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!process && execution_policy == eExecutionPolicyAlways)
|
||||
{
|
||||
err.SetErrorString("Expression needed to run in the target, but the target can't be run");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (execution_policy == eExecutionPolicyAlways || !can_interpret)
|
||||
{
|
||||
if (!process->GetDynamicCheckers() && m_expr.NeedsValidation())
|
||||
{
|
||||
DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions();
|
||||
|
||||
|
@ -581,20 +570,24 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
|
|||
|
||||
if (log)
|
||||
log->Printf("== [ClangUserExpression::Evaluate] Finished installing dynamic checkers ==");
|
||||
|
||||
IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.AsCString());
|
||||
|
||||
if (!ir_dynamic_checks.runOnModule(*m_execution_unit->GetModule()))
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Couldn't add dynamic checks to the expression");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.AsCString());
|
||||
|
||||
if (!ir_dynamic_checks.runOnModule(*m_execution_unit->GetModule()))
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Couldn't add dynamic checks to the expression");
|
||||
return err;
|
||||
}
|
||||
m_execution_unit->GetRunnableInfo(err, func_addr, func_end);
|
||||
}
|
||||
}
|
||||
|
||||
m_execution_unit->GetRunnableInfo(err, func_addr, func_end);
|
||||
else
|
||||
{
|
||||
m_execution_unit->GetRunnableInfo(err, func_addr, func_end);
|
||||
}
|
||||
|
||||
execution_unit_ap.reset (m_execution_unit.release());
|
||||
|
||||
|
|
|
@ -260,17 +260,14 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors)
|
|||
|
||||
if (m_JITted)
|
||||
return true;
|
||||
|
||||
lldb::ClangExpressionVariableSP const_result;
|
||||
|
||||
bool evaluated_statically = false; // should stay that way
|
||||
|
||||
bool can_interpret = false; // should stay that way
|
||||
|
||||
Error jit_error (m_parser->PrepareForExecution (m_jit_start_addr,
|
||||
m_jit_end_addr,
|
||||
m_execution_unit_ap,
|
||||
exe_ctx,
|
||||
evaluated_statically,
|
||||
const_result,
|
||||
can_interpret,
|
||||
eExecutionPolicyAlways));
|
||||
|
||||
if (!jit_error.Success())
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "lldb/Expression/ClangUserExpression.h"
|
||||
#include "lldb/Expression/ExpressionSourceCode.h"
|
||||
#include "lldb/Expression/IRExecutionUnit.h"
|
||||
#include "lldb/Expression/IRInterpreter.h"
|
||||
#include "lldb/Expression/Materializer.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Symbol/Block.h"
|
||||
|
@ -67,8 +68,7 @@ ClangUserExpression::ClangUserExpression (const char *expr,
|
|||
m_needs_object_ptr (false),
|
||||
m_const_object (false),
|
||||
m_target (NULL),
|
||||
m_evaluated_statically (false),
|
||||
m_const_result ()
|
||||
m_can_interpret (false)
|
||||
{
|
||||
switch (m_language)
|
||||
{
|
||||
|
@ -469,8 +469,7 @@ ClangUserExpression::Parse (Stream &error_stream,
|
|||
m_jit_end_addr,
|
||||
m_execution_unit_ap,
|
||||
exe_ctx,
|
||||
m_evaluated_statically,
|
||||
m_const_result,
|
||||
m_can_interpret,
|
||||
execution_policy);
|
||||
|
||||
if (jit_error.Success())
|
||||
|
@ -490,6 +489,46 @@ ClangUserExpression::Parse (Stream &error_stream,
|
|||
}
|
||||
}
|
||||
|
||||
static lldb::addr_t
|
||||
GetObjectPointer (lldb::StackFrameSP frame_sp,
|
||||
ConstString &object_name,
|
||||
Error &err)
|
||||
{
|
||||
err.Clear();
|
||||
|
||||
if (!frame_sp)
|
||||
{
|
||||
err.SetErrorStringWithFormat("Couldn't load '%s' because the context is incomplete", object_name.AsCString());
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
lldb::VariableSP var_sp;
|
||||
lldb::ValueObjectSP valobj_sp;
|
||||
|
||||
valobj_sp = frame_sp->GetValueForVariableExpressionPath(object_name.AsCString(),
|
||||
lldb::eNoDynamicValues,
|
||||
StackFrame::eExpressionPathOptionCheckPtrVsMember ||
|
||||
StackFrame::eExpressionPathOptionsAllowDirectIVarAccess ||
|
||||
StackFrame::eExpressionPathOptionsNoFragileObjcIvar ||
|
||||
StackFrame::eExpressionPathOptionsNoSyntheticChildren ||
|
||||
StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,
|
||||
var_sp,
|
||||
err);
|
||||
|
||||
if (!err.Success())
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
||||
lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
|
||||
|
||||
if (ret == LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
err.SetErrorStringWithFormat("Couldn't load '%s' because its value couldn't be evaluated", object_name.AsCString());
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
|
||||
ExecutionContext &exe_ctx,
|
||||
|
@ -497,8 +536,6 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
|
|||
lldb::addr_t &object_ptr,
|
||||
lldb::addr_t &cmd_ptr)
|
||||
{
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
||||
lldb::TargetSP target;
|
||||
lldb::ProcessSP process;
|
||||
lldb::StackFrameSP frame;
|
||||
|
@ -512,10 +549,8 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
Error materialize_error;
|
||||
|
||||
if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret)
|
||||
{
|
||||
if (m_needs_object_ptr)
|
||||
{
|
||||
ConstString object_name;
|
||||
|
@ -534,9 +569,13 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!(m_expr_decl_map->GetObjectPointer(object_ptr, object_name, materialize_error)))
|
||||
Error object_ptr_error;
|
||||
|
||||
object_ptr = GetObjectPointer(frame, object_name, object_ptr_error);
|
||||
|
||||
if (!object_ptr_error.Success())
|
||||
{
|
||||
error_stream.Printf("warning: couldn't get required object pointer (substituting NULL): %s\n", materialize_error.AsCString());
|
||||
error_stream.Printf("warning: couldn't get required object pointer (substituting NULL): %s\n", object_ptr_error.AsCString());
|
||||
object_ptr = 0;
|
||||
}
|
||||
|
||||
|
@ -544,53 +583,41 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
|
|||
{
|
||||
ConstString cmd_name("_cmd");
|
||||
|
||||
if (!(m_expr_decl_map->GetObjectPointer(cmd_ptr, cmd_name, materialize_error, true)))
|
||||
cmd_ptr = GetObjectPointer(frame, cmd_name, object_ptr_error);
|
||||
|
||||
if (!object_ptr_error.Success())
|
||||
{
|
||||
error_stream.Printf("warning: couldn't get object pointer (substituting NULL): %s\n", materialize_error.AsCString());
|
||||
error_stream.Printf("warning: couldn't get cmd pointer (substituting NULL): %s\n", object_ptr_error.AsCString());
|
||||
cmd_ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_expr_decl_map->Materialize(*m_execution_unit_ap, struct_address, materialize_error))
|
||||
|
||||
Error alloc_error;
|
||||
|
||||
struct_address = m_execution_unit_ap->Malloc(m_materializer_ap->GetStructByteSize(),
|
||||
m_materializer_ap->GetStructAlignment(),
|
||||
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
|
||||
IRMemoryMap::eAllocationPolicyMirror,
|
||||
alloc_error);
|
||||
|
||||
if (!alloc_error.Success())
|
||||
{
|
||||
error_stream.Printf("Couldn't allocate space for materialized struct: %s\n", alloc_error.AsCString());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_materialized_address = struct_address;
|
||||
|
||||
Error materialize_error;
|
||||
|
||||
m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_ap, struct_address, materialize_error);
|
||||
|
||||
if (!materialize_error.Success())
|
||||
{
|
||||
error_stream.Printf("Couldn't materialize struct: %s\n", materialize_error.AsCString());
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// jingham: look here
|
||||
StreamFile logfile ("/tmp/exprs.txt", "a");
|
||||
logfile.Printf("0x%16.16" PRIx64 ": thread = 0x%4.4x, expr = '%s'\n", m_jit_start_addr, exe_ctx.thread ? exe_ctx.thread->GetID() : -1, m_expr_text.c_str());
|
||||
#endif
|
||||
|
||||
if (log)
|
||||
{
|
||||
log->Printf("-- [ClangUserExpression::PrepareToExecuteJITExpression] Materializing for execution --");
|
||||
|
||||
log->Printf(" Function address : 0x%" PRIx64, (uint64_t)m_jit_start_addr);
|
||||
|
||||
if (m_needs_object_ptr)
|
||||
log->Printf(" Object pointer : 0x%" PRIx64, (uint64_t)object_ptr);
|
||||
|
||||
log->Printf(" Structure address : 0x%" PRIx64, (uint64_t)struct_address);
|
||||
|
||||
StreamString args;
|
||||
|
||||
Error dump_error;
|
||||
|
||||
if (struct_address)
|
||||
{
|
||||
if (!m_expr_decl_map->DumpMaterializedStruct(args, dump_error))
|
||||
{
|
||||
log->Printf(" Couldn't extract variable values : %s", dump_error.AsCString("unknown error"));
|
||||
}
|
||||
else
|
||||
{
|
||||
log->Printf(" Structure contents:\n%s", args.GetData());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -635,35 +662,31 @@ ClangUserExpression::FinalizeJITExecution (Stream &error_stream,
|
|||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
||||
if (log)
|
||||
{
|
||||
log->Printf("-- [ClangUserExpression::FinalizeJITExecution] Dematerializing after execution --");
|
||||
|
||||
StreamString args;
|
||||
|
||||
Error dump_error;
|
||||
|
||||
if (!m_expr_decl_map->DumpMaterializedStruct(args, dump_error))
|
||||
{
|
||||
log->Printf(" Couldn't extract variable values : %s", dump_error.AsCString("unknown error"));
|
||||
}
|
||||
else
|
||||
{
|
||||
log->Printf(" Structure contents:\n%s", args.GetData());
|
||||
}
|
||||
}
|
||||
|
||||
lldb::addr_t function_stack_bottom = function_stack_pointer - Host::GetPageSize();
|
||||
|
||||
|
||||
if (!m_expr_decl_map->Dematerialize(result, *m_execution_unit_ap, function_stack_pointer, function_stack_bottom, expr_error))
|
||||
if (!m_dematerializer_sp)
|
||||
{
|
||||
error_stream.Printf ("Couldn't dematerialize struct : no dematerializer is present");
|
||||
return false;
|
||||
}
|
||||
|
||||
Error dematerialize_error;
|
||||
|
||||
m_dematerializer_sp->Dematerialize(dematerialize_error, result, function_stack_pointer, function_stack_bottom);
|
||||
|
||||
if (!dematerialize_error.Success())
|
||||
{
|
||||
error_stream.Printf ("Couldn't dematerialize struct : %s\n", expr_error.AsCString("unknown error"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (result)
|
||||
result->TransferAddress();
|
||||
|
||||
m_dematerializer_sp.reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -681,7 +704,7 @@ ClangUserExpression::Execute (Stream &error_stream,
|
|||
// expression, it's quite convenient to have these logs come out with the STEP log as well.
|
||||
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
|
||||
|
||||
if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
|
||||
if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret)
|
||||
{
|
||||
lldb::addr_t struct_address = LLDB_INVALID_ADDRESS;
|
||||
|
||||
|
@ -694,73 +717,115 @@ ClangUserExpression::Execute (Stream &error_stream,
|
|||
return eExecutionSetupError;
|
||||
}
|
||||
|
||||
const bool stop_others = true;
|
||||
const bool try_all_threads = run_others;
|
||||
lldb::addr_t function_stack_pointer = NULL;
|
||||
|
||||
Address wrapper_address (m_jit_start_addr);
|
||||
lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
|
||||
wrapper_address,
|
||||
struct_address,
|
||||
stop_others,
|
||||
unwind_on_error,
|
||||
ignore_breakpoints,
|
||||
(m_needs_object_ptr ? &object_ptr : NULL),
|
||||
((m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL),
|
||||
shared_ptr_to_me));
|
||||
|
||||
if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream))
|
||||
return eExecutionSetupError;
|
||||
|
||||
lldb::addr_t function_stack_pointer = static_cast<ThreadPlanCallFunction *>(call_plan_sp.get())->GetFunctionStackPointer();
|
||||
|
||||
if (log)
|
||||
log->Printf("-- [ClangUserExpression::Execute] Execution of expression begins --");
|
||||
|
||||
if (exe_ctx.GetProcessPtr())
|
||||
exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
|
||||
if (m_can_interpret)
|
||||
{
|
||||
llvm::Module *module = m_execution_unit_ap->GetModule();
|
||||
llvm::Function *function = m_execution_unit_ap->GetFunction();
|
||||
|
||||
ExecutionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx,
|
||||
call_plan_sp,
|
||||
stop_others,
|
||||
try_all_threads,
|
||||
unwind_on_error,
|
||||
ignore_breakpoints,
|
||||
timeout_usec,
|
||||
error_stream);
|
||||
|
||||
if (exe_ctx.GetProcessPtr())
|
||||
exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
|
||||
|
||||
if (log)
|
||||
log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --");
|
||||
|
||||
if (execution_result == eExecutionInterrupted || execution_result == eExecutionHitBreakpoint)
|
||||
{
|
||||
const char *error_desc = NULL;
|
||||
|
||||
if (call_plan_sp)
|
||||
if (!module || !function)
|
||||
{
|
||||
lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo();
|
||||
if (real_stop_info_sp)
|
||||
error_desc = real_stop_info_sp->GetDescription();
|
||||
error_stream.Printf("Supposed to interpret, but nothing is there");
|
||||
return eExecutionSetupError;
|
||||
}
|
||||
if (error_desc)
|
||||
error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc);
|
||||
else
|
||||
error_stream.Printf ("Execution was interrupted.");
|
||||
|
||||
if ((execution_result == eExecutionInterrupted && unwind_on_error)
|
||||
|| (execution_result == eExecutionHitBreakpoint && ignore_breakpoints))
|
||||
error_stream.Printf ("\nThe process has been returned to the state before expression evaluation.");
|
||||
else
|
||||
error_stream.Printf ("\nThe process has been left at the point where it was interrupted, use \"thread return -x\" to return to the state before expression evaluation.");
|
||||
|
||||
return execution_result;
|
||||
Error interpreter_error;
|
||||
|
||||
llvm::SmallVector <lldb::addr_t, 3> args;
|
||||
|
||||
if (m_needs_object_ptr)
|
||||
{
|
||||
args.push_back(object_ptr);
|
||||
|
||||
if (m_objectivec)
|
||||
args.push_back(cmd_ptr);
|
||||
}
|
||||
|
||||
args.push_back(struct_address);
|
||||
|
||||
IRInterpreter::Interpret (*module,
|
||||
*function,
|
||||
args,
|
||||
*m_execution_unit_ap.get(),
|
||||
interpreter_error);
|
||||
|
||||
if (!interpreter_error.Success())
|
||||
{
|
||||
error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString());
|
||||
return eExecutionDiscarded;
|
||||
}
|
||||
}
|
||||
else if (execution_result != eExecutionCompleted)
|
||||
else
|
||||
{
|
||||
error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result));
|
||||
return execution_result;
|
||||
const bool stop_others = true;
|
||||
const bool try_all_threads = run_others;
|
||||
|
||||
Address wrapper_address (m_jit_start_addr);
|
||||
lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
|
||||
wrapper_address,
|
||||
struct_address,
|
||||
stop_others,
|
||||
unwind_on_error,
|
||||
ignore_breakpoints,
|
||||
(m_needs_object_ptr ? &object_ptr : NULL),
|
||||
((m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL),
|
||||
shared_ptr_to_me));
|
||||
|
||||
if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream))
|
||||
return eExecutionSetupError;
|
||||
|
||||
function_stack_pointer = static_cast<ThreadPlanCallFunction *>(call_plan_sp.get())->GetFunctionStackPointer();
|
||||
|
||||
if (log)
|
||||
log->Printf("-- [ClangUserExpression::Execute] Execution of expression begins --");
|
||||
|
||||
if (exe_ctx.GetProcessPtr())
|
||||
exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
|
||||
|
||||
ExecutionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx,
|
||||
call_plan_sp,
|
||||
stop_others,
|
||||
try_all_threads,
|
||||
unwind_on_error,
|
||||
ignore_breakpoints,
|
||||
timeout_usec,
|
||||
error_stream);
|
||||
|
||||
if (exe_ctx.GetProcessPtr())
|
||||
exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
|
||||
|
||||
if (log)
|
||||
log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --");
|
||||
|
||||
if (execution_result == eExecutionInterrupted || execution_result == eExecutionHitBreakpoint)
|
||||
{
|
||||
const char *error_desc = NULL;
|
||||
|
||||
if (call_plan_sp)
|
||||
{
|
||||
lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo();
|
||||
if (real_stop_info_sp)
|
||||
error_desc = real_stop_info_sp->GetDescription();
|
||||
}
|
||||
if (error_desc)
|
||||
error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc);
|
||||
else
|
||||
error_stream.Printf ("Execution was interrupted.");
|
||||
|
||||
if ((execution_result == eExecutionInterrupted && unwind_on_error)
|
||||
|| (execution_result == eExecutionHitBreakpoint && ignore_breakpoints))
|
||||
error_stream.Printf ("\nThe process has been returned to the state before expression evaluation.");
|
||||
else
|
||||
error_stream.Printf ("\nThe process has been left at the point where it was interrupted, use \"thread return -x\" to return to the state before expression evaluation.");
|
||||
|
||||
return execution_result;
|
||||
}
|
||||
else if (execution_result != eExecutionCompleted)
|
||||
{
|
||||
error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result));
|
||||
return execution_result;
|
||||
}
|
||||
}
|
||||
|
||||
if (FinalizeJITExecution (error_stream, exe_ctx, result, function_stack_pointer))
|
||||
|
@ -862,19 +927,8 @@ ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
|
|||
{
|
||||
lldb::ClangExpressionVariableSP expr_result;
|
||||
|
||||
if (user_expression_sp->EvaluatedStatically())
|
||||
{
|
||||
if (log)
|
||||
log->Printf("== [ClangUserExpression::Evaluate] Expression evaluated as a constant ==");
|
||||
|
||||
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 (execution_policy == eExecutionPolicyNever &&
|
||||
!user_expression_sp->CanInterpret())
|
||||
{
|
||||
if (log)
|
||||
log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant ==");
|
||||
|
|
|
@ -125,17 +125,14 @@ ClangUtilityFunction::Install (Stream &error_stream,
|
|||
//////////////////////////////////
|
||||
// JIT the output of the parser
|
||||
//
|
||||
|
||||
lldb::ClangExpressionVariableSP const_result;
|
||||
|
||||
bool evaluated_statically = false; // should stay that way
|
||||
|
||||
bool can_interpret = false; // should stay that way
|
||||
|
||||
Error jit_error = parser.PrepareForExecution (m_jit_start_addr,
|
||||
m_jit_end_addr,
|
||||
m_execution_unit_ap,
|
||||
exe_ctx,
|
||||
evaluated_statically,
|
||||
const_result,
|
||||
can_interpret,
|
||||
eExecutionPolicyAlways);
|
||||
|
||||
if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
|
||||
|
|
|
@ -42,6 +42,7 @@ static char ID;
|
|||
|
||||
IRForTarget::StaticDataAllocator::StaticDataAllocator(lldb_private::IRExecutionUnit &execution_unit) :
|
||||
m_execution_unit(execution_unit),
|
||||
m_stream_string(lldb_private::Stream::eBinary, execution_unit.GetAddressByteSize(), execution_unit.GetByteOrder()),
|
||||
m_allocation(LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
}
|
||||
|
@ -63,15 +64,11 @@ lldb::addr_t IRForTarget::StaticDataAllocator::Allocate()
|
|||
|
||||
IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
|
||||
bool resolve_vars,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
lldb::ClangExpressionVariableSP &const_result,
|
||||
lldb_private::IRExecutionUnit &execution_unit,
|
||||
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),
|
||||
|
@ -79,7 +76,6 @@ IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
|
|||
m_memory_map(execution_unit),
|
||||
m_CFStringCreateWithBytes(NULL),
|
||||
m_sel_registerName(NULL),
|
||||
m_const_result(const_result),
|
||||
m_error_stream(error_stream),
|
||||
m_has_side_effects(false),
|
||||
m_result_store(NULL),
|
||||
|
@ -444,97 +440,6 @@ IRForTarget::DeclForGlobal (GlobalValue *global_val)
|
|||
return DeclForGlobal(global_val, m_module);
|
||||
}
|
||||
|
||||
void
|
||||
IRForTarget::MaybeSetConstantResult (llvm::Constant *initializer,
|
||||
const lldb_private::ConstString &name,
|
||||
lldb_private::TypeFromParser type)
|
||||
{
|
||||
if (llvm::ConstantExpr *init_expr = dyn_cast<llvm::ConstantExpr>(initializer))
|
||||
{
|
||||
switch (init_expr->getOpcode())
|
||||
{
|
||||
default:
|
||||
return;
|
||||
case Instruction::IntToPtr:
|
||||
MaybeSetConstantResult (init_expr->getOperand(0), name, type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (llvm::ConstantInt *init_int = dyn_cast<llvm::ConstantInt>(initializer))
|
||||
{
|
||||
m_const_result = m_decl_map->BuildIntegerVariable(name, type, init_int->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IRForTarget::MaybeSetCastResult (lldb_private::TypeFromParser type)
|
||||
{
|
||||
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
||||
if (!m_result_store)
|
||||
return;
|
||||
|
||||
LoadInst *original_load = NULL;
|
||||
|
||||
for (llvm::Value *current_value = m_result_store->getValueOperand(), *next_value;
|
||||
current_value != NULL;
|
||||
current_value = next_value)
|
||||
{
|
||||
CastInst *cast_inst = dyn_cast<CastInst>(current_value);
|
||||
LoadInst *load_inst = dyn_cast<LoadInst>(current_value);
|
||||
|
||||
if (cast_inst)
|
||||
{
|
||||
next_value = cast_inst->getOperand(0);
|
||||
}
|
||||
else if (load_inst)
|
||||
{
|
||||
if (isa<LoadInst>(load_inst->getPointerOperand()))
|
||||
{
|
||||
next_value = load_inst->getPointerOperand();
|
||||
}
|
||||
else
|
||||
{
|
||||
original_load = load_inst;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!original_load)
|
||||
return;
|
||||
|
||||
Value *loaded_value = original_load->getPointerOperand();
|
||||
GlobalVariable *loaded_global = dyn_cast<GlobalVariable>(loaded_value);
|
||||
|
||||
if (!loaded_global)
|
||||
return;
|
||||
|
||||
clang::NamedDecl *loaded_decl = DeclForGlobal(loaded_global);
|
||||
|
||||
if (!loaded_decl)
|
||||
return;
|
||||
|
||||
clang::VarDecl *loaded_var = dyn_cast<clang::VarDecl>(loaded_decl);
|
||||
|
||||
if (!loaded_var)
|
||||
return;
|
||||
|
||||
if (log)
|
||||
{
|
||||
lldb_private::StreamString type_desc_stream;
|
||||
type.DumpTypeDescription(&type_desc_stream);
|
||||
|
||||
log->Printf("Type to cast variable to: \"%s\"", type_desc_stream.GetString().c_str());
|
||||
}
|
||||
|
||||
m_const_result = m_decl_map->BuildCastVariable(m_result_name, loaded_var, type);
|
||||
}
|
||||
|
||||
bool
|
||||
IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
|
||||
{
|
||||
|
@ -714,7 +619,7 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
|
|||
log->Printf("Result decl type: \"%s\"", type_desc_stream.GetData());
|
||||
}
|
||||
|
||||
m_result_name = m_decl_map->GetPersistentResultName();
|
||||
m_result_name = lldb_private::ConstString("$RESULT_NAME");
|
||||
|
||||
if (log)
|
||||
log->Printf("Creating a new result global: \"%s\" with size 0x%" PRIx64,
|
||||
|
@ -806,15 +711,14 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
|
|||
|
||||
result_global->replaceAllUsesWith(new_result_global);
|
||||
}
|
||||
|
||||
if (!m_const_result)
|
||||
if (!m_decl_map->AddPersistentVariable(result_decl,
|
||||
m_result_name,
|
||||
m_result_type,
|
||||
true,
|
||||
m_result_is_pointer))
|
||||
return false;
|
||||
|
||||
if (!m_decl_map->AddPersistentVariable(result_decl,
|
||||
m_result_name,
|
||||
m_result_type,
|
||||
true,
|
||||
m_result_is_pointer))
|
||||
return false;
|
||||
|
||||
result_global->eraseFromParent();
|
||||
|
||||
return true;
|
||||
|
@ -2138,10 +2042,11 @@ IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block)
|
|||
llvm::Instruction *inst = *user_iter;
|
||||
|
||||
ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val);
|
||||
Type *operand_type = operand_constant_fp->getType();
|
||||
|
||||
if (operand_constant_fp)
|
||||
{
|
||||
Type *operand_type = operand_constant_fp->getType();
|
||||
|
||||
APFloat operand_apfloat = operand_constant_fp->getValueAPF();
|
||||
APInt operand_apint = operand_apfloat.bitcastToAPInt();
|
||||
|
||||
|
@ -2195,7 +2100,7 @@ IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block)
|
|||
|
||||
llvm::Type *fp_ptr_ty = operand_constant_fp->getType()->getPointerTo();
|
||||
|
||||
Constant *new_pointer = BuildRelocation(fp_ptr_ty, offset);
|
||||
Constant *new_pointer = BuildRelocation(fp_ptr_ty, aligned_offset);
|
||||
|
||||
llvm::LoadInst *fp_load = new llvm::LoadInst(new_pointer, "fp_load", inst);
|
||||
|
||||
|
@ -2762,12 +2667,6 @@ IRForTarget::runOnModule (Module &llvm_module)
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_const_result && m_execution_policy != lldb_private::eExecutionPolicyAlways)
|
||||
{
|
||||
m_interpret_success = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (bbi = function->begin();
|
||||
bbi != function->end();
|
||||
|
@ -2804,20 +2703,6 @@ IRForTarget::runOnModule (Module &llvm_module)
|
|||
}
|
||||
}
|
||||
|
||||
if (m_decl_map && m_execution_policy != lldb_private::eExecutionPolicyAlways)
|
||||
{
|
||||
IRInterpreter::maybeRunOnFunction(m_decl_map, m_memory_map, m_error_stream,m_const_result, m_result_name, m_result_type, *function, llvm_module, m_interpreter_error);
|
||||
|
||||
if (m_interpreter_error.Success())
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_execution_policy == lldb_private::eExecutionPolicyNever) {
|
||||
if (m_result_name)
|
||||
m_decl_map->RemoveResultVariable(m_result_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (log && log->GetVerbose())
|
||||
{
|
||||
std::string s;
|
||||
|
|
|
@ -89,6 +89,10 @@ public:
|
|||
BasicBlock::const_iterator m_ii;
|
||||
BasicBlock::const_iterator m_ie;
|
||||
|
||||
lldb::addr_t m_frame_process_address;
|
||||
size_t m_frame_size;
|
||||
lldb::addr_t m_stack_pointer;
|
||||
|
||||
lldb::ByteOrder m_byte_order;
|
||||
size_t m_addr_byte_size;
|
||||
|
||||
|
@ -101,6 +105,36 @@ public:
|
|||
{
|
||||
m_byte_order = (target_data.isLittleEndian() ? lldb::eByteOrderLittle : lldb::eByteOrderBig);
|
||||
m_addr_byte_size = (target_data.getPointerSize(0));
|
||||
|
||||
m_frame_size = 512 * 1024;
|
||||
|
||||
lldb_private::Error alloc_error;
|
||||
|
||||
m_frame_process_address = memory_map.Malloc(m_frame_size,
|
||||
m_addr_byte_size,
|
||||
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
|
||||
lldb_private::IRMemoryMap::eAllocationPolicyMirror,
|
||||
alloc_error);
|
||||
|
||||
if (alloc_error.Success())
|
||||
{
|
||||
m_stack_pointer = m_frame_process_address + m_frame_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_frame_process_address = LLDB_INVALID_ADDRESS;
|
||||
m_stack_pointer = LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
~InterpreterStackFrame ()
|
||||
{
|
||||
if (m_frame_process_address != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
lldb_private::Error free_error;
|
||||
m_memory_map.Free(m_frame_process_address, free_error);
|
||||
m_frame_process_address = LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
void Jump (const BasicBlock *bb)
|
||||
|
@ -216,57 +250,106 @@ public:
|
|||
|
||||
bool ResolveConstantValue (APInt &value, const Constant *constant)
|
||||
{
|
||||
if (const ConstantInt *constant_int = dyn_cast<ConstantInt>(constant))
|
||||
switch (constant->getValueID())
|
||||
{
|
||||
value = constant_int->getValue();
|
||||
return true;
|
||||
}
|
||||
else if (const ConstantFP *constant_fp = dyn_cast<ConstantFP>(constant))
|
||||
{
|
||||
value = constant_fp->getValueAPF().bitcastToAPInt();
|
||||
return true;
|
||||
}
|
||||
else if (const ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(constant))
|
||||
{
|
||||
switch (constant_expr->getOpcode())
|
||||
default:
|
||||
break;
|
||||
case Value::ConstantIntVal:
|
||||
if (const ConstantInt *constant_int = dyn_cast<ConstantInt>(constant))
|
||||
{
|
||||
default:
|
||||
return false;
|
||||
case Instruction::IntToPtr:
|
||||
case Instruction::PtrToInt:
|
||||
case Instruction::BitCast:
|
||||
return ResolveConstantValue(value, constant_expr->getOperand(0));
|
||||
case Instruction::GetElementPtr:
|
||||
value = constant_int->getValue();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Value::ConstantFPVal:
|
||||
if (const ConstantFP *constant_fp = dyn_cast<ConstantFP>(constant))
|
||||
{
|
||||
value = constant_fp->getValueAPF().bitcastToAPInt();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Value::ConstantExprVal:
|
||||
if (const ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(constant))
|
||||
{
|
||||
switch (constant_expr->getOpcode())
|
||||
{
|
||||
ConstantExpr::const_op_iterator op_cursor = constant_expr->op_begin();
|
||||
ConstantExpr::const_op_iterator op_end = constant_expr->op_end();
|
||||
|
||||
Constant *base = dyn_cast<Constant>(*op_cursor);
|
||||
|
||||
if (!base)
|
||||
default:
|
||||
return false;
|
||||
|
||||
if (!ResolveConstantValue(value, base))
|
||||
return false;
|
||||
|
||||
op_cursor++;
|
||||
|
||||
if (op_cursor == op_end)
|
||||
return true; // no offset to apply!
|
||||
|
||||
SmallVector <Value *, 8> indices (op_cursor, op_end);
|
||||
|
||||
uint64_t offset = m_target_data.getIndexedOffset(base->getType(), indices);
|
||||
|
||||
const bool is_signed = true;
|
||||
value += APInt(value.getBitWidth(), offset, is_signed);
|
||||
|
||||
return true;
|
||||
case Instruction::IntToPtr:
|
||||
case Instruction::PtrToInt:
|
||||
case Instruction::BitCast:
|
||||
return ResolveConstantValue(value, constant_expr->getOperand(0));
|
||||
case Instruction::GetElementPtr:
|
||||
{
|
||||
ConstantExpr::const_op_iterator op_cursor = constant_expr->op_begin();
|
||||
ConstantExpr::const_op_iterator op_end = constant_expr->op_end();
|
||||
|
||||
Constant *base = dyn_cast<Constant>(*op_cursor);
|
||||
|
||||
if (!base)
|
||||
return false;
|
||||
|
||||
if (!ResolveConstantValue(value, base))
|
||||
return false;
|
||||
|
||||
op_cursor++;
|
||||
|
||||
if (op_cursor == op_end)
|
||||
return true; // no offset to apply!
|
||||
|
||||
SmallVector <Value *, 8> indices (op_cursor, op_end);
|
||||
|
||||
uint64_t offset = m_target_data.getIndexedOffset(base->getType(), indices);
|
||||
|
||||
const bool is_signed = true;
|
||||
value += APInt(value.getBitWidth(), offset, is_signed);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Value::ConstantPointerNullVal:
|
||||
if (isa<ConstantPointerNull>(constant))
|
||||
{
|
||||
value = APInt(m_target_data.getPointerSizeInBits(), 0);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MakeArgument(const Argument *value, uint64_t address)
|
||||
{
|
||||
lldb::addr_t data_address = Malloc(value->getType());
|
||||
|
||||
if (data_address == LLDB_INVALID_ADDRESS)
|
||||
return false;
|
||||
|
||||
lldb_private::Error write_error;
|
||||
|
||||
m_memory_map.WritePointerToMemory(data_address, address, write_error);
|
||||
|
||||
if (!write_error.Success())
|
||||
{
|
||||
lldb_private::Error free_error;
|
||||
m_memory_map.Free(data_address, free_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
m_values[value] = data_address;
|
||||
|
||||
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
||||
if (log)
|
||||
{
|
||||
log->Printf("Made an allocation for argument %s", PrintValue(value).c_str());
|
||||
log->Printf(" Data region : %llx", (unsigned long long)address);
|
||||
log->Printf(" Ref region : %llx", (unsigned long long)data_address);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResolveConstant (lldb::addr_t process_address, const Constant *constant)
|
||||
|
@ -287,31 +370,30 @@ public:
|
|||
return write_error.Success();
|
||||
}
|
||||
|
||||
lldb::addr_t Malloc (size_t size, uint8_t byte_alignment)
|
||||
{
|
||||
lldb::addr_t ret = m_stack_pointer;
|
||||
|
||||
ret -= size;
|
||||
ret -= (ret % byte_alignment);
|
||||
|
||||
if (ret < m_frame_process_address)
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
||||
m_stack_pointer = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
lldb::addr_t MallocPointer ()
|
||||
{
|
||||
lldb_private::Error alloc_error;
|
||||
|
||||
lldb::addr_t ret = m_memory_map.Malloc(m_target_data.getPointerSize(), m_target_data.getPointerPrefAlignment(), lldb::ePermissionsReadable | lldb::ePermissionsWritable, lldb_private::IRMemoryMap::eAllocationPolicyMirror, alloc_error);
|
||||
|
||||
if (alloc_error.Success())
|
||||
return ret;
|
||||
else
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
return Malloc(m_target_data.getPointerSize(), m_target_data.getPointerPrefAlignment());
|
||||
}
|
||||
|
||||
lldb::addr_t Malloc (llvm::Type *type, size_t override_byte_size = 0)
|
||||
lldb::addr_t Malloc (llvm::Type *type)
|
||||
{
|
||||
lldb_private::Error alloc_error;
|
||||
|
||||
if (!override_byte_size)
|
||||
override_byte_size = m_target_data.getTypeStoreSize(type);
|
||||
|
||||
lldb::addr_t ret = m_memory_map.Malloc(override_byte_size, m_target_data.getPrefTypeAlignment(type), lldb::ePermissionsReadable | lldb::ePermissionsWritable, lldb_private::IRMemoryMap::eAllocationPolicyMirror, alloc_error);
|
||||
|
||||
if (alloc_error.Success())
|
||||
return ret;
|
||||
else
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
return Malloc(m_target_data.getTypeAllocSize(type), m_target_data.getPrefTypeAlignment(type));
|
||||
}
|
||||
|
||||
lldb::addr_t PlaceLLDBValue (const llvm::Value *value, lldb_private::Value lldb_value)
|
||||
|
@ -325,6 +407,7 @@ public:
|
|||
lldb::addr_t ret;
|
||||
|
||||
size_t value_size = m_target_data.getTypeStoreSize(value->getType());
|
||||
size_t value_align = m_target_data.getPrefTypeAlignment(value->getType());
|
||||
|
||||
if (reg_info && (reg_info->encoding == lldb::eEncodingVector))
|
||||
value_size = reg_info->byte_size;
|
||||
|
@ -332,7 +415,7 @@ public:
|
|||
if (!reg_info && (lldb_value.GetValueType() == lldb_private::Value::eValueTypeLoadAddress))
|
||||
return lldb_value.GetScalar().ULongLong();
|
||||
|
||||
ret = Malloc(value->getType(), value_size);
|
||||
ret = Malloc(value_size, value_align);
|
||||
|
||||
if (ret == LLDB_INVALID_ADDRESS)
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
@ -403,14 +486,28 @@ public:
|
|||
|
||||
lldb::addr_t ResolveValue (const Value *value, Module &module)
|
||||
{
|
||||
if (!m_decl_map)
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
||||
ValueMap::iterator i = m_values.find(value);
|
||||
|
||||
if (i != m_values.end())
|
||||
return i->second;
|
||||
|
||||
// Fall back and allocate space [allocation type Alloca]
|
||||
|
||||
lldb::addr_t data_address = Malloc(value->getType());
|
||||
|
||||
if (const Constant *constant = dyn_cast<Constant>(value))
|
||||
{
|
||||
if (!ResolveConstant (data_address, constant))
|
||||
{
|
||||
lldb_private::Error free_error;
|
||||
m_memory_map.Free(data_address, free_error);
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
m_values[value] = data_address;
|
||||
return data_address;
|
||||
|
||||
const GlobalValue *global_value = dyn_cast<GlobalValue>(value);
|
||||
|
||||
// If the variable is indirected through the argument
|
||||
|
@ -686,23 +783,6 @@ public:
|
|||
}
|
||||
}
|
||||
while(0);
|
||||
|
||||
// Fall back and allocate space [allocation type Alloca]
|
||||
|
||||
lldb::addr_t data_address = Malloc(value->getType());
|
||||
|
||||
if (const Constant *constant = dyn_cast<Constant>(value))
|
||||
{
|
||||
if (!ResolveConstant (data_address, constant))
|
||||
{
|
||||
lldb_private::Error free_error;
|
||||
m_memory_map.Free(data_address, free_error);
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
m_values[value] = data_address;
|
||||
return data_address;
|
||||
}
|
||||
|
||||
bool ConstructResult (lldb::ClangExpressionVariableSP &result,
|
||||
|
@ -1698,15 +1778,50 @@ IRInterpreter::CanInterpret (llvm::Module &module,
|
|||
bool
|
||||
IRInterpreter::Interpret (llvm::Module &module,
|
||||
llvm::Function &function,
|
||||
llvm::ArrayRef<lldb::addr_t> args,
|
||||
lldb_private::IRMemoryMap &memory_map,
|
||||
lldb_private::Error &error)
|
||||
{
|
||||
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
||||
if (log)
|
||||
{
|
||||
std::string s;
|
||||
raw_string_ostream oss(s);
|
||||
|
||||
module.print(oss, NULL);
|
||||
|
||||
oss.flush();
|
||||
|
||||
log->Printf("Module as passed in to IRInterpreter::Interpret: \n\"%s\"", s.c_str());
|
||||
}
|
||||
|
||||
DataLayout data_layout(&module);
|
||||
|
||||
InterpreterStackFrame frame(data_layout, NULL, memory_map);
|
||||
|
||||
if (frame.m_frame_process_address == LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
error.SetErrorString("Couldn't allocate stack frame");
|
||||
}
|
||||
|
||||
int arg_index = 0;
|
||||
|
||||
for (llvm::Function::arg_iterator ai = function.arg_begin(), ae = function.arg_end();
|
||||
ai != ae;
|
||||
++ai, ++arg_index)
|
||||
{
|
||||
if (args.size() < arg_index)
|
||||
{
|
||||
error.SetErrorString ("Not enough arguments passed in to function");
|
||||
return false;
|
||||
}
|
||||
|
||||
lldb::addr_t ptr = args[arg_index];
|
||||
|
||||
frame.MakeArgument(ai, ptr);
|
||||
}
|
||||
|
||||
uint32_t num_insts = 0;
|
||||
|
||||
frame.Jump(function.begin());
|
||||
|
|
|
@ -85,6 +85,9 @@ IRMemoryMap::ContainsHostOnlyAllocations ()
|
|||
IRMemoryMap::AllocationMap::iterator
|
||||
IRMemoryMap::FindAllocation (lldb::addr_t addr, size_t size)
|
||||
{
|
||||
if (addr == LLDB_INVALID_ADDRESS)
|
||||
return m_allocations.end();
|
||||
|
||||
AllocationMap::iterator iter = m_allocations.lower_bound (addr);
|
||||
|
||||
if (iter == m_allocations.end() ||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "lldb/Target/ExecutionContext.h"
|
||||
#include "lldb/Target/RegisterContext.h"
|
||||
#include "lldb/Target/StackFrame.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
|
||||
using namespace lldb_private;
|
||||
|
||||
|
@ -179,11 +180,8 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
// This is the result variable
|
||||
/*
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorStringWithFormat("No materialization happened for persistent variable %s", m_persistent_variable_sp->GetName().AsCString());
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -280,6 +278,7 @@ public:
|
|||
|
||||
if (!read_error.Success())
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorStringWithFormat ("Couldn't read the contents of %s from memory: %s", m_persistent_variable_sp->GetName().GetCString(), read_error.AsCString());
|
||||
return;
|
||||
}
|
||||
|
@ -468,7 +467,7 @@ public:
|
|||
DataExtractor data;
|
||||
valobj_sp->GetData(data);
|
||||
|
||||
if (m_temporary_allocation == LLDB_INVALID_ADDRESS)
|
||||
if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorStringWithFormat("Trying to create a temporary region for %s but one exists", m_variable_sp->GetName().AsCString());
|
||||
|
@ -580,7 +579,7 @@ public:
|
|||
if (!free_error.Success())
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorStringWithFormat("Couldn'tfree the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), free_error.AsCString());
|
||||
err.SetErrorStringWithFormat("Couldn't free the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), free_error.AsCString());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -593,9 +592,11 @@ public:
|
|||
{
|
||||
StreamString dump_stream;
|
||||
|
||||
Error err;
|
||||
dump_stream.Printf("0x%llx: EntityVariable\n", (unsigned long long)process_address + m_offset);
|
||||
|
||||
dump_stream.Printf("0x%llx: EntityVariable (%s)\n", (unsigned long long)process_address + m_offset, m_variable_sp->GetName().AsCString());
|
||||
Error err;
|
||||
|
||||
lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
|
||||
|
||||
{
|
||||
dump_stream.Printf("Pointer:\n");
|
||||
|
@ -614,18 +615,29 @@ public:
|
|||
|
||||
extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, process_address + m_offset);
|
||||
|
||||
lldb::offset_t offset;
|
||||
|
||||
ptr = extractor.GetPointer(&offset);
|
||||
|
||||
dump_stream.PutChar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
if (m_temporary_allocation == LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
dump_stream.Printf("Points to process memory.\n");
|
||||
dump_stream.Printf("Points to process memory:\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
dump_stream.Printf("Temporary allocation:\n");
|
||||
|
||||
}
|
||||
|
||||
if (ptr == LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
dump_stream.Printf(" <could not be be found>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
DataBufferHeap data (m_temporary_allocation_size, 0);
|
||||
|
||||
map.ReadMemory(data.GetBytes(), m_temporary_allocation, m_temporary_allocation_size, err);
|
||||
|
@ -680,21 +692,157 @@ Materializer::AddVariable (lldb::VariableSP &variable_sp, Error &err)
|
|||
class EntityResultVariable : public Materializer::Entity
|
||||
{
|
||||
public:
|
||||
EntityResultVariable (const ClangASTType &type, bool keep_in_memory) :
|
||||
EntityResultVariable (const TypeFromUser &type, bool is_program_reference, bool keep_in_memory) :
|
||||
Entity(),
|
||||
m_type(type),
|
||||
m_keep_in_memory(keep_in_memory)
|
||||
m_is_program_reference(is_program_reference),
|
||||
m_keep_in_memory(keep_in_memory),
|
||||
m_temporary_allocation(LLDB_INVALID_ADDRESS),
|
||||
m_temporary_allocation_size(0)
|
||||
{
|
||||
SetSizeAndAlignmentFromType(m_type);
|
||||
// Hard-coding to maximum size of a pointer since all results are materialized by reference
|
||||
m_size = 8;
|
||||
m_alignment = 8;
|
||||
}
|
||||
|
||||
void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
|
||||
{
|
||||
if (!m_is_program_reference)
|
||||
{
|
||||
if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Trying to create a temporary region for the result but one exists");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t byte_size = m_type.GetTypeByteSize();
|
||||
size_t bit_align = m_type.GetTypeBitAlign();
|
||||
size_t byte_align = (bit_align + 7) / 8;
|
||||
|
||||
Error alloc_error;
|
||||
|
||||
m_temporary_allocation = map.Malloc(byte_size, byte_align, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, alloc_error);
|
||||
m_temporary_allocation_size = byte_size;
|
||||
|
||||
if (!alloc_error.Success())
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorStringWithFormat("Couldn't allocate a temporary region for the result: %s", alloc_error.AsCString());
|
||||
return;
|
||||
}
|
||||
|
||||
Error pointer_write_error;
|
||||
|
||||
map.WritePointerToMemory(process_address + m_offset, m_temporary_allocation, pointer_write_error);
|
||||
|
||||
if (!pointer_write_error.Success())
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorStringWithFormat("Couldn't write the address of the temporary region for the result: %s", pointer_write_error.AsCString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dematerialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address,
|
||||
lldb::addr_t frame_top, lldb::addr_t frame_bottom, Error &err)
|
||||
lldb::addr_t frame_top, lldb::addr_t frame_bottom, Error &err)
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Tried to detmaterialize a result variable with the normal Dematerialize method");
|
||||
}
|
||||
|
||||
void Dematerialize (lldb::ClangExpressionVariableSP &result_variable_sp,
|
||||
lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address,
|
||||
lldb::addr_t frame_top, lldb::addr_t frame_bottom, Error &err)
|
||||
{
|
||||
err.Clear();
|
||||
|
||||
ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
|
||||
|
||||
if (!exe_scope)
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Couldn't dematerialize a result variable: invalid execution context scope");
|
||||
return;
|
||||
}
|
||||
|
||||
lldb::addr_t address;
|
||||
Error read_error;
|
||||
|
||||
map.ReadPointerFromMemory (&address, process_address + m_offset, read_error);
|
||||
|
||||
if (!read_error.Success())
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Couldn't dematerialize a result variable: couldn't read its address");
|
||||
return;
|
||||
}
|
||||
|
||||
lldb::TargetSP target_sp = exe_scope->CalculateTarget();
|
||||
|
||||
if (!target_sp)
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Couldn't dematerialize a result variable: no target");
|
||||
return;
|
||||
}
|
||||
|
||||
ConstString name = target_sp->GetPersistentVariables().GetNextPersistentVariableName();
|
||||
|
||||
lldb::ClangExpressionVariableSP ret;
|
||||
|
||||
ret = target_sp->GetPersistentVariables().CreateVariable(exe_scope,
|
||||
name,
|
||||
m_type,
|
||||
map.GetByteOrder(),
|
||||
map.GetAddressByteSize());
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: failed to make persistent variable %s", name.AsCString());
|
||||
return;
|
||||
}
|
||||
|
||||
ret->m_live_sp = ValueObjectConstResult::Create(exe_scope,
|
||||
m_type.GetASTContext(),
|
||||
m_type.GetOpaqueQualType(),
|
||||
name,
|
||||
address,
|
||||
eAddressTypeLoad,
|
||||
ret->GetByteSize());
|
||||
|
||||
ret->ValueUpdated();
|
||||
|
||||
const size_t pvar_byte_size = ret->GetByteSize();
|
||||
uint8_t *pvar_data = ret->GetValueBytes();
|
||||
|
||||
map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
|
||||
|
||||
if (!read_error.Success())
|
||||
{
|
||||
err.SetErrorToGenericError();
|
||||
err.SetErrorString("Couldn't dematerialize a result variable: couldn't read its memory");
|
||||
return;
|
||||
}
|
||||
|
||||
result_variable_sp = ret;
|
||||
|
||||
if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
ret->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
|
||||
|
||||
Error free_error;
|
||||
|
||||
map.Free(m_temporary_allocation, free_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
|
||||
}
|
||||
|
||||
m_temporary_allocation = LLDB_INVALID_ADDRESS;
|
||||
m_temporary_allocation_size = 0;
|
||||
}
|
||||
|
||||
void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
|
||||
|
@ -703,24 +851,100 @@ public:
|
|||
|
||||
dump_stream.Printf("0x%llx: EntityResultVariable\n", (unsigned long long)process_address + m_offset);
|
||||
|
||||
Error err;
|
||||
|
||||
lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
|
||||
|
||||
{
|
||||
dump_stream.Printf("Pointer:\n");
|
||||
|
||||
DataBufferHeap data (m_size, 0);
|
||||
|
||||
map.ReadMemory(data.GetBytes(), process_address + m_offset, m_size, err);
|
||||
|
||||
if (!err.Success())
|
||||
{
|
||||
dump_stream.Printf(" <could not be read>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
|
||||
|
||||
extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, process_address + m_offset);
|
||||
|
||||
lldb::offset_t offset;
|
||||
|
||||
ptr = extractor.GetPointer(&offset);
|
||||
|
||||
dump_stream.PutChar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
if (m_temporary_allocation == LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
dump_stream.Printf("Points to process memory:\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
dump_stream.Printf("Temporary allocation:\n");
|
||||
}
|
||||
|
||||
if (ptr == LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
dump_stream.Printf(" <could not be be found>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
DataBufferHeap data (m_temporary_allocation_size, 0);
|
||||
|
||||
map.ReadMemory(data.GetBytes(), m_temporary_allocation, m_temporary_allocation_size, err);
|
||||
|
||||
if (!err.Success())
|
||||
{
|
||||
dump_stream.Printf(" <could not be read>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
|
||||
|
||||
extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, process_address + m_offset);
|
||||
|
||||
dump_stream.PutChar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
log->PutCString(dump_stream.GetData());
|
||||
}
|
||||
|
||||
void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
|
||||
{
|
||||
if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
Error free_error;
|
||||
|
||||
map.Free(m_temporary_allocation, free_error);
|
||||
}
|
||||
|
||||
m_temporary_allocation = LLDB_INVALID_ADDRESS;
|
||||
m_temporary_allocation_size = 0;
|
||||
}
|
||||
private:
|
||||
ClangASTType m_type;
|
||||
TypeFromUser m_type;
|
||||
bool m_is_program_reference;
|
||||
bool m_keep_in_memory;
|
||||
|
||||
lldb::addr_t m_temporary_allocation;
|
||||
size_t m_temporary_allocation_size;
|
||||
};
|
||||
|
||||
uint32_t
|
||||
Materializer::AddResultVariable (const ClangASTType &type, bool keep_in_memory, Error &err)
|
||||
Materializer::AddResultVariable (const TypeFromUser &type, bool is_program_reference, bool keep_in_memory, Error &err)
|
||||
{
|
||||
EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
|
||||
iter->reset (new EntityResultVariable (type, keep_in_memory));
|
||||
iter->reset (new EntityResultVariable (type, is_program_reference, keep_in_memory));
|
||||
uint32_t ret = AddStructMember(**iter);
|
||||
(*iter)->SetOffset(ret);
|
||||
m_result_entity = iter->get();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1008,6 +1232,7 @@ Materializer::AddRegister (const RegisterInfo ®ister_info, Error &err)
|
|||
|
||||
Materializer::Materializer () :
|
||||
m_dematerializer_wp(),
|
||||
m_result_entity(NULL),
|
||||
m_current_offset(0),
|
||||
m_struct_alignment(8)
|
||||
{
|
||||
|
@ -1022,7 +1247,7 @@ Materializer::~Materializer ()
|
|||
}
|
||||
|
||||
Materializer::DematerializerSP
|
||||
Materializer::Materialize (lldb::StackFrameSP &frame_sp, lldb::ClangExpressionVariableSP &result_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &error)
|
||||
Materializer::Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &error)
|
||||
{
|
||||
ExecutionContextScope *exe_scope = frame_sp.get();
|
||||
|
||||
|
@ -1066,7 +1291,7 @@ Materializer::Materialize (lldb::StackFrameSP &frame_sp, lldb::ClangExpressionVa
|
|||
}
|
||||
|
||||
void
|
||||
Materializer::Dematerializer::Dematerialize (Error &error, lldb::addr_t frame_top, lldb::addr_t frame_bottom)
|
||||
Materializer::Dematerializer::Dematerialize (Error &error, lldb::ClangExpressionVariableSP &result_sp, lldb::addr_t frame_top, lldb::addr_t frame_bottom)
|
||||
{
|
||||
lldb::StackFrameSP frame_sp = m_frame_wp.lock();
|
||||
|
||||
|
@ -1094,8 +1319,15 @@ Materializer::Dematerializer::Dematerialize (Error &error, lldb::addr_t frame_to
|
|||
|
||||
for (EntityUP &entity_up : m_materializer->m_entities)
|
||||
{
|
||||
entity_up->Dematerialize (frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error);
|
||||
|
||||
if (entity_up.get() == m_materializer->m_result_entity)
|
||||
{
|
||||
static_cast<EntityResultVariable*>(m_materializer->m_result_entity)->Dematerialize (result_sp, frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
entity_up->Dematerialize (frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error);
|
||||
}
|
||||
|
||||
if (!error.Success())
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue