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