LLDB  mainline
CommandObjectFrame.cpp
Go to the documentation of this file.
1 //===-- CommandObjectFrame.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 #include "CommandObjectFrame.h"
9 #include "lldb/Core/Debugger.h"
10 #include "lldb/Core/ValueObject.h"
13 #include "lldb/Host/Config.h"
14 #include "lldb/Host/OptionParser.h"
21 #include "lldb/Symbol/Function.h"
23 #include "lldb/Symbol/Variable.h"
25 #include "lldb/Target/StackFrame.h"
27 #include "lldb/Target/StopInfo.h"
28 #include "lldb/Target/Target.h"
29 #include "lldb/Target/Thread.h"
30 #include "lldb/Utility/Args.h"
31 
32 #include <memory>
33 #include <string>
34 
35 using namespace lldb;
36 using namespace lldb_private;
37 
38 #pragma mark CommandObjectFrameDiagnose
39 
40 // CommandObjectFrameInfo
41 
42 // CommandObjectFrameDiagnose
43 
44 #define LLDB_OPTIONS_frame_diag
45 #include "CommandOptions.inc"
46 
48 public:
49  class CommandOptions : public Options {
50  public:
51  CommandOptions() : Options() { OptionParsingStarting(nullptr); }
52 
53  ~CommandOptions() override = default;
54 
55  Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
56  ExecutionContext *execution_context) override {
57  Status error;
58  const int short_option = m_getopt_table[option_idx].val;
59  switch (short_option) {
60  case 'r':
61  reg = ConstString(option_arg);
62  break;
63 
64  case 'a': {
65  address.emplace();
66  if (option_arg.getAsInteger(0, *address)) {
67  address.reset();
68  error.SetErrorStringWithFormat("invalid address argument '%s'",
69  option_arg.str().c_str());
70  }
71  } break;
72 
73  case 'o': {
74  offset.emplace();
75  if (option_arg.getAsInteger(0, *offset)) {
76  offset.reset();
77  error.SetErrorStringWithFormat("invalid offset argument '%s'",
78  option_arg.str().c_str());
79  }
80  } break;
81 
82  default:
83  llvm_unreachable("Unimplemented option");
84  }
85 
86  return error;
87  }
88 
89  void OptionParsingStarting(ExecutionContext *execution_context) override {
90  address.reset();
91  reg.reset();
92  offset.reset();
93  }
94 
95  llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
96  return llvm::makeArrayRef(g_frame_diag_options);
97  }
98 
99  // Options.
100  llvm::Optional<lldb::addr_t> address;
101  llvm::Optional<ConstString> reg;
102  llvm::Optional<int64_t> offset;
103  };
104 
106  : CommandObjectParsed(interpreter, "frame diagnose",
107  "Try to determine what path path the current stop "
108  "location used to get to a register or address",
109  nullptr,
110  eCommandRequiresThread | eCommandTryTargetAPILock |
111  eCommandProcessMustBeLaunched |
112  eCommandProcessMustBePaused),
113  m_options() {
115  CommandArgumentData index_arg;
116 
117  // Define the first (and only) variant of this arg.
118  index_arg.arg_type = eArgTypeFrameIndex;
120 
121  // There is only one variant this argument could be; put it into the
122  // argument entry.
123  arg.push_back(index_arg);
124 
125  // Push the data for the first argument into the m_arguments vector.
126  m_arguments.push_back(arg);
127  }
128 
129  ~CommandObjectFrameDiagnose() override = default;
130 
131  Options *GetOptions() override { return &m_options; }
132 
133 protected:
134  bool DoExecute(Args &command, CommandReturnObject &result) override {
135  Thread *thread = m_exe_ctx.GetThreadPtr();
136  StackFrameSP frame_sp = thread->GetSelectedFrame();
137 
138  ValueObjectSP valobj_sp;
139 
140  if (m_options.address.hasValue()) {
141  if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
142  result.AppendError(
143  "`frame diagnose --address` is incompatible with other arguments.");
145  return false;
146  }
147  valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
148  } else if (m_options.reg.hasValue()) {
149  valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
150  m_options.reg.getValue(), m_options.offset.getValueOr(0));
151  } else {
152  StopInfoSP stop_info_sp = thread->GetStopInfo();
153  if (!stop_info_sp) {
154  result.AppendError("No arguments provided, and no stop info.");
156  return false;
157  }
158 
159  valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
160  }
161 
162  if (!valobj_sp) {
163  result.AppendError("No diagnosis available.");
165  return false;
166  }
167 
169  [&valobj_sp](ConstString type, ConstString var,
170  const DumpValueObjectOptions &opts,
171  Stream &stream) -> bool {
172  const ValueObject::GetExpressionPathFormat format = ValueObject::
173  GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
174  valobj_sp->GetExpressionPath(stream, format);
175  stream.PutCString(" =");
176  return true;
177  };
178 
179  DumpValueObjectOptions options;
180  options.SetDeclPrintingHelper(helper);
181  ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
182  options);
183  printer.PrintValueObject();
184 
185  return true;
186  }
187 
189 };
190 
191 #pragma mark CommandObjectFrameInfo
192 
193 // CommandObjectFrameInfo
194 
196 public:
198  : CommandObjectParsed(interpreter, "frame info",
199  "List information about the current "
200  "stack frame in the current thread.",
201  "frame info",
202  eCommandRequiresFrame | eCommandTryTargetAPILock |
203  eCommandProcessMustBeLaunched |
204  eCommandProcessMustBePaused) {}
205 
206  ~CommandObjectFrameInfo() override = default;
207 
208 protected:
209  bool DoExecute(Args &command, CommandReturnObject &result) override {
210  m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
212  return result.Succeeded();
213  }
214 };
215 
216 #pragma mark CommandObjectFrameSelect
217 
218 // CommandObjectFrameSelect
219 
220 #define LLDB_OPTIONS_frame_select
221 #include "CommandOptions.inc"
222 
224 public:
225  class CommandOptions : public Options {
226  public:
227  CommandOptions() : Options() { OptionParsingStarting(nullptr); }
228 
229  ~CommandOptions() override = default;
230 
231  Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
232  ExecutionContext *execution_context) override {
233  Status error;
234  const int short_option = m_getopt_table[option_idx].val;
235  switch (short_option) {
236  case 'r': {
237  int32_t offset = 0;
238  if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
239  error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
240  option_arg.str().c_str());
241  } else
242  relative_frame_offset = offset;
243  break;
244  }
245 
246  default:
247  llvm_unreachable("Unimplemented option");
248  }
249 
250  return error;
251  }
252 
253  void OptionParsingStarting(ExecutionContext *execution_context) override {
254  relative_frame_offset.reset();
255  }
256 
257  llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
258  return llvm::makeArrayRef(g_frame_select_options);
259  }
260 
261  llvm::Optional<int32_t> relative_frame_offset;
262  };
263 
265  : CommandObjectParsed(interpreter, "frame select",
266  "Select the current stack frame by "
267  "index from within the current thread "
268  "(see 'thread backtrace'.)",
269  nullptr,
270  eCommandRequiresThread | eCommandTryTargetAPILock |
271  eCommandProcessMustBeLaunched |
272  eCommandProcessMustBePaused),
273  m_options() {
275  CommandArgumentData index_arg;
276 
277  // Define the first (and only) variant of this arg.
278  index_arg.arg_type = eArgTypeFrameIndex;
280 
281  // There is only one variant this argument could be; put it into the
282  // argument entry.
283  arg.push_back(index_arg);
284 
285  // Push the data for the first argument into the m_arguments vector.
286  m_arguments.push_back(arg);
287  }
288 
289  ~CommandObjectFrameSelect() override = default;
290 
291  void
293  OptionElementVector &opt_element_vector) override {
294  if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0)
295  return;
296 
297  lldb::ThreadSP thread_sp = m_exe_ctx.GetThreadSP();
298  const uint32_t frame_num = thread_sp->GetStackFrameCount();
299  for (uint32_t i = 0; i < frame_num; ++i) {
300  lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i);
301  StreamString strm;
302  frame_sp->Dump(&strm, false, true);
303  request.TryCompleteCurrentArg(std::to_string(i), strm.GetString());
304  }
305  }
306 
307  Options *GetOptions() override { return &m_options; }
308 
309 protected:
310  bool DoExecute(Args &command, CommandReturnObject &result) override {
311  // No need to check "thread" for validity as eCommandRequiresThread ensures
312  // it is valid
313  Thread *thread = m_exe_ctx.GetThreadPtr();
314 
315  uint32_t frame_idx = UINT32_MAX;
316  if (m_options.relative_frame_offset.hasValue()) {
317  // The one and only argument is a signed relative frame index
318  frame_idx = thread->GetSelectedFrameIndex();
319  if (frame_idx == UINT32_MAX)
320  frame_idx = 0;
321 
322  if (*m_options.relative_frame_offset < 0) {
323  if (static_cast<int32_t>(frame_idx) >=
324  -*m_options.relative_frame_offset)
325  frame_idx += *m_options.relative_frame_offset;
326  else {
327  if (frame_idx == 0) {
328  // If you are already at the bottom of the stack, then just warn
329  // and don't reset the frame.
330  result.AppendError("Already at the bottom of the stack.");
332  return false;
333  } else
334  frame_idx = 0;
335  }
336  } else if (*m_options.relative_frame_offset > 0) {
337  // I don't want "up 20" where "20" takes you past the top of the stack
338  // to produce
339  // an error, but rather to just go to the top. So I have to count the
340  // stack here...
341  const uint32_t num_frames = thread->GetStackFrameCount();
342  if (static_cast<int32_t>(num_frames - frame_idx) >
343  *m_options.relative_frame_offset)
344  frame_idx += *m_options.relative_frame_offset;
345  else {
346  if (frame_idx == num_frames - 1) {
347  // If we are already at the top of the stack, just warn and don't
348  // reset the frame.
349  result.AppendError("Already at the top of the stack.");
351  return false;
352  } else
353  frame_idx = num_frames - 1;
354  }
355  }
356  } else {
357  if (command.GetArgumentCount() > 1) {
358  result.AppendErrorWithFormat(
359  "too many arguments; expected frame-index, saw '%s'.\n",
360  command[0].c_str());
361  m_options.GenerateOptionUsage(
362  result.GetErrorStream(), this,
363  GetCommandInterpreter().GetDebugger().GetTerminalWidth());
364  return false;
365  }
366 
367  if (command.GetArgumentCount() == 1) {
368  if (command[0].ref().getAsInteger(0, frame_idx)) {
369  result.AppendErrorWithFormat("invalid frame index argument '%s'.",
370  command[0].c_str());
372  return false;
373  }
374  } else if (command.GetArgumentCount() == 0) {
375  frame_idx = thread->GetSelectedFrameIndex();
376  if (frame_idx == UINT32_MAX) {
377  frame_idx = 0;
378  }
379  }
380  }
381 
382  bool success = thread->SetSelectedFrameByIndexNoisily(
383  frame_idx, result.GetOutputStream());
384  if (success) {
385  m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
387  } else {
388  result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
389  frame_idx);
391  }
392 
393  return result.Succeeded();
394  }
395 
397 };
398 
399 #pragma mark CommandObjectFrameVariable
400 // List images with associated information
402 public:
405  interpreter, "frame variable",
406  "Show variables for the current stack frame. Defaults to all "
407  "arguments and local variables in scope. Names of argument, "
408  "local, file static and file global variables can be specified. "
409  "Children of aggregate variables can be specified such as "
410  "'var->child.x'. The -> and [] operators in 'frame variable' do "
411  "not invoke operator overloads if they exist, but directly access "
412  "the specified element. If you want to trigger operator overloads "
413  "use the expression command to print the variable instead."
414  "\nIt is worth noting that except for overloaded "
415  "operators, when printing local variables 'expr local_var' and "
416  "'frame var local_var' produce the same "
417  "results. However, 'frame variable' is more efficient, since it "
418  "uses debug information and memory reads directly, rather than "
419  "parsing and evaluating an expression, which may even involve "
420  "JITing and running code in the target program.",
421  nullptr,
422  eCommandRequiresFrame | eCommandTryTargetAPILock |
423  eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
424  eCommandRequiresProcess),
425  m_option_group(),
426  m_option_variable(
427  true), // Include the frame specific options by passing "true"
428  m_option_format(eFormatDefault), m_varobj_options() {
430  CommandArgumentData var_name_arg;
431 
432  // Define the first (and only) variant of this arg.
433  var_name_arg.arg_type = eArgTypeVarName;
434  var_name_arg.arg_repetition = eArgRepeatStar;
435 
436  // There is only one variant this argument could be; put it into the
437  // argument entry.
438  arg.push_back(var_name_arg);
439 
440  // Push the data for the first argument into the m_arguments vector.
441  m_arguments.push_back(arg);
442 
443  m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
444  m_option_group.Append(&m_option_format,
445  OptionGroupFormat::OPTION_GROUP_FORMAT |
446  OptionGroupFormat::OPTION_GROUP_GDB_FMT,
448  m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
449  m_option_group.Finalize();
450  }
451 
452  ~CommandObjectFrameVariable() override = default;
453 
454  Options *GetOptions() override { return &m_option_group; }
455 
456  void
458  OptionElementVector &opt_element_vector) override {
459  // Arguments are the standard source file completer.
460  CommandCompletions::InvokeCommonCompletionCallbacks(
461  GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
462  request, nullptr);
463  }
464 
465 protected:
466  llvm::StringRef GetScopeString(VariableSP var_sp) {
467  if (!var_sp)
468  return llvm::StringRef::withNullAsEmpty(nullptr);
469 
470  switch (var_sp->GetScope()) {
472  return "GLOBAL: ";
474  return "STATIC: ";
476  return "ARG: ";
478  return "LOCAL: ";
480  return "THREAD: ";
481  default:
482  break;
483  }
484 
485  return llvm::StringRef::withNullAsEmpty(nullptr);
486  }
487 
488  bool DoExecute(Args &command, CommandReturnObject &result) override {
489  // No need to check "frame" for validity as eCommandRequiresFrame ensures
490  // it is valid
491  StackFrame *frame = m_exe_ctx.GetFramePtr();
492 
493  Stream &s = result.GetOutputStream();
494 
495  // Be careful about the stack frame, if any summary formatter runs code, it
496  // might clear the StackFrameList for the thread. So hold onto a shared
497  // pointer to the frame so it stays alive.
498 
499  VariableList *variable_list =
500  frame->GetVariableList(m_option_variable.show_globals);
501 
502  VariableSP var_sp;
503  ValueObjectSP valobj_sp;
504 
505  TypeSummaryImplSP summary_format_sp;
506  if (!m_option_variable.summary.IsCurrentValueEmpty())
507  DataVisualization::NamedSummaryFormats::GetSummaryFormat(
508  ConstString(m_option_variable.summary.GetCurrentValue()),
509  summary_format_sp);
510  else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
511  summary_format_sp = std::make_shared<StringSummaryFormat>(
513  m_option_variable.summary_string.GetCurrentValue());
514 
515  DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
517  summary_format_sp));
518 
519  const SymbolContext &sym_ctx =
520  frame->GetSymbolContext(eSymbolContextFunction);
521  if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
522  m_option_variable.show_globals = true;
523 
524  if (variable_list) {
525  const Format format = m_option_format.GetFormat();
526  options.SetFormat(format);
527 
528  if (!command.empty()) {
529  VariableList regex_var_list;
530 
531  // If we have any args to the variable command, we will make variable
532  // objects from them...
533  for (auto &entry : command) {
534  if (m_option_variable.use_regex) {
535  const size_t regex_start_index = regex_var_list.GetSize();
536  llvm::StringRef name_str = entry.ref();
537  RegularExpression regex(name_str);
538  if (regex.IsValid()) {
539  size_t num_matches = 0;
540  const size_t num_new_regex_vars =
541  variable_list->AppendVariablesIfUnique(regex, regex_var_list,
542  num_matches);
543  if (num_new_regex_vars > 0) {
544  for (size_t regex_idx = regex_start_index,
545  end_index = regex_var_list.GetSize();
546  regex_idx < end_index; ++regex_idx) {
547  var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
548  if (var_sp) {
549  valobj_sp = frame->GetValueObjectForFrameVariable(
550  var_sp, m_varobj_options.use_dynamic);
551  if (valobj_sp) {
552  std::string scope_string;
553  if (m_option_variable.show_scope)
554  scope_string = GetScopeString(var_sp).str();
555 
556  if (!scope_string.empty())
557  s.PutCString(scope_string);
558 
559  if (m_option_variable.show_decl &&
560  var_sp->GetDeclaration().GetFile()) {
561  bool show_fullpaths = false;
562  bool show_module = true;
563  if (var_sp->DumpDeclaration(&s, show_fullpaths,
564  show_module))
565  s.PutCString(": ");
566  }
567  valobj_sp->Dump(result.GetOutputStream(), options);
568  }
569  }
570  }
571  } else if (num_matches == 0) {
572  result.GetErrorStream().Printf("error: no variables matched "
573  "the regular expression '%s'.\n",
574  entry.c_str());
575  }
576  } else {
577  if (llvm::Error err = regex.GetError())
578  result.GetErrorStream().Printf(
579  "error: %s\n", llvm::toString(std::move(err)).c_str());
580  else
581  result.GetErrorStream().Printf(
582  "error: unknown regex error when compiling '%s'\n",
583  entry.c_str());
584  }
585  } else // No regex, either exact variable names or variable
586  // expressions.
587  {
588  Status error;
589  uint32_t expr_path_options =
590  StackFrame::eExpressionPathOptionCheckPtrVsMember |
591  StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
592  StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
593  lldb::VariableSP var_sp;
594  valobj_sp = frame->GetValueForVariableExpressionPath(
595  entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
596  var_sp, error);
597  if (valobj_sp) {
598  std::string scope_string;
599  if (m_option_variable.show_scope)
600  scope_string = GetScopeString(var_sp).str();
601 
602  if (!scope_string.empty())
603  s.PutCString(scope_string);
604  if (m_option_variable.show_decl && var_sp &&
605  var_sp->GetDeclaration().GetFile()) {
606  var_sp->GetDeclaration().DumpStopContext(&s, false);
607  s.PutCString(": ");
608  }
609 
610  options.SetFormat(format);
611  options.SetVariableFormatDisplayLanguage(
612  valobj_sp->GetPreferredDisplayLanguage());
613 
614  Stream &output_stream = result.GetOutputStream();
615  options.SetRootValueObjectName(
616  valobj_sp->GetParent() ? entry.c_str() : nullptr);
617  valobj_sp->Dump(output_stream, options);
618  } else {
619  const char *error_cstr = error.AsCString(nullptr);
620  if (error_cstr)
621  result.GetErrorStream().Printf("error: %s\n", error_cstr);
622  else
623  result.GetErrorStream().Printf("error: unable to find any "
624  "variable expression path that "
625  "matches '%s'.\n",
626  entry.c_str());
627  }
628  }
629  }
630  } else // No command arg specified. Use variable_list, instead.
631  {
632  const size_t num_variables = variable_list->GetSize();
633  if (num_variables > 0) {
634  for (size_t i = 0; i < num_variables; i++) {
635  var_sp = variable_list->GetVariableAtIndex(i);
636  switch (var_sp->GetScope()) {
638  if (!m_option_variable.show_globals)
639  continue;
640  break;
642  if (!m_option_variable.show_globals)
643  continue;
644  break;
646  if (!m_option_variable.show_args)
647  continue;
648  break;
650  if (!m_option_variable.show_locals)
651  continue;
652  break;
653  default:
654  continue;
655  break;
656  }
657  std::string scope_string;
658  if (m_option_variable.show_scope)
659  scope_string = GetScopeString(var_sp).str();
660 
661  // Use the variable object code to make sure we are using the same
662  // APIs as the public API will be using...
663  valobj_sp = frame->GetValueObjectForFrameVariable(
664  var_sp, m_varobj_options.use_dynamic);
665  if (valobj_sp) {
666  // When dumping all variables, don't print any variables that are
667  // not in scope to avoid extra unneeded output
668  if (valobj_sp->IsInScope()) {
669  if (!valobj_sp->GetTargetSP()
670  ->GetDisplayRuntimeSupportValues() &&
671  valobj_sp->IsRuntimeSupportValue())
672  continue;
673 
674  if (!scope_string.empty())
675  s.PutCString(scope_string);
676 
677  if (m_option_variable.show_decl &&
678  var_sp->GetDeclaration().GetFile()) {
679  var_sp->GetDeclaration().DumpStopContext(&s, false);
680  s.PutCString(": ");
681  }
682 
683  options.SetFormat(format);
684  options.SetVariableFormatDisplayLanguage(
685  valobj_sp->GetPreferredDisplayLanguage());
686  options.SetRootValueObjectName(
687  var_sp ? var_sp->GetName().AsCString() : nullptr);
688  valobj_sp->Dump(result.GetOutputStream(), options);
689  }
690  }
691  }
692  }
693  }
695  }
696 
697  if (m_option_variable.show_recognized_args) {
698  auto recognized_frame = frame->GetRecognizedFrame();
699  if (recognized_frame) {
700  ValueObjectListSP recognized_arg_list =
701  recognized_frame->GetRecognizedArguments();
702  if (recognized_arg_list) {
703  for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
704  options.SetFormat(m_option_format.GetFormat());
705  options.SetVariableFormatDisplayLanguage(
706  rec_value_sp->GetPreferredDisplayLanguage());
707  options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
708  rec_value_sp->Dump(result.GetOutputStream(), options);
709  }
710  }
711  }
712  }
713 
714  if (m_interpreter.TruncationWarningNecessary()) {
715  result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
716  m_cmd_name.c_str());
717  m_interpreter.TruncationWarningGiven();
718  }
719 
720  // Increment statistics.
721  bool res = result.Succeeded();
722  Target &target = GetSelectedOrDummyTarget();
723  if (res)
725  else
727  return res;
728  }
729 
734 };
735 
736 #pragma mark CommandObjectFrameRecognizer
737 
738 #define LLDB_OPTIONS_frame_recognizer_add
739 #include "CommandOptions.inc"
740 
742 private:
743  class CommandOptions : public Options {
744  public:
746  ~CommandOptions() override = default;
747 
748  Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
749  ExecutionContext *execution_context) override {
750  Status error;
751  const int short_option = m_getopt_table[option_idx].val;
752 
753  switch (short_option) {
754  case 'l':
755  m_class_name = std::string(option_arg);
756  break;
757  case 's':
758  m_module = std::string(option_arg);
759  break;
760  case 'n':
761  m_symbols.push_back(std::string(option_arg));
762  break;
763  case 'x':
764  m_regex = true;
765  break;
766  default:
767  llvm_unreachable("Unimplemented option");
768  }
769 
770  return error;
771  }
772 
773  void OptionParsingStarting(ExecutionContext *execution_context) override {
774  m_module = "";
775  m_symbols.clear();
776  m_class_name = "";
777  m_regex = false;
778  }
779 
780  llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
781  return llvm::makeArrayRef(g_frame_recognizer_add_options);
782  }
783 
784  // Instance variables to hold the values for command options.
785  std::string m_class_name;
786  std::string m_module;
787  std::vector<std::string> m_symbols;
788  bool m_regex;
789  };
790 
792 
793  Options *GetOptions() override { return &m_options; }
794 
795 protected:
796  bool DoExecute(Args &command, CommandReturnObject &result) override;
797 
798 public:
800  : CommandObjectParsed(interpreter, "frame recognizer add",
801  "Add a new frame recognizer.", nullptr),
802  m_options() {
803  SetHelpLong(R"(
804 Frame recognizers allow for retrieving information about special frames based on
805 ABI, arguments or other special properties of that frame, even without source
806 code or debug info. Currently, one use case is to extract function arguments
807 that would otherwise be unaccesible, or augment existing arguments.
808 
809 Adding a custom frame recognizer is possible by implementing a Python class
810 and using the 'frame recognizer add' command. The Python class should have a
811 'get_recognized_arguments' method and it will receive an argument of type
812 lldb.SBFrame representing the current frame that we are trying to recognize.
813 The method should return a (possibly empty) list of lldb.SBValue objects that
814 represent the recognized arguments.
815 
816 An example of a recognizer that retrieves the file descriptor values from libc
817 functions 'read', 'write' and 'close' follows:
818 
819  class LibcFdRecognizer(object):
820  def get_recognized_arguments(self, frame):
821  if frame.name in ["read", "write", "close"]:
822  fd = frame.EvaluateExpression("$arg1").unsigned
823  value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
824  return [value]
825  return []
826 
827 The file containing this implementation can be imported via 'command script
828 import' and then we can register this recognizer with 'frame recognizer add'.
829 It's important to restrict the recognizer to the libc library (which is
830 libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
831 in other modules:
832 
833 (lldb) command script import .../fd_recognizer.py
834 (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
835 
836 When the program is stopped at the beginning of the 'read' function in libc, we
837 can view the recognizer arguments in 'frame variable':
838 
839 (lldb) b read
840 (lldb) r
841 Process 1234 stopped
842 * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
843  frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
844 (lldb) frame variable
845 (int) fd = 3
846 
847  )");
848  }
849  ~CommandObjectFrameRecognizerAdd() override = default;
850 };
851 
853  CommandReturnObject &result) {
854 #if LLDB_ENABLE_PYTHON
855  if (m_options.m_class_name.empty()) {
856  result.AppendErrorWithFormat(
857  "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
859  return false;
860  }
861 
862  if (m_options.m_module.empty()) {
863  result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
864  m_cmd_name.c_str());
866  return false;
867  }
868 
869  if (m_options.m_symbols.empty()) {
870  result.AppendErrorWithFormat(
871  "%s needs at least one symbol name (-n argument).\n",
872  m_cmd_name.c_str());
874  return false;
875  }
876 
877  if (m_options.m_regex && m_options.m_symbols.size() > 1) {
878  result.AppendErrorWithFormat(
879  "%s needs only one symbol regular expression (-n argument).\n",
880  m_cmd_name.c_str());
882  return false;
883  }
884 
885  ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
886 
887  if (interpreter &&
888  !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
889  result.AppendWarning("The provided class does not exist - please define it "
890  "before attempting to use this frame recognizer");
891  }
892 
893  StackFrameRecognizerSP recognizer_sp =
894  StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
895  interpreter, m_options.m_class_name.c_str()));
896  if (m_options.m_regex) {
897  auto module =
898  RegularExpressionSP(new RegularExpression(m_options.m_module));
899  auto func =
900  RegularExpressionSP(new RegularExpression(m_options.m_symbols.front()));
901  StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
902  } else {
903  auto module = ConstString(m_options.m_module);
904  std::vector<ConstString> symbols(m_options.m_symbols.begin(),
905  m_options.m_symbols.end());
906  StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, symbols);
907  }
908 #endif
909 
911  return result.Succeeded();
912 }
913 
915 public:
917  : CommandObjectParsed(interpreter, "frame recognizer clear",
918  "Delete all frame recognizers.", nullptr) {}
919 
920  ~CommandObjectFrameRecognizerClear() override = default;
921 
922 protected:
923  bool DoExecute(Args &command, CommandReturnObject &result) override {
924  StackFrameRecognizerManager::RemoveAllRecognizers();
926  return result.Succeeded();
927  }
928 };
929 
931 public:
933  : CommandObjectParsed(interpreter, "frame recognizer delete",
934  "Delete an existing frame recognizer.", nullptr) {}
935 
936  ~CommandObjectFrameRecognizerDelete() override = default;
937 
938  void
940  OptionElementVector &opt_element_vector) override {
941  if (request.GetCursorIndex() != 0)
942  return;
943 
944  StackFrameRecognizerManager::ForEach(
945  [&request](uint32_t rid, std::string rname, std::string module,
946  llvm::ArrayRef<lldb_private::ConstString> symbols,
947  bool regexp) {
948  StreamString strm;
949  if (rname.empty())
950  rname = "(internal)";
951 
952  strm << rname;
953  if (!module.empty())
954  strm << ", module " << module;
955  if (!symbols.empty())
956  for (auto &symbol : symbols)
957  strm << ", symbol " << symbol;
958  if (regexp)
959  strm << " (regexp)";
960 
961  request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
962  });
963  }
964 
965 protected:
966  bool DoExecute(Args &command, CommandReturnObject &result) override {
967  if (command.GetArgumentCount() == 0) {
968  if (!m_interpreter.Confirm(
969  "About to delete all frame recognizers, do you want to do that?",
970  true)) {
971  result.AppendMessage("Operation cancelled...");
973  return false;
974  }
975 
976  StackFrameRecognizerManager::RemoveAllRecognizers();
978  return result.Succeeded();
979  }
980 
981  if (command.GetArgumentCount() != 1) {
982  result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
983  m_cmd_name.c_str());
985  return false;
986  }
987 
988  uint32_t recognizer_id;
989  if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
990  result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
991  command.GetArgumentAtIndex(0));
993  return false;
994  }
995 
996  StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
998  return result.Succeeded();
999  }
1000 };
1001 
1003 public:
1005  : CommandObjectParsed(interpreter, "frame recognizer list",
1006  "Show a list of active frame recognizers.",
1007  nullptr) {}
1008 
1009  ~CommandObjectFrameRecognizerList() override = default;
1010 
1011 protected:
1012  bool DoExecute(Args &command, CommandReturnObject &result) override {
1013  bool any_printed = false;
1014  StackFrameRecognizerManager::ForEach(
1015  [&result, &any_printed](
1016  uint32_t recognizer_id, std::string name, std::string module,
1017  llvm::ArrayRef<ConstString> symbols, bool regexp) {
1018  Stream &stream = result.GetOutputStream();
1019 
1020  if (name.empty())
1021  name = "(internal)";
1022 
1023  stream << std::to_string(recognizer_id) << ": " << name;
1024  if (!module.empty())
1025  stream << ", module " << module;
1026  if (!symbols.empty())
1027  for (auto &symbol : symbols)
1028  stream << ", symbol " << symbol;
1029  if (regexp)
1030  stream << " (regexp)";
1031 
1032  stream.EOL();
1033  stream.Flush();
1034 
1035  any_printed = true;
1036  });
1037 
1038  if (any_printed)
1040  else {
1041  result.GetOutputStream().PutCString("no matching results found.\n");
1043  }
1044  return result.Succeeded();
1045  }
1046 };
1047 
1049 public:
1052  interpreter, "frame recognizer info",
1053  "Show which frame recognizer is applied a stack frame (if any).",
1054  nullptr) {
1056  CommandArgumentData index_arg;
1057 
1058  // Define the first (and only) variant of this arg.
1059  index_arg.arg_type = eArgTypeFrameIndex;
1060  index_arg.arg_repetition = eArgRepeatPlain;
1061 
1062  // There is only one variant this argument could be; put it into the
1063  // argument entry.
1064  arg.push_back(index_arg);
1065 
1066  // Push the data for the first argument into the m_arguments vector.
1067  m_arguments.push_back(arg);
1068  }
1069 
1070  ~CommandObjectFrameRecognizerInfo() override = default;
1071 
1072 protected:
1073  bool DoExecute(Args &command, CommandReturnObject &result) override {
1074  const char *frame_index_str = command.GetArgumentAtIndex(0);
1075  uint32_t frame_index;
1076  if (!llvm::to_integer(frame_index_str, frame_index)) {
1077  result.AppendErrorWithFormat("'%s' is not a valid frame index.",
1078  frame_index_str);
1080  return false;
1081  }
1082 
1083  Process *process = m_exe_ctx.GetProcessPtr();
1084  if (process == nullptr) {
1085  result.AppendError("no process");
1087  return false;
1088  }
1089  Thread *thread = m_exe_ctx.GetThreadPtr();
1090  if (thread == nullptr) {
1091  result.AppendError("no thread");
1093  return false;
1094  }
1095  if (command.GetArgumentCount() != 1) {
1096  result.AppendErrorWithFormat(
1097  "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1099  return false;
1100  }
1101 
1102  StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1103  if (!frame_sp) {
1104  result.AppendErrorWithFormat("no frame with index %u", frame_index);
1106  return false;
1107  }
1108 
1109  auto recognizer =
1110  StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
1111 
1112  Stream &output_stream = result.GetOutputStream();
1113  output_stream.Printf("frame %d ", frame_index);
1114  if (recognizer) {
1115  output_stream << "is recognized by ";
1116  output_stream << recognizer->GetName();
1117  } else {
1118  output_stream << "not recognized by any recognizer";
1119  }
1120  output_stream.EOL();
1122  return result.Succeeded();
1123  }
1124 };
1125 
1127 public:
1130  interpreter, "frame recognizer",
1131  "Commands for editing and viewing frame recognizers.",
1132  "frame recognizer [<sub-command-options>] ") {
1133  LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1134  interpreter)));
1135  LoadSubCommand(
1136  "clear",
1137  CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
1138  LoadSubCommand(
1139  "delete",
1140  CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1141  LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1142  interpreter)));
1143  LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1144  interpreter)));
1145  }
1146 
1147  ~CommandObjectFrameRecognizer() override = default;
1148 };
1149 
1150 #pragma mark CommandObjectMultiwordFrame
1151 
1152 // CommandObjectMultiwordFrame
1153 
1154 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1155  CommandInterpreter &interpreter)
1156  : CommandObjectMultiword(interpreter, "frame",
1157  "Commands for selecting and "
1158  "examing the current "
1159  "thread's stack frames.",
1160  "frame <subcommand> [<subcommand-options>]") {
1161  LoadSubCommand("diagnose",
1162  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1163  LoadSubCommand("info",
1164  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1165  LoadSubCommand("select",
1166  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1167  LoadSubCommand("variable",
1168  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
1169 #if LLDB_ENABLE_PYTHON
1170  LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1171  interpreter)));
1172 #endif
1173 }
1174 
void OptionParsingStarting(ExecutionContext *execution_context) override
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:63
std::vector< CommandArgumentData > CommandArgumentEntry
A command line argument class.
Definition: Args.h:33
lldb::StackFrameSP GetSelectedFrame()
Definition: Thread.cpp:270
bool empty() const
Definition: Args.h:118
A class that represents a running process on the host machine.
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
virtual bool CheckObjectExists(const char *name)
Defines a symbol context baton that can be handed other debug core functions.
Definition: SymbolContext.h:33
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
llvm::Error Error
bool DoExecute(Args &command, CommandReturnObject &result) override
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.cpp:254
uint32_t GetSelectedFrameIndex()
Definition: Thread.h:430
CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
virtual void Flush()=0
Flush the stream.
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
bool DoExecute(Args &command, CommandReturnObject &result) override
VariableList * GetVariableList(bool get_file_globals)
Retrieve the list of variables that are in scope at this StackFrame&#39;s pc.
Definition: StackFrame.cpp:421
CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
Format
Display format definitions.
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx. ...
Definition: Args.cpp:256
bool DoExecute(Args &command, CommandReturnObject &result) override
lldb::ValueObjectSP GetValueForVariableExpressionPath(llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic, uint32_t options, lldb::VariableSP &var_sp, Status &error)
Create a ValueObject for a variable name / pathname, possibly including simple dereference/child sele...
Definition: StackFrame.cpp:493
CommandObjectFrameVariable(CommandInterpreter &interpreter)
const SymbolContext & GetSymbolContext(lldb::SymbolContextItem resolve_scope)
Provide a SymbolContext for this StackFrame&#39;s current pc value.
Definition: StackFrame.cpp:274
"lldb/Utility/ArgCompletionRequest.h"
bool DoExecute(Args &command, CommandReturnObject &result) override
void IncrementStats(lldb_private::StatisticKind key)
Definition: Target.h:1342
void OptionParsingStarting(ExecutionContext *execution_context) override
std::vector< OptionArgElement > OptionElementVector
Definition: Options.h:41
#define UINT32_MAX
Definition: lldb-defines.h:31
lldb::VariableSP GetVariableAtIndex(size_t idx) const
bool DoExecute(Args &command, CommandReturnObject &result) override
bool IsValid() const
Test if this object contains a valid regular expression.
void AppendWarning(llvm::StringRef in_string)
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
llvm::StringRef toString(Record::Kind K)
Options * GetOptions() override
static llvm::raw_ostream & error(Stream &strm)
CommandObjectFrameSelect(CommandInterpreter &interpreter)
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:128
bool SetSelectedFrameByIndexNoisily(uint32_t frame_idx, Stream &output_stream)
Definition: Thread.cpp:299
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
size_t AppendVariablesIfUnique(VariableList &var_list)
void AppendMessage(llvm::StringRef in_string)
CommandObjectFrameInfo(CommandInterpreter &interpreter)
llvm::StringRef GetString() const
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
llvm::Error GetError() const
Return an error if the regular expression failed to compile.
A plug-in interface definition class for debugging a process.
Definition: Process.h:362
DumpValueObjectOptions & SetDeclPrintingHelper(DeclPrintingHelper helper)
Options * GetOptions() override
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
void OptionParsingStarting(ExecutionContext *execution_context) override
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
function argument variables
CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
Options * GetOptions() override
Python implementation for frame recognizers.
A command line option parsing protocol class.
Definition: Options.h:62
function local variables
void void AppendError(llvm::StringRef in_string)
bool DoExecute(Args &command, CommandReturnObject &result) override
A uniqued constant string class.
Definition: ConstString.h:40
bool DoExecute(Args &command, CommandReturnObject &result) override
OptionGroupValueObjectDisplay m_varobj_options
Definition: SBAddress.h:15
thread local storage variable
bool DoExecute(Args &command, CommandReturnObject &result) override
void TryCompleteCurrentArg(llvm::StringRef completion, llvm::StringRef description="")
Adds a possible completion string if the completion would complete the current argument.
#define LLDB_OPT_SET_ALL
Definition: lldb-defines.h:110
std::function< bool(ConstString, ConstString, const DumpValueObjectOptions &, Stream &)> DeclPrintingHelper
int SetErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Set the current error string to a formatted error string.
Definition: Status.cpp:256
bool DoExecute(Args &command, CommandReturnObject &result) override
#define LLDB_OPT_SET_1
Definition: lldb-defines.h:111
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition: Status.cpp:131
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:398
virtual uint32_t GetStackFrameCount()
Definition: Thread.h:394
CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
lldb::ValueObjectSP GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic)
Create a ValueObject for a given Variable in this StackFrame.
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
OptionGroupVariable m_option_variable
lldb::StopInfoSP GetStopInfo()
Definition: Thread.cpp:339
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
lldb::RecognizedStackFrameSP GetRecognizedFrame()
void SetStatus(lldb::ReturnStatus status)
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
This base class provides an interface to stack frames.
Definition: StackFrame.h:40
llvm::StringRef GetScopeString(VariableSP var_sp)
An error handling class.
Definition: Status.h:44