mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-20 12:05:48 -04:00

In templated const functions, trying to run an expression would produce the error error: out-of-line definition of '$__lldb_expr' does not match any declaration in 'foo' member declaration does not match because it is const qualified error: 1 error parsing expression which is no good. It turned out we don't actually need to worry about "const," we just need to be consistent about the declaration of the expression and the FunctionDecl we inject into the class for "this." Also added a test case. <rdar://problem/24985958> llvm-svn: 267833
382 lines
15 KiB
C++
382 lines
15 KiB
C++
//===-- LLVMUserExpression.cpp ----------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
|
|
// Project includes
|
|
#include "lldb/Expression/LLVMUserExpression.h"
|
|
#include "lldb/Core/ConstString.h"
|
|
#include "lldb/Core/Log.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/StreamFile.h"
|
|
#include "lldb/Core/StreamString.h"
|
|
#include "lldb/Core/ValueObjectConstResult.h"
|
|
#include "lldb/Expression/DiagnosticManager.h"
|
|
#include "lldb/Expression/ExpressionSourceCode.h"
|
|
#include "lldb/Expression/IRExecutionUnit.h"
|
|
#include "lldb/Expression/IRInterpreter.h"
|
|
#include "lldb/Expression/Materializer.h"
|
|
#include "lldb/Host/HostInfo.h"
|
|
#include "lldb/Symbol/Block.h"
|
|
#include "lldb/Symbol/ClangASTContext.h"
|
|
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
|
|
#include "lldb/Symbol/Function.h"
|
|
#include "lldb/Symbol/ObjectFile.h"
|
|
#include "lldb/Symbol/SymbolVendor.h"
|
|
#include "lldb/Symbol/Type.h"
|
|
#include "lldb/Symbol/VariableList.h"
|
|
#include "lldb/Target/ExecutionContext.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Target/StackFrame.h"
|
|
#include "lldb/Target/Target.h"
|
|
#include "lldb/Target/ThreadPlan.h"
|
|
#include "lldb/Target/ThreadPlanCallUserExpression.h"
|
|
|
|
using namespace lldb_private;
|
|
|
|
LLVMUserExpression::LLVMUserExpression(ExecutionContextScope &exe_scope,
|
|
const char *expr,
|
|
const char *expr_prefix,
|
|
lldb::LanguageType language,
|
|
ResultType desired_type,
|
|
const EvaluateExpressionOptions &options)
|
|
: UserExpression(exe_scope, expr, expr_prefix, language, desired_type, options),
|
|
m_stack_frame_bottom(LLDB_INVALID_ADDRESS),
|
|
m_stack_frame_top(LLDB_INVALID_ADDRESS),
|
|
m_transformed_text(),
|
|
m_execution_unit_sp(),
|
|
m_materializer_ap(),
|
|
m_jit_module_wp(),
|
|
m_enforce_valid_object(true),
|
|
m_in_cplusplus_method(false),
|
|
m_in_objectivec_method(false),
|
|
m_in_static_method(false),
|
|
m_needs_object_ptr(false),
|
|
m_target(NULL),
|
|
m_can_interpret(false),
|
|
m_materialized_address(LLDB_INVALID_ADDRESS)
|
|
{
|
|
}
|
|
|
|
LLVMUserExpression::~LLVMUserExpression()
|
|
{
|
|
if (m_target)
|
|
{
|
|
lldb::ModuleSP jit_module_sp(m_jit_module_wp.lock());
|
|
if (jit_module_sp)
|
|
m_target->GetImages().Remove(jit_module_sp);
|
|
}
|
|
}
|
|
|
|
lldb::ExpressionResults
|
|
LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
|
|
const EvaluateExpressionOptions &options, lldb::UserExpressionSP &shared_ptr_to_me,
|
|
lldb::ExpressionVariableSP &result)
|
|
{
|
|
// The expression log is quite verbose, and if you're just tracking the execution of the
|
|
// 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 || m_can_interpret)
|
|
{
|
|
lldb::addr_t struct_address = LLDB_INVALID_ADDRESS;
|
|
|
|
if (!PrepareToExecuteJITExpression(diagnostic_manager, exe_ctx, struct_address))
|
|
{
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError,
|
|
"errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__);
|
|
return lldb::eExpressionSetupError;
|
|
}
|
|
|
|
lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS;
|
|
lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS;
|
|
|
|
if (m_can_interpret)
|
|
{
|
|
llvm::Module *module = m_execution_unit_sp->GetModule();
|
|
llvm::Function *function = m_execution_unit_sp->GetFunction();
|
|
|
|
if (!module || !function)
|
|
{
|
|
diagnostic_manager.PutCString(eDiagnosticSeverityError, "supposed to interpret, but nothing is there");
|
|
return lldb::eExpressionSetupError;
|
|
}
|
|
|
|
Error interpreter_error;
|
|
|
|
std::vector<lldb::addr_t> args;
|
|
|
|
if (!AddArguments(exe_ctx, args, struct_address, diagnostic_manager))
|
|
{
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError, "errored out in %s, couldn't AddArguments",
|
|
__FUNCTION__);
|
|
return lldb::eExpressionSetupError;
|
|
}
|
|
|
|
function_stack_bottom = m_stack_frame_bottom;
|
|
function_stack_top = m_stack_frame_top;
|
|
|
|
IRInterpreter::Interpret(*module, *function, args, *m_execution_unit_sp.get(), interpreter_error,
|
|
function_stack_bottom, function_stack_top, exe_ctx);
|
|
|
|
if (!interpreter_error.Success())
|
|
{
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError, "supposed to interpret, but failed: %s",
|
|
interpreter_error.AsCString());
|
|
return lldb::eExpressionDiscarded;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!exe_ctx.HasThreadScope())
|
|
{
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError, "%s called with no thread selected", __FUNCTION__);
|
|
return lldb::eExpressionSetupError;
|
|
}
|
|
|
|
Address wrapper_address(m_jit_start_addr);
|
|
|
|
std::vector<lldb::addr_t> args;
|
|
|
|
if (!AddArguments(exe_ctx, args, struct_address, diagnostic_manager))
|
|
{
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError, "errored out in %s, couldn't AddArguments",
|
|
__FUNCTION__);
|
|
return lldb::eExpressionSetupError;
|
|
}
|
|
|
|
lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression(exe_ctx.GetThreadRef(), wrapper_address,
|
|
args, options, shared_ptr_to_me));
|
|
|
|
StreamString ss;
|
|
if (!call_plan_sp || !call_plan_sp->ValidatePlan(&ss))
|
|
{
|
|
diagnostic_manager.PutCString(eDiagnosticSeverityError, ss.GetData());
|
|
return lldb::eExpressionSetupError;
|
|
}
|
|
|
|
ThreadPlanCallUserExpression *user_expression_plan =
|
|
static_cast<ThreadPlanCallUserExpression *>(call_plan_sp.get());
|
|
|
|
lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer();
|
|
|
|
function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize();
|
|
function_stack_top = function_stack_pointer;
|
|
|
|
if (log)
|
|
log->Printf("-- [UserExpression::Execute] Execution of expression begins --");
|
|
|
|
if (exe_ctx.GetProcessPtr())
|
|
exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
|
|
|
|
lldb::ExpressionResults execution_result =
|
|
exe_ctx.GetProcessRef().RunThreadPlan(exe_ctx, call_plan_sp, options, diagnostic_manager);
|
|
|
|
if (exe_ctx.GetProcessPtr())
|
|
exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
|
|
|
|
if (log)
|
|
log->Printf("-- [UserExpression::Execute] Execution of expression completed --");
|
|
|
|
if (execution_result == lldb::eExpressionInterrupted || execution_result == lldb::eExpressionHitBreakpoint)
|
|
{
|
|
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)
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError, "Execution was interrupted, reason: %s.",
|
|
error_desc);
|
|
else
|
|
diagnostic_manager.PutCString(eDiagnosticSeverityError, "Execution was interrupted.");
|
|
|
|
if ((execution_result == lldb::eExpressionInterrupted && options.DoesUnwindOnError()) ||
|
|
(execution_result == lldb::eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints()))
|
|
diagnostic_manager.AppendMessageToDiagnostic(
|
|
"The process has been returned to the state before expression evaluation.");
|
|
else
|
|
{
|
|
if (execution_result == lldb::eExpressionHitBreakpoint)
|
|
user_expression_plan->TransferExpressionOwnership();
|
|
diagnostic_manager.AppendMessageToDiagnostic(
|
|
"The 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 == lldb::eExpressionStoppedForDebug)
|
|
{
|
|
diagnostic_manager.PutCString(
|
|
eDiagnosticSeverityRemark,
|
|
"Execution was halted at the first instruction of the expression "
|
|
"function because \"debug\" was requested.\n"
|
|
"Use \"thread return -x\" to return to the state before expression evaluation.");
|
|
return execution_result;
|
|
}
|
|
else if (execution_result != lldb::eExpressionCompleted)
|
|
{
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError, "Couldn't execute function; result was %s",
|
|
Process::ExecutionResultAsCString(execution_result));
|
|
return execution_result;
|
|
}
|
|
}
|
|
|
|
if (FinalizeJITExecution(diagnostic_manager, exe_ctx, result, function_stack_bottom, function_stack_top))
|
|
{
|
|
return lldb::eExpressionCompleted;
|
|
}
|
|
else
|
|
{
|
|
return lldb::eExpressionResultUnavailable;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
diagnostic_manager.PutCString(eDiagnosticSeverityError,
|
|
"Expression can't be run, because there is no JIT compiled function");
|
|
return lldb::eExpressionSetupError;
|
|
}
|
|
}
|
|
|
|
bool
|
|
LLVMUserExpression::FinalizeJITExecution(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
|
|
lldb::ExpressionVariableSP &result, lldb::addr_t function_stack_bottom,
|
|
lldb::addr_t function_stack_top)
|
|
{
|
|
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
|
|
|
|
if (log)
|
|
log->Printf("-- [UserExpression::FinalizeJITExecution] Dematerializing after execution --");
|
|
|
|
if (!m_dematerializer_sp)
|
|
{
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError,
|
|
"Couldn't apply expression side effects : no dematerializer is present");
|
|
return false;
|
|
}
|
|
|
|
Error dematerialize_error;
|
|
|
|
m_dematerializer_sp->Dematerialize(dematerialize_error, function_stack_bottom, function_stack_top);
|
|
|
|
if (!dematerialize_error.Success())
|
|
{
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError, "Couldn't apply expression side effects : %s",
|
|
dematerialize_error.AsCString("unknown error"));
|
|
return false;
|
|
}
|
|
|
|
result = GetResultAfterDematerialization(exe_ctx.GetBestExecutionContextScope());
|
|
|
|
if (result)
|
|
result->TransferAddress();
|
|
|
|
m_dematerializer_sp.reset();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
LLVMUserExpression::PrepareToExecuteJITExpression(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
|
|
lldb::addr_t &struct_address)
|
|
{
|
|
lldb::TargetSP target;
|
|
lldb::ProcessSP process;
|
|
lldb::StackFrameSP frame;
|
|
|
|
if (!LockAndCheckContext(exe_ctx, target, process, frame))
|
|
{
|
|
diagnostic_manager.PutCString(eDiagnosticSeverityError,
|
|
"The context has changed before we could JIT the expression!");
|
|
return false;
|
|
}
|
|
|
|
if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret)
|
|
{
|
|
if (m_materialized_address == LLDB_INVALID_ADDRESS)
|
|
{
|
|
Error alloc_error;
|
|
|
|
IRMemoryMap::AllocationPolicy policy =
|
|
m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly : IRMemoryMap::eAllocationPolicyMirror;
|
|
|
|
const bool zero_memory = false;
|
|
|
|
m_materialized_address = m_execution_unit_sp->Malloc(m_materializer_ap->GetStructByteSize(),
|
|
m_materializer_ap->GetStructAlignment(),
|
|
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
|
|
policy,
|
|
zero_memory,
|
|
alloc_error);
|
|
|
|
if (!alloc_error.Success())
|
|
{
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError,
|
|
"Couldn't allocate space for materialized struct: %s",
|
|
alloc_error.AsCString());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
struct_address = m_materialized_address;
|
|
|
|
if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS)
|
|
{
|
|
Error alloc_error;
|
|
|
|
const size_t stack_frame_size = 512 * 1024;
|
|
|
|
const bool zero_memory = false;
|
|
|
|
m_stack_frame_bottom = m_execution_unit_sp->Malloc(stack_frame_size,
|
|
8,
|
|
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
|
|
IRMemoryMap::eAllocationPolicyHostOnly,
|
|
zero_memory,
|
|
alloc_error);
|
|
|
|
m_stack_frame_top = m_stack_frame_bottom + stack_frame_size;
|
|
|
|
if (!alloc_error.Success())
|
|
{
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError, "Couldn't allocate space for the stack frame: %s",
|
|
alloc_error.AsCString());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Error materialize_error;
|
|
|
|
m_dematerializer_sp =
|
|
m_materializer_ap->Materialize(frame, *m_execution_unit_sp, struct_address, materialize_error);
|
|
|
|
if (!materialize_error.Success())
|
|
{
|
|
diagnostic_manager.Printf(eDiagnosticSeverityError, "Couldn't materialize: %s",
|
|
materialize_error.AsCString());
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
lldb::ModuleSP
|
|
LLVMUserExpression::GetJITModule()
|
|
{
|
|
if (m_execution_unit_sp)
|
|
return m_execution_unit_sp->GetJITModule();
|
|
return lldb::ModuleSP();
|
|
}
|