1 //===-- LLVMUserExpression.cpp --------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Expression/LLVMUserExpression.h"
10 #include "lldb/Core/Module.h"
11 #include "lldb/Expression/DiagnosticManager.h"
12 #include "lldb/Expression/ExpressionVariable.h"
13 #include "lldb/Expression/IRExecutionUnit.h"
14 #include "lldb/Expression/IRInterpreter.h"
15 #include "lldb/Expression/Materializer.h"
16 #include "lldb/Host/HostInfo.h"
17 #include "lldb/Symbol/Block.h"
18 #include "lldb/Symbol/Function.h"
19 #include "lldb/Symbol/ObjectFile.h"
20 #include "lldb/Symbol/SymbolVendor.h"
21 #include "lldb/Symbol/Type.h"
22 #include "lldb/Symbol/VariableList.h"
23 #include "lldb/Target/ABI.h"
24 #include "lldb/Target/ExecutionContext.h"
25 #include "lldb/Target/Process.h"
26 #include "lldb/Target/StackFrame.h"
27 #include "lldb/Target/Target.h"
28 #include "lldb/Target/ThreadPlan.h"
29 #include "lldb/Target/ThreadPlanCallUserExpression.h"
30 #include "lldb/Utility/ConstString.h"
31 #include "lldb/Utility/ErrorMessages.h"
32 #include "lldb/Utility/LLDBLog.h"
33 #include "lldb/Utility/Log.h"
34 #include "lldb/Utility/StreamString.h"
35 #include "lldb/ValueObject/ValueObjectConstResult.h"
38 using namespace lldb_private
;
40 char LLVMUserExpression::ID
;
42 LLVMUserExpression::LLVMUserExpression(ExecutionContextScope
&exe_scope
,
44 llvm::StringRef prefix
,
45 SourceLanguage language
,
46 ResultType desired_type
,
47 const EvaluateExpressionOptions
&options
)
48 : UserExpression(exe_scope
, expr
, prefix
, language
, desired_type
, options
),
49 m_stack_frame_bottom(LLDB_INVALID_ADDRESS
),
50 m_stack_frame_top(LLDB_INVALID_ADDRESS
), m_allow_cxx(false),
51 m_allow_objc(false), m_transformed_text(), m_execution_unit_sp(),
52 m_materializer_up(), m_jit_module_wp(), m_target(nullptr),
53 m_can_interpret(false), m_materialized_address(LLDB_INVALID_ADDRESS
) {}
55 LLVMUserExpression::~LLVMUserExpression() {
57 lldb::ModuleSP
jit_module_sp(m_jit_module_wp
.lock());
59 m_target
->GetImages().Remove(jit_module_sp
);
63 lldb::ExpressionResults
64 LLVMUserExpression::DoExecute(DiagnosticManager
&diagnostic_manager
,
65 ExecutionContext
&exe_ctx
,
66 const EvaluateExpressionOptions
&options
,
67 lldb::UserExpressionSP
&shared_ptr_to_me
,
68 lldb::ExpressionVariableSP
&result
) {
69 // The expression log is quite verbose, and if you're just tracking the
70 // execution of the expression, it's quite convenient to have these logs come
71 // out with the STEP log as well.
72 Log
*log(GetLog(LLDBLog::Expressions
| LLDBLog::Step
));
74 if (m_jit_start_addr
== LLDB_INVALID_ADDRESS
&& !m_can_interpret
) {
75 diagnostic_manager
.PutString(
77 "Expression can't be run, because there is no JIT compiled function");
78 return lldb::eExpressionSetupError
;
81 lldb::addr_t struct_address
= LLDB_INVALID_ADDRESS
;
83 if (!PrepareToExecuteJITExpression(diagnostic_manager
, exe_ctx
,
85 diagnostic_manager
.Printf(
87 "errored out in %s, couldn't PrepareToExecuteJITExpression",
89 return lldb::eExpressionSetupError
;
92 lldb::addr_t function_stack_bottom
= LLDB_INVALID_ADDRESS
;
93 lldb::addr_t function_stack_top
= LLDB_INVALID_ADDRESS
;
95 if (m_can_interpret
) {
96 llvm::Module
*module
= m_execution_unit_sp
->GetModule();
97 llvm::Function
*function
= m_execution_unit_sp
->GetFunction();
99 if (!module
|| !function
) {
100 diagnostic_manager
.PutString(
101 lldb::eSeverityError
, "supposed to interpret, but nothing is there");
102 return lldb::eExpressionSetupError
;
105 Status interpreter_error
;
107 std::vector
<lldb::addr_t
> args
;
109 if (!AddArguments(exe_ctx
, args
, struct_address
, diagnostic_manager
)) {
110 diagnostic_manager
.Printf(lldb::eSeverityError
,
111 "errored out in %s, couldn't AddArguments",
113 return lldb::eExpressionSetupError
;
116 function_stack_bottom
= m_stack_frame_bottom
;
117 function_stack_top
= m_stack_frame_top
;
119 IRInterpreter::Interpret(*module
, *function
, args
, *m_execution_unit_sp
,
120 interpreter_error
, function_stack_bottom
,
121 function_stack_top
, exe_ctx
, options
.GetTimeout());
123 if (!interpreter_error
.Success()) {
124 diagnostic_manager
.Printf(lldb::eSeverityError
,
125 "supposed to interpret, but failed: %s",
126 interpreter_error
.AsCString());
127 return lldb::eExpressionDiscarded
;
130 if (!exe_ctx
.HasThreadScope()) {
131 diagnostic_manager
.Printf(lldb::eSeverityError
,
132 "%s called with no thread selected",
134 return lldb::eExpressionSetupError
;
137 // Store away the thread ID for error reporting, in case it exits
139 lldb::tid_t expr_thread_id
= exe_ctx
.GetThreadRef().GetID();
141 Address
wrapper_address(m_jit_start_addr
);
143 std::vector
<lldb::addr_t
> args
;
145 if (!AddArguments(exe_ctx
, args
, struct_address
, diagnostic_manager
)) {
146 diagnostic_manager
.Printf(lldb::eSeverityError
,
147 "errored out in %s, couldn't AddArguments",
149 return lldb::eExpressionSetupError
;
152 lldb::ThreadPlanSP
call_plan_sp(new ThreadPlanCallUserExpression(
153 exe_ctx
.GetThreadRef(), wrapper_address
, args
, options
,
157 if (!call_plan_sp
|| !call_plan_sp
->ValidatePlan(&ss
)) {
158 diagnostic_manager
.PutString(lldb::eSeverityError
, ss
.GetString());
159 return lldb::eExpressionSetupError
;
162 ThreadPlanCallUserExpression
*user_expression_plan
=
163 static_cast<ThreadPlanCallUserExpression
*>(call_plan_sp
.get());
165 lldb::addr_t function_stack_pointer
=
166 user_expression_plan
->GetFunctionStackPointer();
168 function_stack_bottom
= function_stack_pointer
- HostInfo::GetPageSize();
169 function_stack_top
= function_stack_pointer
;
172 "-- [UserExpression::Execute] Execution of expression begins --");
174 if (exe_ctx
.GetProcessPtr())
175 exe_ctx
.GetProcessPtr()->SetRunningUserExpression(true);
177 lldb::ExpressionResults execution_result
=
178 exe_ctx
.GetProcessRef().RunThreadPlan(exe_ctx
, call_plan_sp
, options
,
181 if (exe_ctx
.GetProcessPtr())
182 exe_ctx
.GetProcessPtr()->SetRunningUserExpression(false);
184 LLDB_LOGF(log
, "-- [UserExpression::Execute] Execution of expression "
187 if (execution_result
== lldb::eExpressionInterrupted
||
188 execution_result
== lldb::eExpressionHitBreakpoint
) {
189 const char *error_desc
= nullptr;
191 if (user_expression_plan
) {
192 if (auto real_stop_info_sp
= user_expression_plan
->GetRealStopInfo())
193 error_desc
= real_stop_info_sp
->GetDescription();
196 diagnostic_manager
.Printf(lldb::eSeverityError
,
197 "Execution was interrupted, reason: %s.",
200 diagnostic_manager
.PutString(lldb::eSeverityError
,
201 "Execution was interrupted.");
203 if ((execution_result
== lldb::eExpressionInterrupted
&&
204 options
.DoesUnwindOnError()) ||
205 (execution_result
== lldb::eExpressionHitBreakpoint
&&
206 options
.DoesIgnoreBreakpoints()))
207 diagnostic_manager
.AppendMessageToDiagnostic(
208 "The process has been returned to the state before expression "
211 if (execution_result
== lldb::eExpressionHitBreakpoint
)
212 user_expression_plan
->TransferExpressionOwnership();
213 diagnostic_manager
.AppendMessageToDiagnostic(
214 "The process has been left at the point where it was "
216 "use \"thread return -x\" to return to the state before "
217 "expression evaluation.");
220 return execution_result
;
221 } else if (execution_result
== lldb::eExpressionStoppedForDebug
) {
222 diagnostic_manager
.PutString(
224 "Execution was halted at the first instruction of the expression "
225 "function because \"debug\" was requested.\n"
226 "Use \"thread return -x\" to return to the state before expression "
228 return execution_result
;
229 } else if (execution_result
== lldb::eExpressionThreadVanished
) {
230 diagnostic_manager
.Printf(
231 lldb::eSeverityError
,
232 "Couldn't complete execution; the thread "
233 "on which the expression was being run: 0x%" PRIx64
234 " exited during its execution.",
236 return execution_result
;
237 } else if (execution_result
!= lldb::eExpressionCompleted
) {
238 diagnostic_manager
.Printf(lldb::eSeverityError
,
239 "Couldn't execute function; result was %s",
240 toString(execution_result
).c_str());
241 return execution_result
;
245 if (FinalizeJITExecution(diagnostic_manager
, exe_ctx
, result
,
246 function_stack_bottom
, function_stack_top
)) {
247 return lldb::eExpressionCompleted
;
249 return lldb::eExpressionResultUnavailable
;
253 bool LLVMUserExpression::FinalizeJITExecution(
254 DiagnosticManager
&diagnostic_manager
, ExecutionContext
&exe_ctx
,
255 lldb::ExpressionVariableSP
&result
, lldb::addr_t function_stack_bottom
,
256 lldb::addr_t function_stack_top
) {
257 Log
*log
= GetLog(LLDBLog::Expressions
);
259 LLDB_LOGF(log
, "-- [UserExpression::FinalizeJITExecution] Dematerializing "
260 "after execution --");
262 if (!m_dematerializer_sp
) {
263 diagnostic_manager
.Printf(lldb::eSeverityError
,
264 "Couldn't apply expression side effects : no "
265 "dematerializer is present");
269 Status dematerialize_error
;
271 m_dematerializer_sp
->Dematerialize(dematerialize_error
, function_stack_bottom
,
274 if (!dematerialize_error
.Success()) {
275 diagnostic_manager
.Printf(lldb::eSeverityError
,
276 "Couldn't apply expression side effects : %s",
277 dematerialize_error
.AsCString("unknown error"));
282 GetResultAfterDematerialization(exe_ctx
.GetBestExecutionContextScope());
285 result
->TransferAddress();
287 m_dematerializer_sp
.reset();
292 bool LLVMUserExpression::PrepareToExecuteJITExpression(
293 DiagnosticManager
&diagnostic_manager
, ExecutionContext
&exe_ctx
,
294 lldb::addr_t
&struct_address
) {
295 lldb::TargetSP target
;
296 lldb::ProcessSP process
;
297 lldb::StackFrameSP frame
;
299 if (!LockAndCheckContext(exe_ctx
, target
, process
, frame
)) {
300 diagnostic_manager
.PutString(
301 lldb::eSeverityError
,
302 "The context has changed before we could JIT the expression!");
306 if (m_jit_start_addr
!= LLDB_INVALID_ADDRESS
|| m_can_interpret
) {
307 if (m_materialized_address
== LLDB_INVALID_ADDRESS
) {
310 IRMemoryMap::AllocationPolicy policy
=
311 m_can_interpret
? IRMemoryMap::eAllocationPolicyHostOnly
312 : IRMemoryMap::eAllocationPolicyMirror
;
314 const bool zero_memory
= false;
316 m_materialized_address
= m_execution_unit_sp
->Malloc(
317 m_materializer_up
->GetStructByteSize(),
318 m_materializer_up
->GetStructAlignment(),
319 lldb::ePermissionsReadable
| lldb::ePermissionsWritable
, policy
,
320 zero_memory
, alloc_error
);
322 if (!alloc_error
.Success()) {
323 diagnostic_manager
.Printf(
324 lldb::eSeverityError
,
325 "Couldn't allocate space for materialized struct: %s",
326 alloc_error
.AsCString());
331 struct_address
= m_materialized_address
;
333 if (m_can_interpret
&& m_stack_frame_bottom
== LLDB_INVALID_ADDRESS
) {
336 size_t stack_frame_size
= target
->GetExprAllocSize();
337 if (stack_frame_size
== 0) {
339 if (process
&& (abi_sp
= process
->GetABI()))
340 stack_frame_size
= abi_sp
->GetStackFrameSize();
342 stack_frame_size
= 512 * 1024;
345 const bool zero_memory
= false;
347 m_stack_frame_bottom
= m_execution_unit_sp
->Malloc(
349 lldb::ePermissionsReadable
| lldb::ePermissionsWritable
,
350 IRMemoryMap::eAllocationPolicyHostOnly
, zero_memory
, alloc_error
);
352 m_stack_frame_top
= m_stack_frame_bottom
+ stack_frame_size
;
354 if (!alloc_error
.Success()) {
355 diagnostic_manager
.Printf(
356 lldb::eSeverityError
,
357 "Couldn't allocate space for the stack frame: %s",
358 alloc_error
.AsCString());
363 Status materialize_error
;
365 m_dematerializer_sp
= m_materializer_up
->Materialize(
366 frame
, *m_execution_unit_sp
, struct_address
, materialize_error
);
368 if (!materialize_error
.Success()) {
369 diagnostic_manager
.Printf(lldb::eSeverityError
,
370 "Couldn't materialize: %s",
371 materialize_error
.AsCString());