LLDB  mainline
LLVMUserExpression.cpp
Go to the documentation of this file.
1 //===-- LLVMUserExpression.cpp ----------------------------------*- C++ -*-===//
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 
11 #include "lldb/Core/Module.h"
12 #include "lldb/Core/StreamFile.h"
18 #include "lldb/Host/HostInfo.h"
19 #include "lldb/Symbol/Block.h"
22 #include "lldb/Symbol/Function.h"
23 #include "lldb/Symbol/ObjectFile.h"
25 #include "lldb/Symbol/Type.h"
28 #include "lldb/Target/Process.h"
29 #include "lldb/Target/StackFrame.h"
30 #include "lldb/Target/Target.h"
31 #include "lldb/Target/ThreadPlan.h"
34 #include "lldb/Utility/Log.h"
36 
37 using namespace lldb_private;
38 
40  llvm::StringRef expr,
41  llvm::StringRef prefix,
42  lldb::LanguageType language,
43  ResultType desired_type,
44  const EvaluateExpressionOptions &options,
45  ExpressionKind kind)
46  : UserExpression(exe_scope, expr, prefix, language, desired_type, options,
47  kind),
48  m_stack_frame_bottom(LLDB_INVALID_ADDRESS),
49  m_stack_frame_top(LLDB_INVALID_ADDRESS), m_allow_cxx(false),
50  m_allow_objc(false), m_transformed_text(), m_execution_unit_sp(),
51  m_materializer_up(), m_jit_module_wp(), m_enforce_valid_object(true),
52  m_in_cplusplus_method(false), m_in_objectivec_method(false),
53  m_in_static_method(false), m_needs_object_ptr(false), m_target(NULL),
54  m_can_interpret(false), m_materialized_address(LLDB_INVALID_ADDRESS) {}
55 
57  if (m_target) {
58  lldb::ModuleSP jit_module_sp(m_jit_module_wp.lock());
59  if (jit_module_sp)
60  m_target->GetImages().Remove(jit_module_sp);
61  }
62 }
63 
66  ExecutionContext &exe_ctx,
67  const EvaluateExpressionOptions &options,
68  lldb::UserExpressionSP &shared_ptr_to_me,
69  lldb::ExpressionVariableSP &result) {
70  // The expression log is quite verbose, and if you're just tracking the
71  // execution of the expression, it's quite convenient to have these logs come
72  // out with the STEP log as well.
75 
77  lldb::addr_t struct_address = LLDB_INVALID_ADDRESS;
78 
79  if (!PrepareToExecuteJITExpression(diagnostic_manager, exe_ctx,
80  struct_address)) {
81  diagnostic_manager.Printf(
83  "errored out in %s, couldn't PrepareToExecuteJITExpression",
84  __FUNCTION__);
86  }
87 
88  lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS;
89  lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS;
90 
91  if (m_can_interpret) {
92  llvm::Module *module = m_execution_unit_sp->GetModule();
93  llvm::Function *function = m_execution_unit_sp->GetFunction();
94 
95  if (!module || !function) {
96  diagnostic_manager.PutString(
98  "supposed to interpret, but nothing is there");
100  }
101 
102  Status interpreter_error;
103 
104  std::vector<lldb::addr_t> args;
105 
106  if (!AddArguments(exe_ctx, args, struct_address, diagnostic_manager)) {
107  diagnostic_manager.Printf(eDiagnosticSeverityError,
108  "errored out in %s, couldn't AddArguments",
109  __FUNCTION__);
111  }
112 
113  function_stack_bottom = m_stack_frame_bottom;
114  function_stack_top = m_stack_frame_top;
115 
116  IRInterpreter::Interpret(*module, *function, args, *m_execution_unit_sp,
117  interpreter_error, function_stack_bottom,
118  function_stack_top, exe_ctx);
119 
120  if (!interpreter_error.Success()) {
121  diagnostic_manager.Printf(eDiagnosticSeverityError,
122  "supposed to interpret, but failed: %s",
123  interpreter_error.AsCString());
125  }
126  } else {
127  if (!exe_ctx.HasThreadScope()) {
128  diagnostic_manager.Printf(eDiagnosticSeverityError,
129  "%s called with no thread selected",
130  __FUNCTION__);
132  }
133 
134  Address wrapper_address(m_jit_start_addr);
135 
136  std::vector<lldb::addr_t> args;
137 
138  if (!AddArguments(exe_ctx, args, struct_address, diagnostic_manager)) {
139  diagnostic_manager.Printf(eDiagnosticSeverityError,
140  "errored out in %s, couldn't AddArguments",
141  __FUNCTION__);
143  }
144 
145  lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression(
146  exe_ctx.GetThreadRef(), wrapper_address, args, options,
147  shared_ptr_to_me));
148 
149  StreamString ss;
150  if (!call_plan_sp || !call_plan_sp->ValidatePlan(&ss)) {
151  diagnostic_manager.PutString(eDiagnosticSeverityError, ss.GetString());
153  }
154 
155  ThreadPlanCallUserExpression *user_expression_plan =
156  static_cast<ThreadPlanCallUserExpression *>(call_plan_sp.get());
157 
158  lldb::addr_t function_stack_pointer =
159  user_expression_plan->GetFunctionStackPointer();
160 
161  function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize();
162  function_stack_top = function_stack_pointer;
163 
164  if (log)
165  log->Printf(
166  "-- [UserExpression::Execute] Execution of expression begins --");
167 
168  if (exe_ctx.GetProcessPtr())
169  exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
170 
171  lldb::ExpressionResults execution_result =
172  exe_ctx.GetProcessRef().RunThreadPlan(exe_ctx, call_plan_sp, options,
173  diagnostic_manager);
174 
175  if (exe_ctx.GetProcessPtr())
176  exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
177 
178  if (log)
179  log->Printf("-- [UserExpression::Execute] Execution of expression "
180  "completed --");
181 
182  if (execution_result == lldb::eExpressionInterrupted ||
183  execution_result == lldb::eExpressionHitBreakpoint) {
184  const char *error_desc = NULL;
185 
186  if (call_plan_sp) {
187  lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo();
188  if (real_stop_info_sp)
189  error_desc = real_stop_info_sp->GetDescription();
190  }
191  if (error_desc)
192  diagnostic_manager.Printf(eDiagnosticSeverityError,
193  "Execution was interrupted, reason: %s.",
194  error_desc);
195  else
196  diagnostic_manager.PutString(eDiagnosticSeverityError,
197  "Execution was interrupted.");
198 
199  if ((execution_result == lldb::eExpressionInterrupted &&
200  options.DoesUnwindOnError()) ||
201  (execution_result == lldb::eExpressionHitBreakpoint &&
202  options.DoesIgnoreBreakpoints()))
203  diagnostic_manager.AppendMessageToDiagnostic(
204  "The process has been returned to the state before expression "
205  "evaluation.");
206  else {
207  if (execution_result == lldb::eExpressionHitBreakpoint)
208  user_expression_plan->TransferExpressionOwnership();
209  diagnostic_manager.AppendMessageToDiagnostic(
210  "The process has been left at the point where it was "
211  "interrupted, "
212  "use \"thread return -x\" to return to the state before "
213  "expression evaluation.");
214  }
215 
216  return execution_result;
217  } else if (execution_result == lldb::eExpressionStoppedForDebug) {
218  diagnostic_manager.PutString(
220  "Execution was halted at the first instruction of the expression "
221  "function because \"debug\" was requested.\n"
222  "Use \"thread return -x\" to return to the state before expression "
223  "evaluation.");
224  return execution_result;
225  } else if (execution_result != lldb::eExpressionCompleted) {
226  diagnostic_manager.Printf(
228  "Couldn't execute function; result was %s",
229  Process::ExecutionResultAsCString(execution_result));
230  return execution_result;
231  }
232  }
233 
234  if (FinalizeJITExecution(diagnostic_manager, exe_ctx, result,
235  function_stack_bottom, function_stack_top)) {
237  } else {
239  }
240  } else {
241  diagnostic_manager.PutString(
243  "Expression can't be run, because there is no JIT compiled function");
245  }
246 }
247 
249  DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
250  lldb::ExpressionVariableSP &result, lldb::addr_t function_stack_bottom,
251  lldb::addr_t function_stack_top) {
253 
254  if (log)
255  log->Printf("-- [UserExpression::FinalizeJITExecution] Dematerializing "
256  "after execution --");
257 
258  if (!m_dematerializer_sp) {
259  diagnostic_manager.Printf(eDiagnosticSeverityError,
260  "Couldn't apply expression side effects : no "
261  "dematerializer is present");
262  return false;
263  }
264 
265  Status dematerialize_error;
266 
267  m_dematerializer_sp->Dematerialize(dematerialize_error, function_stack_bottom,
268  function_stack_top);
269 
270  if (!dematerialize_error.Success()) {
271  diagnostic_manager.Printf(eDiagnosticSeverityError,
272  "Couldn't apply expression side effects : %s",
273  dematerialize_error.AsCString("unknown error"));
274  return false;
275  }
276 
277  result =
279 
280  if (result)
281  result->TransferAddress();
282 
283  m_dematerializer_sp.reset();
284 
285  return true;
286 }
287 
289  DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
290  lldb::addr_t &struct_address) {
291  lldb::TargetSP target;
292  lldb::ProcessSP process;
293  lldb::StackFrameSP frame;
294 
295  if (!LockAndCheckContext(exe_ctx, target, process, frame)) {
296  diagnostic_manager.PutString(
298  "The context has changed before we could JIT the expression!");
299  return false;
300  }
301 
304  Status alloc_error;
305 
309 
310  const bool zero_memory = false;
311 
313  m_materializer_up->GetStructByteSize(),
314  m_materializer_up->GetStructAlignment(),
315  lldb::ePermissionsReadable | lldb::ePermissionsWritable, policy,
316  zero_memory, alloc_error);
317 
318  if (!alloc_error.Success()) {
319  diagnostic_manager.Printf(
321  "Couldn't allocate space for materialized struct: %s",
322  alloc_error.AsCString());
323  return false;
324  }
325  }
326 
327  struct_address = m_materialized_address;
328 
330  Status alloc_error;
331 
332  const size_t stack_frame_size = 512 * 1024;
333 
334  const bool zero_memory = false;
335 
337  stack_frame_size, 8,
338  lldb::ePermissionsReadable | lldb::ePermissionsWritable,
339  IRMemoryMap::eAllocationPolicyHostOnly, zero_memory, alloc_error);
340 
341  m_stack_frame_top = m_stack_frame_bottom + stack_frame_size;
342 
343  if (!alloc_error.Success()) {
344  diagnostic_manager.Printf(
346  "Couldn't allocate space for the stack frame: %s",
347  alloc_error.AsCString());
348  return false;
349  }
350  }
351 
352  Status materialize_error;
353 
354  m_dematerializer_sp = m_materializer_up->Materialize(
355  frame, *m_execution_unit_sp, struct_address, materialize_error);
356 
357  if (!materialize_error.Success()) {
358  diagnostic_manager.Printf(eDiagnosticSeverityError,
359  "Couldn't materialize: %s",
360  materialize_error.AsCString());
361  return false;
362  }
363  }
364  return true;
365 }
366 
369  return m_execution_unit_sp->GetJITModule();
370  return lldb::ModuleSP();
371 }
Materializer::DematerializerSP m_dematerializer_sp
The dematerializer.
ExpressionKind
Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
Definition: Expression.h:36
lldb::addr_t m_jit_start_addr
An expression might have a process, but it doesn&#39;t need to (e.g.
Definition: Expression.h:104
bool HasThreadScope() const
Returns true the ExecutionContext object contains a valid target, process, and thread.
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
virtual bool AddArguments(ExecutionContext &exe_ctx, std::vector< lldb::addr_t > &args, lldb::addr_t struct_address, DiagnosticManager &diagnostic_manager)=0
lldb::ExpressionResults RunThreadPlan(ExecutionContext &exe_ctx, lldb::ThreadPlanSP &thread_plan_sp, const EvaluateExpressionOptions &options, DiagnosticManager &diagnostic_manager)
Definition: Process.cpp:4648
bool FinalizeJITExecution(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, lldb::ExpressionVariableSP &result, lldb::addr_t function_stack_bottom=LLDB_INVALID_ADDRESS, lldb::addr_t function_stack_top=LLDB_INVALID_ADDRESS) override
Apply the side effects of the function to program state.
static bool Interpret(llvm::Module &module, llvm::Function &function, llvm::ArrayRef< lldb::addr_t > args, lldb_private::IRExecutionUnit &execution_unit, lldb_private::Status &error, lldb::addr_t stack_frame_bottom, lldb::addr_t stack_frame_top, lldb_private::ExecutionContext &exe_ctx)
Encapsulates a one-time expression for use in lldb.
Thread & GetThreadRef() const
Returns a reference to the thread object.
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
static const char * ExecutionResultAsCString(lldb::ExpressionResults result)
Definition: Process.cpp:5436
lldb::addr_t m_stack_frame_bottom
The bottom of the allocated stack frame.
lldb::ExpressionResults DoExecute(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options, lldb::UserExpressionSP &shared_ptr_to_me, lldb::ExpressionVariableSP &result) override
lldb::ModuleSP GetJITModule() override
std::unique_ptr< Materializer > m_materializer_up
The materializer to use when running the expression.
virtual lldb::ExpressionVariableSP GetResultAfterDematerialization(ExecutionContextScope *exe_scope)
This allocation was created in the host and will never make it into the process.
Definition: IRMemoryMap.h:42
bool Remove(const lldb::ModuleSP &module_sp, bool notify=true)
Remove a module from the module list.
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
lldb::addr_t m_stack_frame_top
The top of the allocated stack frame.
LanguageType
Programming language type.
std::shared_ptr< IRExecutionUnit > m_execution_unit_sp
The execution unit the expression is stored in.
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:57
The intent is that this allocation exist both in the host and the process and have the same content i...
Definition: IRMemoryMap.h:46
void SetRunningUserExpression(bool on)
Definition: Process.cpp:1531
bool m_can_interpret
True if the expression could be evaluated statically; false otherwise.
llvm::StringRef GetString() const
size_t Printf(DiagnosticSeverity severity, const char *format,...) __attribute__((format(printf
"lldb/Target/ExecutionContextScope.h" Inherit from this if your object can reconstruct its execution ...
Process * GetProcessPtr() const
Returns a pointer to the process object.
size_t size_t PutString(DiagnosticSeverity severity, llvm::StringRef str)
bool Success() const
Test for success condition.
Definition: Status.cpp:287
A section + offset based address class.
Definition: Address.h:80
bool PrepareToExecuteJITExpression(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, lldb::addr_t &struct_address)
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition: Target.h:899
Target * m_target
The target for storing persistent data like types and variables.
uint64_t addr_t
Definition: lldb-types.h:83
lldb::addr_t m_materialized_address
The address at which the arguments to the expression have been materialized.
bool LockAndCheckContext(ExecutionContext &exe_ctx, lldb::TargetSP &target_sp, lldb::ProcessSP &process_sp, lldb::StackFrameSP &frame_sp)
Log * GetLogIfAnyCategoriesSet(uint32_t mask)
Definition: Logging.cpp:61
#define LIBLLDB_LOG_EXPRESSIONS
Definition: Logging.h:22
LLVMUserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, ResultType desired_type, const EvaluateExpressionOptions &options, ExpressionKind kind)
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition: Status.cpp:130
void AppendMessageToDiagnostic(llvm::StringRef str)
Process & GetProcessRef() const
Returns a reference to the process object.
ExecutionContextScope * GetBestExecutionContextScope() const
#define LIBLLDB_LOG_STEP
Definition: Logging.h:21
void Printf(const char *format,...) __attribute__((format(printf
Definition: Log.cpp:113
An error handling class.
Definition: Status.h:44