Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Expression/LLVMUserExpression.cpp
39587 views
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/ValueObjectConstResult.h"
13
#include "lldb/Expression/DiagnosticManager.h"
14
#include "lldb/Expression/ExpressionVariable.h"
15
#include "lldb/Expression/IRExecutionUnit.h"
16
#include "lldb/Expression/IRInterpreter.h"
17
#include "lldb/Expression/Materializer.h"
18
#include "lldb/Host/HostInfo.h"
19
#include "lldb/Symbol/Block.h"
20
#include "lldb/Symbol/Function.h"
21
#include "lldb/Symbol/ObjectFile.h"
22
#include "lldb/Symbol/SymbolVendor.h"
23
#include "lldb/Symbol/Type.h"
24
#include "lldb/Symbol/VariableList.h"
25
#include "lldb/Target/ABI.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/LLDBLog.h"
34
#include "lldb/Utility/Log.h"
35
#include "lldb/Utility/StreamString.h"
36
37
using namespace lldb;
38
using namespace lldb_private;
39
40
char LLVMUserExpression::ID;
41
42
LLVMUserExpression::LLVMUserExpression(ExecutionContextScope &exe_scope,
43
llvm::StringRef expr,
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) {}
54
55
LLVMUserExpression::~LLVMUserExpression() {
56
if (m_target) {
57
lldb::ModuleSP jit_module_sp(m_jit_module_wp.lock());
58
if (jit_module_sp)
59
m_target->GetImages().Remove(jit_module_sp);
60
}
61
}
62
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));
73
74
if (m_jit_start_addr == LLDB_INVALID_ADDRESS && !m_can_interpret) {
75
diagnostic_manager.PutString(
76
lldb::eSeverityError,
77
"Expression can't be run, because there is no JIT compiled function");
78
return lldb::eExpressionSetupError;
79
}
80
81
lldb::addr_t struct_address = LLDB_INVALID_ADDRESS;
82
83
if (!PrepareToExecuteJITExpression(diagnostic_manager, exe_ctx,
84
struct_address)) {
85
diagnostic_manager.Printf(
86
lldb::eSeverityError,
87
"errored out in %s, couldn't PrepareToExecuteJITExpression",
88
__FUNCTION__);
89
return lldb::eExpressionSetupError;
90
}
91
92
lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS;
93
lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS;
94
95
if (m_can_interpret) {
96
llvm::Module *module = m_execution_unit_sp->GetModule();
97
llvm::Function *function = m_execution_unit_sp->GetFunction();
98
99
if (!module || !function) {
100
diagnostic_manager.PutString(
101
lldb::eSeverityError, "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(lldb::eSeverityError,
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, options.GetTimeout());
122
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;
128
}
129
} else {
130
if (!exe_ctx.HasThreadScope()) {
131
diagnostic_manager.Printf(lldb::eSeverityError,
132
"%s called with no thread selected",
133
__FUNCTION__);
134
return lldb::eExpressionSetupError;
135
}
136
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
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(lldb::eSeverityError,
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(lldb::eSeverityError, 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 (user_expression_plan) {
192
if (auto real_stop_info_sp = user_expression_plan->GetRealStopInfo())
193
error_desc = real_stop_info_sp->GetDescription();
194
}
195
if (error_desc)
196
diagnostic_manager.Printf(lldb::eSeverityError,
197
"Execution was interrupted, reason: %s.",
198
error_desc);
199
else
200
diagnostic_manager.PutString(lldb::eSeverityError,
201
"Execution was interrupted.");
202
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 "
209
"evaluation.");
210
else {
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 "
215
"interrupted, "
216
"use \"thread return -x\" to return to the state before "
217
"expression evaluation.");
218
}
219
220
return execution_result;
221
} else if (execution_result == lldb::eExpressionStoppedForDebug) {
222
diagnostic_manager.PutString(
223
lldb::eSeverityInfo,
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 "
227
"evaluation.");
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.",
235
expr_thread_id);
236
return execution_result;
237
} else if (execution_result != lldb::eExpressionCompleted) {
238
diagnostic_manager.Printf(
239
lldb::eSeverityError, "Couldn't execute function; result was %s",
240
Process::ExecutionResultAsCString(execution_result));
241
return execution_result;
242
}
243
}
244
245
if (FinalizeJITExecution(diagnostic_manager, exe_ctx, result,
246
function_stack_bottom, function_stack_top)) {
247
return lldb::eExpressionCompleted;
248
} else {
249
return lldb::eExpressionResultUnavailable;
250
}
251
}
252
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);
258
259
LLDB_LOGF(log, "-- [UserExpression::FinalizeJITExecution] Dematerializing "
260
"after execution --");
261
262
if (!m_dematerializer_sp) {
263
diagnostic_manager.Printf(lldb::eSeverityError,
264
"Couldn't apply expression side effects : no "
265
"dematerializer is present");
266
return false;
267
}
268
269
Status dematerialize_error;
270
271
m_dematerializer_sp->Dematerialize(dematerialize_error, function_stack_bottom,
272
function_stack_top);
273
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"));
278
return false;
279
}
280
281
result =
282
GetResultAfterDematerialization(exe_ctx.GetBestExecutionContextScope());
283
284
if (result)
285
result->TransferAddress();
286
287
m_dematerializer_sp.reset();
288
289
return true;
290
}
291
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;
298
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!");
303
return false;
304
}
305
306
if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) {
307
if (m_materialized_address == LLDB_INVALID_ADDRESS) {
308
Status alloc_error;
309
310
IRMemoryMap::AllocationPolicy policy =
311
m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly
312
: IRMemoryMap::eAllocationPolicyMirror;
313
314
const bool zero_memory = false;
315
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);
321
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());
327
return false;
328
}
329
}
330
331
struct_address = m_materialized_address;
332
333
if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS) {
334
Status alloc_error;
335
336
size_t stack_frame_size = target->GetExprAllocSize();
337
if (stack_frame_size == 0) {
338
ABISP abi_sp;
339
if (process && (abi_sp = process->GetABI()))
340
stack_frame_size = abi_sp->GetStackFrameSize();
341
else
342
stack_frame_size = 512 * 1024;
343
}
344
345
const bool zero_memory = false;
346
347
m_stack_frame_bottom = m_execution_unit_sp->Malloc(
348
stack_frame_size, 8,
349
lldb::ePermissionsReadable | lldb::ePermissionsWritable,
350
IRMemoryMap::eAllocationPolicyHostOnly, zero_memory, alloc_error);
351
352
m_stack_frame_top = m_stack_frame_bottom + stack_frame_size;
353
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());
359
return false;
360
}
361
}
362
363
Status materialize_error;
364
365
m_dematerializer_sp = m_materializer_up->Materialize(
366
frame, *m_execution_unit_sp, struct_address, materialize_error);
367
368
if (!materialize_error.Success()) {
369
diagnostic_manager.Printf(lldb::eSeverityError,
370
"Couldn't materialize: %s",
371
materialize_error.AsCString());
372
return false;
373
}
374
}
375
return true;
376
}
377
378
379