150
|
1 //===-- LLVMUserExpression.cpp --------------------------------------------===//
|
|
2 //
|
|
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
|
|
6 //
|
|
7 //===----------------------------------------------------------------------===//
|
|
8
|
|
9
|
|
10 #include "lldb/Expression/LLVMUserExpression.h"
|
|
11 #include "lldb/Core/Module.h"
|
|
12 #include "lldb/Core/StreamFile.h"
|
|
13 #include "lldb/Core/ValueObjectConstResult.h"
|
|
14 #include "lldb/Expression/DiagnosticManager.h"
|
|
15 #include "lldb/Expression/ExpressionVariable.h"
|
|
16 #include "lldb/Expression/IRExecutionUnit.h"
|
|
17 #include "lldb/Expression/IRInterpreter.h"
|
|
18 #include "lldb/Expression/Materializer.h"
|
|
19 #include "lldb/Host/HostInfo.h"
|
|
20 #include "lldb/Symbol/Block.h"
|
|
21 #include "lldb/Symbol/Function.h"
|
|
22 #include "lldb/Symbol/ObjectFile.h"
|
|
23 #include "lldb/Symbol/SymbolVendor.h"
|
|
24 #include "lldb/Symbol/Type.h"
|
|
25 #include "lldb/Symbol/VariableList.h"
|
|
26 #include "lldb/Target/ExecutionContext.h"
|
|
27 #include "lldb/Target/Process.h"
|
|
28 #include "lldb/Target/StackFrame.h"
|
|
29 #include "lldb/Target/Target.h"
|
|
30 #include "lldb/Target/ThreadPlan.h"
|
|
31 #include "lldb/Target/ThreadPlanCallUserExpression.h"
|
|
32 #include "lldb/Utility/ConstString.h"
|
|
33 #include "lldb/Utility/Log.h"
|
|
34 #include "lldb/Utility/StreamString.h"
|
|
35
|
|
36 using namespace lldb_private;
|
|
37
|
|
38 char LLVMUserExpression::ID;
|
|
39
|
|
40 LLVMUserExpression::LLVMUserExpression(ExecutionContextScope &exe_scope,
|
|
41 llvm::StringRef expr,
|
|
42 llvm::StringRef prefix,
|
|
43 lldb::LanguageType language,
|
|
44 ResultType desired_type,
|
|
45 const EvaluateExpressionOptions &options)
|
|
46 : UserExpression(exe_scope, expr, prefix, language, desired_type, options),
|
|
47 m_stack_frame_bottom(LLDB_INVALID_ADDRESS),
|
|
48 m_stack_frame_top(LLDB_INVALID_ADDRESS), m_allow_cxx(false),
|
|
49 m_allow_objc(false), m_transformed_text(), m_execution_unit_sp(),
|
|
50 m_materializer_up(), m_jit_module_wp(), m_can_interpret(false),
|
|
51 m_materialized_address(LLDB_INVALID_ADDRESS) {}
|
|
52
|
|
53 LLVMUserExpression::~LLVMUserExpression() {
|
|
54 if (m_target) {
|
|
55 lldb::ModuleSP jit_module_sp(m_jit_module_wp.lock());
|
|
56 if (jit_module_sp)
|
|
57 m_target->GetImages().Remove(jit_module_sp);
|
|
58 }
|
|
59 }
|
|
60
|
|
61 lldb::ExpressionResults
|
|
62 LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager,
|
|
63 ExecutionContext &exe_ctx,
|
|
64 const EvaluateExpressionOptions &options,
|
|
65 lldb::UserExpressionSP &shared_ptr_to_me,
|
|
66 lldb::ExpressionVariableSP &result) {
|
|
67 // The expression log is quite verbose, and if you're just tracking the
|
|
68 // execution of the expression, it's quite convenient to have these logs come
|
|
69 // out with the STEP log as well.
|
|
70 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS |
|
|
71 LIBLLDB_LOG_STEP));
|
|
72
|
|
73 if (m_jit_start_addr == LLDB_INVALID_ADDRESS && !m_can_interpret) {
|
|
74 diagnostic_manager.PutString(
|
|
75 eDiagnosticSeverityError,
|
|
76 "Expression can't be run, because there is no JIT compiled function");
|
|
77 return lldb::eExpressionSetupError;
|
|
78 }
|
|
79
|
|
80 lldb::addr_t struct_address = LLDB_INVALID_ADDRESS;
|
|
81
|
|
82 if (!PrepareToExecuteJITExpression(diagnostic_manager, exe_ctx,
|
|
83 struct_address)) {
|
|
84 diagnostic_manager.Printf(
|
|
85 eDiagnosticSeverityError,
|
|
86 "errored out in %s, couldn't PrepareToExecuteJITExpression",
|
|
87 __FUNCTION__);
|
|
88 return lldb::eExpressionSetupError;
|
|
89 }
|
|
90
|
|
91 lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS;
|
|
92 lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS;
|
|
93
|
|
94 if (m_can_interpret) {
|
|
95 llvm::Module *module = m_execution_unit_sp->GetModule();
|
|
96 llvm::Function *function = m_execution_unit_sp->GetFunction();
|
|
97
|
|
98 if (!module || !function) {
|
|
99 diagnostic_manager.PutString(
|
|
100 eDiagnosticSeverityError,
|
|
101 "supposed to interpret, but nothing is there");
|
|
102 return lldb::eExpressionSetupError;
|
|
103 }
|
|
104
|
|
105 Status interpreter_error;
|
|
106
|
|
107 std::vector<lldb::addr_t> args;
|
|
108
|
|
109 if (!AddArguments(exe_ctx, args, struct_address, diagnostic_manager)) {
|
|
110 diagnostic_manager.Printf(eDiagnosticSeverityError,
|
|
111 "errored out in %s, couldn't AddArguments",
|
|
112 __FUNCTION__);
|
|
113 return lldb::eExpressionSetupError;
|
|
114 }
|
|
115
|
|
116 function_stack_bottom = m_stack_frame_bottom;
|
|
117 function_stack_top = m_stack_frame_top;
|
|
118
|
|
119 IRInterpreter::Interpret(*module, *function, args, *m_execution_unit_sp,
|
|
120 interpreter_error, function_stack_bottom,
|
|
121 function_stack_top, exe_ctx);
|
|
122
|
|
123 if (!interpreter_error.Success()) {
|
|
124 diagnostic_manager.Printf(eDiagnosticSeverityError,
|
|
125 "supposed to interpret, but failed: %s",
|
|
126 interpreter_error.AsCString());
|
|
127 return lldb::eExpressionDiscarded;
|
|
128 }
|
|
129 } else {
|
|
130 if (!exe_ctx.HasThreadScope()) {
|
|
131 diagnostic_manager.Printf(eDiagnosticSeverityError,
|
|
132 "%s called with no thread selected",
|
|
133 __FUNCTION__);
|
|
134 return lldb::eExpressionSetupError;
|
|
135 }
|
|
136
|
173
|
137 // Store away the thread ID for error reporting, in case it exits
|
|
138 // during execution:
|
|
139 lldb::tid_t expr_thread_id = exe_ctx.GetThreadRef().GetID();
|
|
140
|
150
|
141 Address wrapper_address(m_jit_start_addr);
|
|
142
|
|
143 std::vector<lldb::addr_t> args;
|
|
144
|
|
145 if (!AddArguments(exe_ctx, args, struct_address, diagnostic_manager)) {
|
|
146 diagnostic_manager.Printf(eDiagnosticSeverityError,
|
|
147 "errored out in %s, couldn't AddArguments",
|
|
148 __FUNCTION__);
|
|
149 return lldb::eExpressionSetupError;
|
|
150 }
|
|
151
|
|
152 lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression(
|
|
153 exe_ctx.GetThreadRef(), wrapper_address, args, options,
|
|
154 shared_ptr_to_me));
|
|
155
|
|
156 StreamString ss;
|
|
157 if (!call_plan_sp || !call_plan_sp->ValidatePlan(&ss)) {
|
|
158 diagnostic_manager.PutString(eDiagnosticSeverityError, ss.GetString());
|
|
159 return lldb::eExpressionSetupError;
|
|
160 }
|
|
161
|
|
162 ThreadPlanCallUserExpression *user_expression_plan =
|
|
163 static_cast<ThreadPlanCallUserExpression *>(call_plan_sp.get());
|
|
164
|
|
165 lldb::addr_t function_stack_pointer =
|
|
166 user_expression_plan->GetFunctionStackPointer();
|
|
167
|
|
168 function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize();
|
|
169 function_stack_top = function_stack_pointer;
|
|
170
|
|
171 LLDB_LOGF(log,
|
|
172 "-- [UserExpression::Execute] Execution of expression begins --");
|
|
173
|
|
174 if (exe_ctx.GetProcessPtr())
|
|
175 exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
|
|
176
|
|
177 lldb::ExpressionResults execution_result =
|
|
178 exe_ctx.GetProcessRef().RunThreadPlan(exe_ctx, call_plan_sp, options,
|
|
179 diagnostic_manager);
|
|
180
|
|
181 if (exe_ctx.GetProcessPtr())
|
|
182 exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
|
|
183
|
|
184 LLDB_LOGF(log, "-- [UserExpression::Execute] Execution of expression "
|
|
185 "completed --");
|
|
186
|
|
187 if (execution_result == lldb::eExpressionInterrupted ||
|
|
188 execution_result == lldb::eExpressionHitBreakpoint) {
|
|
189 const char *error_desc = nullptr;
|
|
190
|
|
191 if (call_plan_sp) {
|
|
192 lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo();
|
|
193 if (real_stop_info_sp)
|
|
194 error_desc = real_stop_info_sp->GetDescription();
|
|
195 }
|
|
196 if (error_desc)
|
|
197 diagnostic_manager.Printf(eDiagnosticSeverityError,
|
|
198 "Execution was interrupted, reason: %s.",
|
|
199 error_desc);
|
|
200 else
|
|
201 diagnostic_manager.PutString(eDiagnosticSeverityError,
|
|
202 "Execution was interrupted.");
|
|
203
|
|
204 if ((execution_result == lldb::eExpressionInterrupted &&
|
|
205 options.DoesUnwindOnError()) ||
|
|
206 (execution_result == lldb::eExpressionHitBreakpoint &&
|
|
207 options.DoesIgnoreBreakpoints()))
|
|
208 diagnostic_manager.AppendMessageToDiagnostic(
|
|
209 "The process has been returned to the state before expression "
|
|
210 "evaluation.");
|
|
211 else {
|
|
212 if (execution_result == lldb::eExpressionHitBreakpoint)
|
|
213 user_expression_plan->TransferExpressionOwnership();
|
|
214 diagnostic_manager.AppendMessageToDiagnostic(
|
|
215 "The process has been left at the point where it was "
|
|
216 "interrupted, "
|
|
217 "use \"thread return -x\" to return to the state before "
|
|
218 "expression evaluation.");
|
|
219 }
|
|
220
|
|
221 return execution_result;
|
|
222 } else if (execution_result == lldb::eExpressionStoppedForDebug) {
|
|
223 diagnostic_manager.PutString(
|
|
224 eDiagnosticSeverityRemark,
|
|
225 "Execution was halted at the first instruction of the expression "
|
|
226 "function because \"debug\" was requested.\n"
|
|
227 "Use \"thread return -x\" to return to the state before expression "
|
|
228 "evaluation.");
|
|
229 return execution_result;
|
173
|
230 } else if (execution_result == lldb::eExpressionThreadVanished) {
|
|
231 diagnostic_manager.Printf(
|
|
232 eDiagnosticSeverityError,
|
|
233 "Couldn't complete execution; the thread "
|
|
234 "on which the expression was being run: 0x%" PRIx64
|
|
235 " exited during its execution.",
|
|
236 expr_thread_id);
|
|
237 return execution_result;
|
150
|
238 } else if (execution_result != lldb::eExpressionCompleted) {
|
|
239 diagnostic_manager.Printf(
|
|
240 eDiagnosticSeverityError, "Couldn't execute function; result was %s",
|
|
241 Process::ExecutionResultAsCString(execution_result));
|
|
242 return execution_result;
|
|
243 }
|
|
244 }
|
|
245
|
|
246 if (FinalizeJITExecution(diagnostic_manager, exe_ctx, result,
|
|
247 function_stack_bottom, function_stack_top)) {
|
|
248 return lldb::eExpressionCompleted;
|
|
249 } else {
|
|
250 return lldb::eExpressionResultUnavailable;
|
|
251 }
|
|
252 }
|
|
253
|
|
254 bool LLVMUserExpression::FinalizeJITExecution(
|
|
255 DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
|
|
256 lldb::ExpressionVariableSP &result, lldb::addr_t function_stack_bottom,
|
|
257 lldb::addr_t function_stack_top) {
|
|
258 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
|
|
259
|
|
260 LLDB_LOGF(log, "-- [UserExpression::FinalizeJITExecution] Dematerializing "
|
|
261 "after execution --");
|
|
262
|
|
263 if (!m_dematerializer_sp) {
|
|
264 diagnostic_manager.Printf(eDiagnosticSeverityError,
|
|
265 "Couldn't apply expression side effects : no "
|
|
266 "dematerializer is present");
|
|
267 return false;
|
|
268 }
|
|
269
|
|
270 Status dematerialize_error;
|
|
271
|
|
272 m_dematerializer_sp->Dematerialize(dematerialize_error, function_stack_bottom,
|
|
273 function_stack_top);
|
|
274
|
|
275 if (!dematerialize_error.Success()) {
|
|
276 diagnostic_manager.Printf(eDiagnosticSeverityError,
|
|
277 "Couldn't apply expression side effects : %s",
|
|
278 dematerialize_error.AsCString("unknown error"));
|
|
279 return false;
|
|
280 }
|
|
281
|
|
282 result =
|
|
283 GetResultAfterDematerialization(exe_ctx.GetBestExecutionContextScope());
|
|
284
|
|
285 if (result)
|
|
286 result->TransferAddress();
|
|
287
|
|
288 m_dematerializer_sp.reset();
|
|
289
|
|
290 return true;
|
|
291 }
|
|
292
|
|
293 bool LLVMUserExpression::PrepareToExecuteJITExpression(
|
|
294 DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
|
|
295 lldb::addr_t &struct_address) {
|
|
296 lldb::TargetSP target;
|
|
297 lldb::ProcessSP process;
|
|
298 lldb::StackFrameSP frame;
|
|
299
|
|
300 if (!LockAndCheckContext(exe_ctx, target, process, frame)) {
|
|
301 diagnostic_manager.PutString(
|
|
302 eDiagnosticSeverityError,
|
|
303 "The context has changed before we could JIT the expression!");
|
|
304 return false;
|
|
305 }
|
|
306
|
|
307 if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) {
|
|
308 if (m_materialized_address == LLDB_INVALID_ADDRESS) {
|
|
309 Status alloc_error;
|
|
310
|
|
311 IRMemoryMap::AllocationPolicy policy =
|
|
312 m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly
|
|
313 : IRMemoryMap::eAllocationPolicyMirror;
|
|
314
|
|
315 const bool zero_memory = false;
|
|
316
|
|
317 m_materialized_address = m_execution_unit_sp->Malloc(
|
|
318 m_materializer_up->GetStructByteSize(),
|
|
319 m_materializer_up->GetStructAlignment(),
|
|
320 lldb::ePermissionsReadable | lldb::ePermissionsWritable, policy,
|
|
321 zero_memory, alloc_error);
|
|
322
|
|
323 if (!alloc_error.Success()) {
|
|
324 diagnostic_manager.Printf(
|
|
325 eDiagnosticSeverityError,
|
|
326 "Couldn't allocate space for materialized struct: %s",
|
|
327 alloc_error.AsCString());
|
|
328 return false;
|
|
329 }
|
|
330 }
|
|
331
|
|
332 struct_address = m_materialized_address;
|
|
333
|
|
334 if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS) {
|
|
335 Status alloc_error;
|
|
336
|
|
337 const size_t stack_frame_size = 512 * 1024;
|
|
338
|
|
339 const bool zero_memory = false;
|
|
340
|
|
341 m_stack_frame_bottom = m_execution_unit_sp->Malloc(
|
|
342 stack_frame_size, 8,
|
|
343 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
|
|
344 IRMemoryMap::eAllocationPolicyHostOnly, zero_memory, alloc_error);
|
|
345
|
|
346 m_stack_frame_top = m_stack_frame_bottom + stack_frame_size;
|
|
347
|
|
348 if (!alloc_error.Success()) {
|
|
349 diagnostic_manager.Printf(
|
|
350 eDiagnosticSeverityError,
|
|
351 "Couldn't allocate space for the stack frame: %s",
|
|
352 alloc_error.AsCString());
|
|
353 return false;
|
|
354 }
|
|
355 }
|
|
356
|
|
357 Status materialize_error;
|
|
358
|
|
359 m_dematerializer_sp = m_materializer_up->Materialize(
|
|
360 frame, *m_execution_unit_sp, struct_address, materialize_error);
|
|
361
|
|
362 if (!materialize_error.Success()) {
|
|
363 diagnostic_manager.Printf(eDiagnosticSeverityError,
|
|
364 "Couldn't materialize: %s",
|
|
365 materialize_error.AsCString());
|
|
366 return false;
|
|
367 }
|
|
368 }
|
|
369 return true;
|
|
370 }
|
|
371
|