1*dda28197Spatrick //===-- CommandObjectFrame.cpp --------------------------------------------===// 2061da546Spatrick // 3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6061da546Spatrick // 7061da546Spatrick //===----------------------------------------------------------------------===// 8061da546Spatrick #include "CommandObjectFrame.h" 9061da546Spatrick #include "lldb/Core/Debugger.h" 10061da546Spatrick #include "lldb/Core/ValueObject.h" 11061da546Spatrick #include "lldb/DataFormatters/DataVisualization.h" 12061da546Spatrick #include "lldb/DataFormatters/ValueObjectPrinter.h" 13061da546Spatrick #include "lldb/Host/Config.h" 14061da546Spatrick #include "lldb/Host/OptionParser.h" 15061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h" 16061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h" 17061da546Spatrick #include "lldb/Interpreter/OptionGroupFormat.h" 18061da546Spatrick #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" 19061da546Spatrick #include "lldb/Interpreter/OptionGroupVariable.h" 20061da546Spatrick #include "lldb/Interpreter/Options.h" 21061da546Spatrick #include "lldb/Symbol/Function.h" 22061da546Spatrick #include "lldb/Symbol/SymbolContext.h" 23061da546Spatrick #include "lldb/Symbol/Variable.h" 24061da546Spatrick #include "lldb/Symbol/VariableList.h" 25061da546Spatrick #include "lldb/Target/StackFrame.h" 26061da546Spatrick #include "lldb/Target/StackFrameRecognizer.h" 27061da546Spatrick #include "lldb/Target/StopInfo.h" 28061da546Spatrick #include "lldb/Target/Target.h" 29061da546Spatrick #include "lldb/Target/Thread.h" 30061da546Spatrick #include "lldb/Utility/Args.h" 31061da546Spatrick 32061da546Spatrick #include <memory> 33061da546Spatrick #include <string> 34061da546Spatrick 35061da546Spatrick using namespace lldb; 36061da546Spatrick using namespace lldb_private; 37061da546Spatrick 38061da546Spatrick #pragma mark CommandObjectFrameDiagnose 39061da546Spatrick 40061da546Spatrick // CommandObjectFrameInfo 41061da546Spatrick 42061da546Spatrick // CommandObjectFrameDiagnose 43061da546Spatrick 44061da546Spatrick #define LLDB_OPTIONS_frame_diag 45061da546Spatrick #include "CommandOptions.inc" 46061da546Spatrick 47061da546Spatrick class CommandObjectFrameDiagnose : public CommandObjectParsed { 48061da546Spatrick public: 49061da546Spatrick class CommandOptions : public Options { 50061da546Spatrick public: 51061da546Spatrick CommandOptions() : Options() { OptionParsingStarting(nullptr); } 52061da546Spatrick 53061da546Spatrick ~CommandOptions() override = default; 54061da546Spatrick 55061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 56061da546Spatrick ExecutionContext *execution_context) override { 57061da546Spatrick Status error; 58061da546Spatrick const int short_option = m_getopt_table[option_idx].val; 59061da546Spatrick switch (short_option) { 60061da546Spatrick case 'r': 61061da546Spatrick reg = ConstString(option_arg); 62061da546Spatrick break; 63061da546Spatrick 64061da546Spatrick case 'a': { 65061da546Spatrick address.emplace(); 66061da546Spatrick if (option_arg.getAsInteger(0, *address)) { 67061da546Spatrick address.reset(); 68061da546Spatrick error.SetErrorStringWithFormat("invalid address argument '%s'", 69061da546Spatrick option_arg.str().c_str()); 70061da546Spatrick } 71061da546Spatrick } break; 72061da546Spatrick 73061da546Spatrick case 'o': { 74061da546Spatrick offset.emplace(); 75061da546Spatrick if (option_arg.getAsInteger(0, *offset)) { 76061da546Spatrick offset.reset(); 77061da546Spatrick error.SetErrorStringWithFormat("invalid offset argument '%s'", 78061da546Spatrick option_arg.str().c_str()); 79061da546Spatrick } 80061da546Spatrick } break; 81061da546Spatrick 82061da546Spatrick default: 83061da546Spatrick llvm_unreachable("Unimplemented option"); 84061da546Spatrick } 85061da546Spatrick 86061da546Spatrick return error; 87061da546Spatrick } 88061da546Spatrick 89061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override { 90061da546Spatrick address.reset(); 91061da546Spatrick reg.reset(); 92061da546Spatrick offset.reset(); 93061da546Spatrick } 94061da546Spatrick 95061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 96061da546Spatrick return llvm::makeArrayRef(g_frame_diag_options); 97061da546Spatrick } 98061da546Spatrick 99061da546Spatrick // Options. 100061da546Spatrick llvm::Optional<lldb::addr_t> address; 101061da546Spatrick llvm::Optional<ConstString> reg; 102061da546Spatrick llvm::Optional<int64_t> offset; 103061da546Spatrick }; 104061da546Spatrick 105061da546Spatrick CommandObjectFrameDiagnose(CommandInterpreter &interpreter) 106061da546Spatrick : CommandObjectParsed(interpreter, "frame diagnose", 107061da546Spatrick "Try to determine what path path the current stop " 108061da546Spatrick "location used to get to a register or address", 109061da546Spatrick nullptr, 110061da546Spatrick eCommandRequiresThread | eCommandTryTargetAPILock | 111061da546Spatrick eCommandProcessMustBeLaunched | 112061da546Spatrick eCommandProcessMustBePaused), 113061da546Spatrick m_options() { 114061da546Spatrick CommandArgumentEntry arg; 115061da546Spatrick CommandArgumentData index_arg; 116061da546Spatrick 117061da546Spatrick // Define the first (and only) variant of this arg. 118061da546Spatrick index_arg.arg_type = eArgTypeFrameIndex; 119061da546Spatrick index_arg.arg_repetition = eArgRepeatOptional; 120061da546Spatrick 121061da546Spatrick // There is only one variant this argument could be; put it into the 122061da546Spatrick // argument entry. 123061da546Spatrick arg.push_back(index_arg); 124061da546Spatrick 125061da546Spatrick // Push the data for the first argument into the m_arguments vector. 126061da546Spatrick m_arguments.push_back(arg); 127061da546Spatrick } 128061da546Spatrick 129061da546Spatrick ~CommandObjectFrameDiagnose() override = default; 130061da546Spatrick 131061da546Spatrick Options *GetOptions() override { return &m_options; } 132061da546Spatrick 133061da546Spatrick protected: 134061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override { 135061da546Spatrick Thread *thread = m_exe_ctx.GetThreadPtr(); 136061da546Spatrick StackFrameSP frame_sp = thread->GetSelectedFrame(); 137061da546Spatrick 138061da546Spatrick ValueObjectSP valobj_sp; 139061da546Spatrick 140061da546Spatrick if (m_options.address.hasValue()) { 141061da546Spatrick if (m_options.reg.hasValue() || m_options.offset.hasValue()) { 142061da546Spatrick result.AppendError( 143061da546Spatrick "`frame diagnose --address` is incompatible with other arguments."); 144061da546Spatrick result.SetStatus(eReturnStatusFailed); 145061da546Spatrick return false; 146061da546Spatrick } 147061da546Spatrick valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue()); 148061da546Spatrick } else if (m_options.reg.hasValue()) { 149061da546Spatrick valobj_sp = frame_sp->GuessValueForRegisterAndOffset( 150061da546Spatrick m_options.reg.getValue(), m_options.offset.getValueOr(0)); 151061da546Spatrick } else { 152061da546Spatrick StopInfoSP stop_info_sp = thread->GetStopInfo(); 153061da546Spatrick if (!stop_info_sp) { 154061da546Spatrick result.AppendError("No arguments provided, and no stop info."); 155061da546Spatrick result.SetStatus(eReturnStatusFailed); 156061da546Spatrick return false; 157061da546Spatrick } 158061da546Spatrick 159061da546Spatrick valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp); 160061da546Spatrick } 161061da546Spatrick 162061da546Spatrick if (!valobj_sp) { 163061da546Spatrick result.AppendError("No diagnosis available."); 164061da546Spatrick result.SetStatus(eReturnStatusFailed); 165061da546Spatrick return false; 166061da546Spatrick } 167061da546Spatrick 168061da546Spatrick DumpValueObjectOptions::DeclPrintingHelper helper = 169061da546Spatrick [&valobj_sp](ConstString type, ConstString var, 170061da546Spatrick const DumpValueObjectOptions &opts, 171061da546Spatrick Stream &stream) -> bool { 172061da546Spatrick const ValueObject::GetExpressionPathFormat format = ValueObject:: 173061da546Spatrick GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers; 174*dda28197Spatrick valobj_sp->GetExpressionPath(stream, format); 175061da546Spatrick stream.PutCString(" ="); 176061da546Spatrick return true; 177061da546Spatrick }; 178061da546Spatrick 179061da546Spatrick DumpValueObjectOptions options; 180061da546Spatrick options.SetDeclPrintingHelper(helper); 181061da546Spatrick ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(), 182061da546Spatrick options); 183061da546Spatrick printer.PrintValueObject(); 184061da546Spatrick 185061da546Spatrick return true; 186061da546Spatrick } 187061da546Spatrick 188061da546Spatrick CommandOptions m_options; 189061da546Spatrick }; 190061da546Spatrick 191061da546Spatrick #pragma mark CommandObjectFrameInfo 192061da546Spatrick 193061da546Spatrick // CommandObjectFrameInfo 194061da546Spatrick 195061da546Spatrick class CommandObjectFrameInfo : public CommandObjectParsed { 196061da546Spatrick public: 197061da546Spatrick CommandObjectFrameInfo(CommandInterpreter &interpreter) 198061da546Spatrick : CommandObjectParsed(interpreter, "frame info", 199061da546Spatrick "List information about the current " 200061da546Spatrick "stack frame in the current thread.", 201061da546Spatrick "frame info", 202061da546Spatrick eCommandRequiresFrame | eCommandTryTargetAPILock | 203061da546Spatrick eCommandProcessMustBeLaunched | 204061da546Spatrick eCommandProcessMustBePaused) {} 205061da546Spatrick 206061da546Spatrick ~CommandObjectFrameInfo() override = default; 207061da546Spatrick 208061da546Spatrick protected: 209061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override { 210061da546Spatrick m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream()); 211061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult); 212061da546Spatrick return result.Succeeded(); 213061da546Spatrick } 214061da546Spatrick }; 215061da546Spatrick 216061da546Spatrick #pragma mark CommandObjectFrameSelect 217061da546Spatrick 218061da546Spatrick // CommandObjectFrameSelect 219061da546Spatrick 220061da546Spatrick #define LLDB_OPTIONS_frame_select 221061da546Spatrick #include "CommandOptions.inc" 222061da546Spatrick 223061da546Spatrick class CommandObjectFrameSelect : public CommandObjectParsed { 224061da546Spatrick public: 225061da546Spatrick class CommandOptions : public Options { 226061da546Spatrick public: 227061da546Spatrick CommandOptions() : Options() { OptionParsingStarting(nullptr); } 228061da546Spatrick 229061da546Spatrick ~CommandOptions() override = default; 230061da546Spatrick 231061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 232061da546Spatrick ExecutionContext *execution_context) override { 233061da546Spatrick Status error; 234061da546Spatrick const int short_option = m_getopt_table[option_idx].val; 235061da546Spatrick switch (short_option) { 236061da546Spatrick case 'r': { 237061da546Spatrick int32_t offset = 0; 238061da546Spatrick if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) { 239061da546Spatrick error.SetErrorStringWithFormat("invalid frame offset argument '%s'", 240061da546Spatrick option_arg.str().c_str()); 241061da546Spatrick } else 242061da546Spatrick relative_frame_offset = offset; 243061da546Spatrick break; 244061da546Spatrick } 245061da546Spatrick 246061da546Spatrick default: 247061da546Spatrick llvm_unreachable("Unimplemented option"); 248061da546Spatrick } 249061da546Spatrick 250061da546Spatrick return error; 251061da546Spatrick } 252061da546Spatrick 253061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override { 254061da546Spatrick relative_frame_offset.reset(); 255061da546Spatrick } 256061da546Spatrick 257061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 258061da546Spatrick return llvm::makeArrayRef(g_frame_select_options); 259061da546Spatrick } 260061da546Spatrick 261061da546Spatrick llvm::Optional<int32_t> relative_frame_offset; 262061da546Spatrick }; 263061da546Spatrick 264061da546Spatrick CommandObjectFrameSelect(CommandInterpreter &interpreter) 265061da546Spatrick : CommandObjectParsed(interpreter, "frame select", 266061da546Spatrick "Select the current stack frame by " 267061da546Spatrick "index from within the current thread " 268061da546Spatrick "(see 'thread backtrace'.)", 269061da546Spatrick nullptr, 270061da546Spatrick eCommandRequiresThread | eCommandTryTargetAPILock | 271061da546Spatrick eCommandProcessMustBeLaunched | 272061da546Spatrick eCommandProcessMustBePaused), 273061da546Spatrick m_options() { 274061da546Spatrick CommandArgumentEntry arg; 275061da546Spatrick CommandArgumentData index_arg; 276061da546Spatrick 277061da546Spatrick // Define the first (and only) variant of this arg. 278061da546Spatrick index_arg.arg_type = eArgTypeFrameIndex; 279061da546Spatrick index_arg.arg_repetition = eArgRepeatOptional; 280061da546Spatrick 281061da546Spatrick // There is only one variant this argument could be; put it into the 282061da546Spatrick // argument entry. 283061da546Spatrick arg.push_back(index_arg); 284061da546Spatrick 285061da546Spatrick // Push the data for the first argument into the m_arguments vector. 286061da546Spatrick m_arguments.push_back(arg); 287061da546Spatrick } 288061da546Spatrick 289061da546Spatrick ~CommandObjectFrameSelect() override = default; 290061da546Spatrick 291*dda28197Spatrick void 292*dda28197Spatrick HandleArgumentCompletion(CompletionRequest &request, 293*dda28197Spatrick OptionElementVector &opt_element_vector) override { 294*dda28197Spatrick if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0) 295*dda28197Spatrick return; 296*dda28197Spatrick 297*dda28197Spatrick lldb::ThreadSP thread_sp = m_exe_ctx.GetThreadSP(); 298*dda28197Spatrick const uint32_t frame_num = thread_sp->GetStackFrameCount(); 299*dda28197Spatrick for (uint32_t i = 0; i < frame_num; ++i) { 300*dda28197Spatrick lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i); 301*dda28197Spatrick StreamString strm; 302*dda28197Spatrick frame_sp->Dump(&strm, false, true); 303*dda28197Spatrick request.TryCompleteCurrentArg(std::to_string(i), strm.GetString()); 304*dda28197Spatrick } 305*dda28197Spatrick } 306*dda28197Spatrick 307061da546Spatrick Options *GetOptions() override { return &m_options; } 308061da546Spatrick 309061da546Spatrick protected: 310061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override { 311061da546Spatrick // No need to check "thread" for validity as eCommandRequiresThread ensures 312061da546Spatrick // it is valid 313061da546Spatrick Thread *thread = m_exe_ctx.GetThreadPtr(); 314061da546Spatrick 315061da546Spatrick uint32_t frame_idx = UINT32_MAX; 316061da546Spatrick if (m_options.relative_frame_offset.hasValue()) { 317061da546Spatrick // The one and only argument is a signed relative frame index 318061da546Spatrick frame_idx = thread->GetSelectedFrameIndex(); 319061da546Spatrick if (frame_idx == UINT32_MAX) 320061da546Spatrick frame_idx = 0; 321061da546Spatrick 322061da546Spatrick if (*m_options.relative_frame_offset < 0) { 323061da546Spatrick if (static_cast<int32_t>(frame_idx) >= 324061da546Spatrick -*m_options.relative_frame_offset) 325061da546Spatrick frame_idx += *m_options.relative_frame_offset; 326061da546Spatrick else { 327061da546Spatrick if (frame_idx == 0) { 328061da546Spatrick // If you are already at the bottom of the stack, then just warn 329061da546Spatrick // and don't reset the frame. 330061da546Spatrick result.AppendError("Already at the bottom of the stack."); 331061da546Spatrick result.SetStatus(eReturnStatusFailed); 332061da546Spatrick return false; 333061da546Spatrick } else 334061da546Spatrick frame_idx = 0; 335061da546Spatrick } 336061da546Spatrick } else if (*m_options.relative_frame_offset > 0) { 337061da546Spatrick // I don't want "up 20" where "20" takes you past the top of the stack 338061da546Spatrick // to produce 339061da546Spatrick // an error, but rather to just go to the top. So I have to count the 340061da546Spatrick // stack here... 341061da546Spatrick const uint32_t num_frames = thread->GetStackFrameCount(); 342061da546Spatrick if (static_cast<int32_t>(num_frames - frame_idx) > 343061da546Spatrick *m_options.relative_frame_offset) 344061da546Spatrick frame_idx += *m_options.relative_frame_offset; 345061da546Spatrick else { 346061da546Spatrick if (frame_idx == num_frames - 1) { 347061da546Spatrick // If we are already at the top of the stack, just warn and don't 348061da546Spatrick // reset the frame. 349061da546Spatrick result.AppendError("Already at the top of the stack."); 350061da546Spatrick result.SetStatus(eReturnStatusFailed); 351061da546Spatrick return false; 352061da546Spatrick } else 353061da546Spatrick frame_idx = num_frames - 1; 354061da546Spatrick } 355061da546Spatrick } 356061da546Spatrick } else { 357061da546Spatrick if (command.GetArgumentCount() > 1) { 358061da546Spatrick result.AppendErrorWithFormat( 359061da546Spatrick "too many arguments; expected frame-index, saw '%s'.\n", 360061da546Spatrick command[0].c_str()); 361061da546Spatrick m_options.GenerateOptionUsage( 362061da546Spatrick result.GetErrorStream(), this, 363061da546Spatrick GetCommandInterpreter().GetDebugger().GetTerminalWidth()); 364061da546Spatrick return false; 365061da546Spatrick } 366061da546Spatrick 367061da546Spatrick if (command.GetArgumentCount() == 1) { 368061da546Spatrick if (command[0].ref().getAsInteger(0, frame_idx)) { 369061da546Spatrick result.AppendErrorWithFormat("invalid frame index argument '%s'.", 370061da546Spatrick command[0].c_str()); 371061da546Spatrick result.SetStatus(eReturnStatusFailed); 372061da546Spatrick return false; 373061da546Spatrick } 374061da546Spatrick } else if (command.GetArgumentCount() == 0) { 375061da546Spatrick frame_idx = thread->GetSelectedFrameIndex(); 376061da546Spatrick if (frame_idx == UINT32_MAX) { 377061da546Spatrick frame_idx = 0; 378061da546Spatrick } 379061da546Spatrick } 380061da546Spatrick } 381061da546Spatrick 382061da546Spatrick bool success = thread->SetSelectedFrameByIndexNoisily( 383061da546Spatrick frame_idx, result.GetOutputStream()); 384061da546Spatrick if (success) { 385061da546Spatrick m_exe_ctx.SetFrameSP(thread->GetSelectedFrame()); 386061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult); 387061da546Spatrick } else { 388061da546Spatrick result.AppendErrorWithFormat("Frame index (%u) out of range.\n", 389061da546Spatrick frame_idx); 390061da546Spatrick result.SetStatus(eReturnStatusFailed); 391061da546Spatrick } 392061da546Spatrick 393061da546Spatrick return result.Succeeded(); 394061da546Spatrick } 395061da546Spatrick 396061da546Spatrick CommandOptions m_options; 397061da546Spatrick }; 398061da546Spatrick 399061da546Spatrick #pragma mark CommandObjectFrameVariable 400061da546Spatrick // List images with associated information 401061da546Spatrick class CommandObjectFrameVariable : public CommandObjectParsed { 402061da546Spatrick public: 403061da546Spatrick CommandObjectFrameVariable(CommandInterpreter &interpreter) 404061da546Spatrick : CommandObjectParsed( 405061da546Spatrick interpreter, "frame variable", 406061da546Spatrick "Show variables for the current stack frame. Defaults to all " 407061da546Spatrick "arguments and local variables in scope. Names of argument, " 408061da546Spatrick "local, file static and file global variables can be specified. " 409061da546Spatrick "Children of aggregate variables can be specified such as " 410061da546Spatrick "'var->child.x'. The -> and [] operators in 'frame variable' do " 411061da546Spatrick "not invoke operator overloads if they exist, but directly access " 412061da546Spatrick "the specified element. If you want to trigger operator overloads " 413061da546Spatrick "use the expression command to print the variable instead." 414061da546Spatrick "\nIt is worth noting that except for overloaded " 415061da546Spatrick "operators, when printing local variables 'expr local_var' and " 416061da546Spatrick "'frame var local_var' produce the same " 417061da546Spatrick "results. However, 'frame variable' is more efficient, since it " 418061da546Spatrick "uses debug information and memory reads directly, rather than " 419061da546Spatrick "parsing and evaluating an expression, which may even involve " 420061da546Spatrick "JITing and running code in the target program.", 421061da546Spatrick nullptr, 422061da546Spatrick eCommandRequiresFrame | eCommandTryTargetAPILock | 423061da546Spatrick eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | 424061da546Spatrick eCommandRequiresProcess), 425061da546Spatrick m_option_group(), 426061da546Spatrick m_option_variable( 427061da546Spatrick true), // Include the frame specific options by passing "true" 428061da546Spatrick m_option_format(eFormatDefault), m_varobj_options() { 429061da546Spatrick CommandArgumentEntry arg; 430061da546Spatrick CommandArgumentData var_name_arg; 431061da546Spatrick 432061da546Spatrick // Define the first (and only) variant of this arg. 433061da546Spatrick var_name_arg.arg_type = eArgTypeVarName; 434061da546Spatrick var_name_arg.arg_repetition = eArgRepeatStar; 435061da546Spatrick 436061da546Spatrick // There is only one variant this argument could be; put it into the 437061da546Spatrick // argument entry. 438061da546Spatrick arg.push_back(var_name_arg); 439061da546Spatrick 440061da546Spatrick // Push the data for the first argument into the m_arguments vector. 441061da546Spatrick m_arguments.push_back(arg); 442061da546Spatrick 443061da546Spatrick m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 444061da546Spatrick m_option_group.Append(&m_option_format, 445061da546Spatrick OptionGroupFormat::OPTION_GROUP_FORMAT | 446061da546Spatrick OptionGroupFormat::OPTION_GROUP_GDB_FMT, 447061da546Spatrick LLDB_OPT_SET_1); 448061da546Spatrick m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 449061da546Spatrick m_option_group.Finalize(); 450061da546Spatrick } 451061da546Spatrick 452061da546Spatrick ~CommandObjectFrameVariable() override = default; 453061da546Spatrick 454061da546Spatrick Options *GetOptions() override { return &m_option_group; } 455061da546Spatrick 456061da546Spatrick void 457061da546Spatrick HandleArgumentCompletion(CompletionRequest &request, 458061da546Spatrick OptionElementVector &opt_element_vector) override { 459061da546Spatrick // Arguments are the standard source file completer. 460061da546Spatrick CommandCompletions::InvokeCommonCompletionCallbacks( 461061da546Spatrick GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, 462061da546Spatrick request, nullptr); 463061da546Spatrick } 464061da546Spatrick 465061da546Spatrick protected: 466061da546Spatrick llvm::StringRef GetScopeString(VariableSP var_sp) { 467061da546Spatrick if (!var_sp) 468061da546Spatrick return llvm::StringRef::withNullAsEmpty(nullptr); 469061da546Spatrick 470061da546Spatrick switch (var_sp->GetScope()) { 471061da546Spatrick case eValueTypeVariableGlobal: 472061da546Spatrick return "GLOBAL: "; 473061da546Spatrick case eValueTypeVariableStatic: 474061da546Spatrick return "STATIC: "; 475061da546Spatrick case eValueTypeVariableArgument: 476061da546Spatrick return "ARG: "; 477061da546Spatrick case eValueTypeVariableLocal: 478061da546Spatrick return "LOCAL: "; 479061da546Spatrick case eValueTypeVariableThreadLocal: 480061da546Spatrick return "THREAD: "; 481061da546Spatrick default: 482061da546Spatrick break; 483061da546Spatrick } 484061da546Spatrick 485061da546Spatrick return llvm::StringRef::withNullAsEmpty(nullptr); 486061da546Spatrick } 487061da546Spatrick 488061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override { 489061da546Spatrick // No need to check "frame" for validity as eCommandRequiresFrame ensures 490061da546Spatrick // it is valid 491061da546Spatrick StackFrame *frame = m_exe_ctx.GetFramePtr(); 492061da546Spatrick 493061da546Spatrick Stream &s = result.GetOutputStream(); 494061da546Spatrick 495061da546Spatrick // Be careful about the stack frame, if any summary formatter runs code, it 496061da546Spatrick // might clear the StackFrameList for the thread. So hold onto a shared 497061da546Spatrick // pointer to the frame so it stays alive. 498061da546Spatrick 499061da546Spatrick VariableList *variable_list = 500061da546Spatrick frame->GetVariableList(m_option_variable.show_globals); 501061da546Spatrick 502061da546Spatrick VariableSP var_sp; 503061da546Spatrick ValueObjectSP valobj_sp; 504061da546Spatrick 505061da546Spatrick TypeSummaryImplSP summary_format_sp; 506061da546Spatrick if (!m_option_variable.summary.IsCurrentValueEmpty()) 507061da546Spatrick DataVisualization::NamedSummaryFormats::GetSummaryFormat( 508061da546Spatrick ConstString(m_option_variable.summary.GetCurrentValue()), 509061da546Spatrick summary_format_sp); 510061da546Spatrick else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 511061da546Spatrick summary_format_sp = std::make_shared<StringSummaryFormat>( 512061da546Spatrick TypeSummaryImpl::Flags(), 513061da546Spatrick m_option_variable.summary_string.GetCurrentValue()); 514061da546Spatrick 515061da546Spatrick DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( 516061da546Spatrick eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault, 517061da546Spatrick summary_format_sp)); 518061da546Spatrick 519061da546Spatrick const SymbolContext &sym_ctx = 520061da546Spatrick frame->GetSymbolContext(eSymbolContextFunction); 521061da546Spatrick if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 522061da546Spatrick m_option_variable.show_globals = true; 523061da546Spatrick 524061da546Spatrick if (variable_list) { 525061da546Spatrick const Format format = m_option_format.GetFormat(); 526061da546Spatrick options.SetFormat(format); 527061da546Spatrick 528061da546Spatrick if (!command.empty()) { 529061da546Spatrick VariableList regex_var_list; 530061da546Spatrick 531061da546Spatrick // If we have any args to the variable command, we will make variable 532061da546Spatrick // objects from them... 533061da546Spatrick for (auto &entry : command) { 534061da546Spatrick if (m_option_variable.use_regex) { 535061da546Spatrick const size_t regex_start_index = regex_var_list.GetSize(); 536061da546Spatrick llvm::StringRef name_str = entry.ref(); 537061da546Spatrick RegularExpression regex(name_str); 538061da546Spatrick if (regex.IsValid()) { 539061da546Spatrick size_t num_matches = 0; 540061da546Spatrick const size_t num_new_regex_vars = 541061da546Spatrick variable_list->AppendVariablesIfUnique(regex, regex_var_list, 542061da546Spatrick num_matches); 543061da546Spatrick if (num_new_regex_vars > 0) { 544061da546Spatrick for (size_t regex_idx = regex_start_index, 545061da546Spatrick end_index = regex_var_list.GetSize(); 546061da546Spatrick regex_idx < end_index; ++regex_idx) { 547061da546Spatrick var_sp = regex_var_list.GetVariableAtIndex(regex_idx); 548061da546Spatrick if (var_sp) { 549061da546Spatrick valobj_sp = frame->GetValueObjectForFrameVariable( 550061da546Spatrick var_sp, m_varobj_options.use_dynamic); 551061da546Spatrick if (valobj_sp) { 552061da546Spatrick std::string scope_string; 553061da546Spatrick if (m_option_variable.show_scope) 554061da546Spatrick scope_string = GetScopeString(var_sp).str(); 555061da546Spatrick 556061da546Spatrick if (!scope_string.empty()) 557061da546Spatrick s.PutCString(scope_string); 558061da546Spatrick 559061da546Spatrick if (m_option_variable.show_decl && 560061da546Spatrick var_sp->GetDeclaration().GetFile()) { 561061da546Spatrick bool show_fullpaths = false; 562061da546Spatrick bool show_module = true; 563061da546Spatrick if (var_sp->DumpDeclaration(&s, show_fullpaths, 564061da546Spatrick show_module)) 565061da546Spatrick s.PutCString(": "); 566061da546Spatrick } 567061da546Spatrick valobj_sp->Dump(result.GetOutputStream(), options); 568061da546Spatrick } 569061da546Spatrick } 570061da546Spatrick } 571061da546Spatrick } else if (num_matches == 0) { 572061da546Spatrick result.GetErrorStream().Printf("error: no variables matched " 573061da546Spatrick "the regular expression '%s'.\n", 574061da546Spatrick entry.c_str()); 575061da546Spatrick } 576061da546Spatrick } else { 577061da546Spatrick if (llvm::Error err = regex.GetError()) 578061da546Spatrick result.GetErrorStream().Printf( 579061da546Spatrick "error: %s\n", llvm::toString(std::move(err)).c_str()); 580061da546Spatrick else 581061da546Spatrick result.GetErrorStream().Printf( 582061da546Spatrick "error: unknown regex error when compiling '%s'\n", 583061da546Spatrick entry.c_str()); 584061da546Spatrick } 585061da546Spatrick } else // No regex, either exact variable names or variable 586061da546Spatrick // expressions. 587061da546Spatrick { 588061da546Spatrick Status error; 589061da546Spatrick uint32_t expr_path_options = 590061da546Spatrick StackFrame::eExpressionPathOptionCheckPtrVsMember | 591061da546Spatrick StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 592061da546Spatrick StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 593061da546Spatrick lldb::VariableSP var_sp; 594061da546Spatrick valobj_sp = frame->GetValueForVariableExpressionPath( 595061da546Spatrick entry.ref(), m_varobj_options.use_dynamic, expr_path_options, 596061da546Spatrick var_sp, error); 597061da546Spatrick if (valobj_sp) { 598061da546Spatrick std::string scope_string; 599061da546Spatrick if (m_option_variable.show_scope) 600061da546Spatrick scope_string = GetScopeString(var_sp).str(); 601061da546Spatrick 602061da546Spatrick if (!scope_string.empty()) 603061da546Spatrick s.PutCString(scope_string); 604061da546Spatrick if (m_option_variable.show_decl && var_sp && 605061da546Spatrick var_sp->GetDeclaration().GetFile()) { 606061da546Spatrick var_sp->GetDeclaration().DumpStopContext(&s, false); 607061da546Spatrick s.PutCString(": "); 608061da546Spatrick } 609061da546Spatrick 610061da546Spatrick options.SetFormat(format); 611061da546Spatrick options.SetVariableFormatDisplayLanguage( 612061da546Spatrick valobj_sp->GetPreferredDisplayLanguage()); 613061da546Spatrick 614061da546Spatrick Stream &output_stream = result.GetOutputStream(); 615061da546Spatrick options.SetRootValueObjectName( 616061da546Spatrick valobj_sp->GetParent() ? entry.c_str() : nullptr); 617061da546Spatrick valobj_sp->Dump(output_stream, options); 618061da546Spatrick } else { 619061da546Spatrick const char *error_cstr = error.AsCString(nullptr); 620061da546Spatrick if (error_cstr) 621061da546Spatrick result.GetErrorStream().Printf("error: %s\n", error_cstr); 622061da546Spatrick else 623061da546Spatrick result.GetErrorStream().Printf("error: unable to find any " 624061da546Spatrick "variable expression path that " 625061da546Spatrick "matches '%s'.\n", 626061da546Spatrick entry.c_str()); 627061da546Spatrick } 628061da546Spatrick } 629061da546Spatrick } 630061da546Spatrick } else // No command arg specified. Use variable_list, instead. 631061da546Spatrick { 632061da546Spatrick const size_t num_variables = variable_list->GetSize(); 633061da546Spatrick if (num_variables > 0) { 634061da546Spatrick for (size_t i = 0; i < num_variables; i++) { 635061da546Spatrick var_sp = variable_list->GetVariableAtIndex(i); 636061da546Spatrick switch (var_sp->GetScope()) { 637061da546Spatrick case eValueTypeVariableGlobal: 638061da546Spatrick if (!m_option_variable.show_globals) 639061da546Spatrick continue; 640061da546Spatrick break; 641061da546Spatrick case eValueTypeVariableStatic: 642061da546Spatrick if (!m_option_variable.show_globals) 643061da546Spatrick continue; 644061da546Spatrick break; 645061da546Spatrick case eValueTypeVariableArgument: 646061da546Spatrick if (!m_option_variable.show_args) 647061da546Spatrick continue; 648061da546Spatrick break; 649061da546Spatrick case eValueTypeVariableLocal: 650061da546Spatrick if (!m_option_variable.show_locals) 651061da546Spatrick continue; 652061da546Spatrick break; 653061da546Spatrick default: 654061da546Spatrick continue; 655061da546Spatrick break; 656061da546Spatrick } 657061da546Spatrick std::string scope_string; 658061da546Spatrick if (m_option_variable.show_scope) 659061da546Spatrick scope_string = GetScopeString(var_sp).str(); 660061da546Spatrick 661061da546Spatrick // Use the variable object code to make sure we are using the same 662061da546Spatrick // APIs as the public API will be using... 663061da546Spatrick valobj_sp = frame->GetValueObjectForFrameVariable( 664061da546Spatrick var_sp, m_varobj_options.use_dynamic); 665061da546Spatrick if (valobj_sp) { 666061da546Spatrick // When dumping all variables, don't print any variables that are 667061da546Spatrick // not in scope to avoid extra unneeded output 668061da546Spatrick if (valobj_sp->IsInScope()) { 669061da546Spatrick if (!valobj_sp->GetTargetSP() 670061da546Spatrick ->GetDisplayRuntimeSupportValues() && 671061da546Spatrick valobj_sp->IsRuntimeSupportValue()) 672061da546Spatrick continue; 673061da546Spatrick 674061da546Spatrick if (!scope_string.empty()) 675061da546Spatrick s.PutCString(scope_string); 676061da546Spatrick 677061da546Spatrick if (m_option_variable.show_decl && 678061da546Spatrick var_sp->GetDeclaration().GetFile()) { 679061da546Spatrick var_sp->GetDeclaration().DumpStopContext(&s, false); 680061da546Spatrick s.PutCString(": "); 681061da546Spatrick } 682061da546Spatrick 683061da546Spatrick options.SetFormat(format); 684061da546Spatrick options.SetVariableFormatDisplayLanguage( 685061da546Spatrick valobj_sp->GetPreferredDisplayLanguage()); 686061da546Spatrick options.SetRootValueObjectName( 687061da546Spatrick var_sp ? var_sp->GetName().AsCString() : nullptr); 688061da546Spatrick valobj_sp->Dump(result.GetOutputStream(), options); 689061da546Spatrick } 690061da546Spatrick } 691061da546Spatrick } 692061da546Spatrick } 693061da546Spatrick } 694061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult); 695061da546Spatrick } 696061da546Spatrick 697061da546Spatrick if (m_option_variable.show_recognized_args) { 698061da546Spatrick auto recognized_frame = frame->GetRecognizedFrame(); 699061da546Spatrick if (recognized_frame) { 700061da546Spatrick ValueObjectListSP recognized_arg_list = 701061da546Spatrick recognized_frame->GetRecognizedArguments(); 702061da546Spatrick if (recognized_arg_list) { 703061da546Spatrick for (auto &rec_value_sp : recognized_arg_list->GetObjects()) { 704061da546Spatrick options.SetFormat(m_option_format.GetFormat()); 705061da546Spatrick options.SetVariableFormatDisplayLanguage( 706061da546Spatrick rec_value_sp->GetPreferredDisplayLanguage()); 707061da546Spatrick options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); 708061da546Spatrick rec_value_sp->Dump(result.GetOutputStream(), options); 709061da546Spatrick } 710061da546Spatrick } 711061da546Spatrick } 712061da546Spatrick } 713061da546Spatrick 714061da546Spatrick if (m_interpreter.TruncationWarningNecessary()) { 715061da546Spatrick result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 716061da546Spatrick m_cmd_name.c_str()); 717061da546Spatrick m_interpreter.TruncationWarningGiven(); 718061da546Spatrick } 719061da546Spatrick 720061da546Spatrick // Increment statistics. 721061da546Spatrick bool res = result.Succeeded(); 722061da546Spatrick Target &target = GetSelectedOrDummyTarget(); 723061da546Spatrick if (res) 724061da546Spatrick target.IncrementStats(StatisticKind::FrameVarSuccess); 725061da546Spatrick else 726061da546Spatrick target.IncrementStats(StatisticKind::FrameVarFailure); 727061da546Spatrick return res; 728061da546Spatrick } 729061da546Spatrick 730061da546Spatrick OptionGroupOptions m_option_group; 731061da546Spatrick OptionGroupVariable m_option_variable; 732061da546Spatrick OptionGroupFormat m_option_format; 733061da546Spatrick OptionGroupValueObjectDisplay m_varobj_options; 734061da546Spatrick }; 735061da546Spatrick 736061da546Spatrick #pragma mark CommandObjectFrameRecognizer 737061da546Spatrick 738061da546Spatrick #define LLDB_OPTIONS_frame_recognizer_add 739061da546Spatrick #include "CommandOptions.inc" 740061da546Spatrick 741061da546Spatrick class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { 742061da546Spatrick private: 743061da546Spatrick class CommandOptions : public Options { 744061da546Spatrick public: 745061da546Spatrick CommandOptions() : Options() {} 746061da546Spatrick ~CommandOptions() override = default; 747061da546Spatrick 748061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 749061da546Spatrick ExecutionContext *execution_context) override { 750061da546Spatrick Status error; 751061da546Spatrick const int short_option = m_getopt_table[option_idx].val; 752061da546Spatrick 753061da546Spatrick switch (short_option) { 754061da546Spatrick case 'l': 755061da546Spatrick m_class_name = std::string(option_arg); 756061da546Spatrick break; 757061da546Spatrick case 's': 758061da546Spatrick m_module = std::string(option_arg); 759061da546Spatrick break; 760061da546Spatrick case 'n': 761*dda28197Spatrick m_symbols.push_back(std::string(option_arg)); 762061da546Spatrick break; 763061da546Spatrick case 'x': 764061da546Spatrick m_regex = true; 765061da546Spatrick break; 766061da546Spatrick default: 767061da546Spatrick llvm_unreachable("Unimplemented option"); 768061da546Spatrick } 769061da546Spatrick 770061da546Spatrick return error; 771061da546Spatrick } 772061da546Spatrick 773061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override { 774061da546Spatrick m_module = ""; 775*dda28197Spatrick m_symbols.clear(); 776061da546Spatrick m_class_name = ""; 777061da546Spatrick m_regex = false; 778061da546Spatrick } 779061da546Spatrick 780061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 781061da546Spatrick return llvm::makeArrayRef(g_frame_recognizer_add_options); 782061da546Spatrick } 783061da546Spatrick 784061da546Spatrick // Instance variables to hold the values for command options. 785061da546Spatrick std::string m_class_name; 786061da546Spatrick std::string m_module; 787*dda28197Spatrick std::vector<std::string> m_symbols; 788061da546Spatrick bool m_regex; 789061da546Spatrick }; 790061da546Spatrick 791061da546Spatrick CommandOptions m_options; 792061da546Spatrick 793061da546Spatrick Options *GetOptions() override { return &m_options; } 794061da546Spatrick 795061da546Spatrick protected: 796061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override; 797061da546Spatrick 798061da546Spatrick public: 799061da546Spatrick CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) 800061da546Spatrick : CommandObjectParsed(interpreter, "frame recognizer add", 801061da546Spatrick "Add a new frame recognizer.", nullptr), 802061da546Spatrick m_options() { 803061da546Spatrick SetHelpLong(R"( 804061da546Spatrick Frame recognizers allow for retrieving information about special frames based on 805061da546Spatrick ABI, arguments or other special properties of that frame, even without source 806061da546Spatrick code or debug info. Currently, one use case is to extract function arguments 807061da546Spatrick that would otherwise be unaccesible, or augment existing arguments. 808061da546Spatrick 809061da546Spatrick Adding a custom frame recognizer is possible by implementing a Python class 810061da546Spatrick and using the 'frame recognizer add' command. The Python class should have a 811061da546Spatrick 'get_recognized_arguments' method and it will receive an argument of type 812061da546Spatrick lldb.SBFrame representing the current frame that we are trying to recognize. 813061da546Spatrick The method should return a (possibly empty) list of lldb.SBValue objects that 814061da546Spatrick represent the recognized arguments. 815061da546Spatrick 816061da546Spatrick An example of a recognizer that retrieves the file descriptor values from libc 817061da546Spatrick functions 'read', 'write' and 'close' follows: 818061da546Spatrick 819061da546Spatrick class LibcFdRecognizer(object): 820061da546Spatrick def get_recognized_arguments(self, frame): 821061da546Spatrick if frame.name in ["read", "write", "close"]: 822061da546Spatrick fd = frame.EvaluateExpression("$arg1").unsigned 823061da546Spatrick value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd) 824061da546Spatrick return [value] 825061da546Spatrick return [] 826061da546Spatrick 827061da546Spatrick The file containing this implementation can be imported via 'command script 828061da546Spatrick import' and then we can register this recognizer with 'frame recognizer add'. 829061da546Spatrick It's important to restrict the recognizer to the libc library (which is 830061da546Spatrick libsystem_kernel.dylib on macOS) to avoid matching functions with the same name 831061da546Spatrick in other modules: 832061da546Spatrick 833061da546Spatrick (lldb) command script import .../fd_recognizer.py 834061da546Spatrick (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib 835061da546Spatrick 836061da546Spatrick When the program is stopped at the beginning of the 'read' function in libc, we 837061da546Spatrick can view the recognizer arguments in 'frame variable': 838061da546Spatrick 839061da546Spatrick (lldb) b read 840061da546Spatrick (lldb) r 841061da546Spatrick Process 1234 stopped 842061da546Spatrick * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 843061da546Spatrick frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read 844061da546Spatrick (lldb) frame variable 845061da546Spatrick (int) fd = 3 846061da546Spatrick 847061da546Spatrick )"); 848061da546Spatrick } 849061da546Spatrick ~CommandObjectFrameRecognizerAdd() override = default; 850061da546Spatrick }; 851061da546Spatrick 852061da546Spatrick bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, 853061da546Spatrick CommandReturnObject &result) { 854061da546Spatrick #if LLDB_ENABLE_PYTHON 855061da546Spatrick if (m_options.m_class_name.empty()) { 856061da546Spatrick result.AppendErrorWithFormat( 857061da546Spatrick "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); 858061da546Spatrick result.SetStatus(eReturnStatusFailed); 859061da546Spatrick return false; 860061da546Spatrick } 861061da546Spatrick 862061da546Spatrick if (m_options.m_module.empty()) { 863061da546Spatrick result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", 864061da546Spatrick m_cmd_name.c_str()); 865061da546Spatrick result.SetStatus(eReturnStatusFailed); 866061da546Spatrick return false; 867061da546Spatrick } 868061da546Spatrick 869*dda28197Spatrick if (m_options.m_symbols.empty()) { 870*dda28197Spatrick result.AppendErrorWithFormat( 871*dda28197Spatrick "%s needs at least one symbol name (-n argument).\n", 872*dda28197Spatrick m_cmd_name.c_str()); 873*dda28197Spatrick result.SetStatus(eReturnStatusFailed); 874*dda28197Spatrick return false; 875*dda28197Spatrick } 876*dda28197Spatrick 877*dda28197Spatrick if (m_options.m_regex && m_options.m_symbols.size() > 1) { 878*dda28197Spatrick result.AppendErrorWithFormat( 879*dda28197Spatrick "%s needs only one symbol regular expression (-n argument).\n", 880061da546Spatrick m_cmd_name.c_str()); 881061da546Spatrick result.SetStatus(eReturnStatusFailed); 882061da546Spatrick return false; 883061da546Spatrick } 884061da546Spatrick 885061da546Spatrick ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 886061da546Spatrick 887061da546Spatrick if (interpreter && 888061da546Spatrick !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { 889061da546Spatrick result.AppendWarning("The provided class does not exist - please define it " 890061da546Spatrick "before attempting to use this frame recognizer"); 891061da546Spatrick } 892061da546Spatrick 893061da546Spatrick StackFrameRecognizerSP recognizer_sp = 894061da546Spatrick StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( 895061da546Spatrick interpreter, m_options.m_class_name.c_str())); 896061da546Spatrick if (m_options.m_regex) { 897061da546Spatrick auto module = 898061da546Spatrick RegularExpressionSP(new RegularExpression(m_options.m_module)); 899061da546Spatrick auto func = 900*dda28197Spatrick RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); 901061da546Spatrick StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); 902061da546Spatrick } else { 903061da546Spatrick auto module = ConstString(m_options.m_module); 904*dda28197Spatrick std::vector<ConstString> symbols(m_options.m_symbols.begin(), 905*dda28197Spatrick m_options.m_symbols.end()); 906*dda28197Spatrick StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, symbols); 907061da546Spatrick } 908061da546Spatrick #endif 909061da546Spatrick 910061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult); 911061da546Spatrick return result.Succeeded(); 912061da546Spatrick } 913061da546Spatrick 914061da546Spatrick class CommandObjectFrameRecognizerClear : public CommandObjectParsed { 915061da546Spatrick public: 916061da546Spatrick CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) 917061da546Spatrick : CommandObjectParsed(interpreter, "frame recognizer clear", 918061da546Spatrick "Delete all frame recognizers.", nullptr) {} 919061da546Spatrick 920061da546Spatrick ~CommandObjectFrameRecognizerClear() override = default; 921061da546Spatrick 922061da546Spatrick protected: 923061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override { 924061da546Spatrick StackFrameRecognizerManager::RemoveAllRecognizers(); 925061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult); 926061da546Spatrick return result.Succeeded(); 927061da546Spatrick } 928061da546Spatrick }; 929061da546Spatrick 930061da546Spatrick class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { 931061da546Spatrick public: 932061da546Spatrick CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) 933061da546Spatrick : CommandObjectParsed(interpreter, "frame recognizer delete", 934061da546Spatrick "Delete an existing frame recognizer.", nullptr) {} 935061da546Spatrick 936061da546Spatrick ~CommandObjectFrameRecognizerDelete() override = default; 937061da546Spatrick 938*dda28197Spatrick void 939*dda28197Spatrick HandleArgumentCompletion(CompletionRequest &request, 940*dda28197Spatrick OptionElementVector &opt_element_vector) override { 941*dda28197Spatrick if (request.GetCursorIndex() != 0) 942*dda28197Spatrick return; 943*dda28197Spatrick 944*dda28197Spatrick StackFrameRecognizerManager::ForEach( 945*dda28197Spatrick [&request](uint32_t rid, std::string rname, std::string module, 946*dda28197Spatrick llvm::ArrayRef<lldb_private::ConstString> symbols, 947*dda28197Spatrick bool regexp) { 948*dda28197Spatrick StreamString strm; 949*dda28197Spatrick if (rname.empty()) 950*dda28197Spatrick rname = "(internal)"; 951*dda28197Spatrick 952*dda28197Spatrick strm << rname; 953*dda28197Spatrick if (!module.empty()) 954*dda28197Spatrick strm << ", module " << module; 955*dda28197Spatrick if (!symbols.empty()) 956*dda28197Spatrick for (auto &symbol : symbols) 957*dda28197Spatrick strm << ", symbol " << symbol; 958*dda28197Spatrick if (regexp) 959*dda28197Spatrick strm << " (regexp)"; 960*dda28197Spatrick 961*dda28197Spatrick request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString()); 962*dda28197Spatrick }); 963*dda28197Spatrick } 964*dda28197Spatrick 965061da546Spatrick protected: 966061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override { 967061da546Spatrick if (command.GetArgumentCount() == 0) { 968061da546Spatrick if (!m_interpreter.Confirm( 969061da546Spatrick "About to delete all frame recognizers, do you want to do that?", 970061da546Spatrick true)) { 971061da546Spatrick result.AppendMessage("Operation cancelled..."); 972061da546Spatrick result.SetStatus(eReturnStatusFailed); 973061da546Spatrick return false; 974061da546Spatrick } 975061da546Spatrick 976061da546Spatrick StackFrameRecognizerManager::RemoveAllRecognizers(); 977061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult); 978061da546Spatrick return result.Succeeded(); 979061da546Spatrick } 980061da546Spatrick 981061da546Spatrick if (command.GetArgumentCount() != 1) { 982061da546Spatrick result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 983061da546Spatrick m_cmd_name.c_str()); 984061da546Spatrick result.SetStatus(eReturnStatusFailed); 985061da546Spatrick return false; 986061da546Spatrick } 987061da546Spatrick 988*dda28197Spatrick uint32_t recognizer_id; 989*dda28197Spatrick if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) { 990*dda28197Spatrick result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 991*dda28197Spatrick command.GetArgumentAtIndex(0)); 992*dda28197Spatrick result.SetStatus(eReturnStatusFailed); 993*dda28197Spatrick return false; 994*dda28197Spatrick } 995061da546Spatrick 996061da546Spatrick StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id); 997061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult); 998061da546Spatrick return result.Succeeded(); 999061da546Spatrick } 1000061da546Spatrick }; 1001061da546Spatrick 1002061da546Spatrick class CommandObjectFrameRecognizerList : public CommandObjectParsed { 1003061da546Spatrick public: 1004061da546Spatrick CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 1005061da546Spatrick : CommandObjectParsed(interpreter, "frame recognizer list", 1006061da546Spatrick "Show a list of active frame recognizers.", 1007061da546Spatrick nullptr) {} 1008061da546Spatrick 1009061da546Spatrick ~CommandObjectFrameRecognizerList() override = default; 1010061da546Spatrick 1011061da546Spatrick protected: 1012061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override { 1013061da546Spatrick bool any_printed = false; 1014061da546Spatrick StackFrameRecognizerManager::ForEach( 1015*dda28197Spatrick [&result, &any_printed]( 1016*dda28197Spatrick uint32_t recognizer_id, std::string name, std::string module, 1017*dda28197Spatrick llvm::ArrayRef<ConstString> symbols, bool regexp) { 1018*dda28197Spatrick Stream &stream = result.GetOutputStream(); 1019*dda28197Spatrick 1020*dda28197Spatrick if (name.empty()) 1021061da546Spatrick name = "(internal)"; 1022*dda28197Spatrick 1023*dda28197Spatrick stream << std::to_string(recognizer_id) << ": " << name; 1024*dda28197Spatrick if (!module.empty()) 1025*dda28197Spatrick stream << ", module " << module; 1026*dda28197Spatrick if (!symbols.empty()) 1027*dda28197Spatrick for (auto &symbol : symbols) 1028*dda28197Spatrick stream << ", symbol " << symbol; 1029*dda28197Spatrick if (regexp) 1030*dda28197Spatrick stream << " (regexp)"; 1031*dda28197Spatrick 1032*dda28197Spatrick stream.EOL(); 1033*dda28197Spatrick stream.Flush(); 1034*dda28197Spatrick 1035061da546Spatrick any_printed = true; 1036061da546Spatrick }); 1037061da546Spatrick 1038061da546Spatrick if (any_printed) 1039061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult); 1040061da546Spatrick else { 1041061da546Spatrick result.GetOutputStream().PutCString("no matching results found.\n"); 1042061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult); 1043061da546Spatrick } 1044061da546Spatrick return result.Succeeded(); 1045061da546Spatrick } 1046061da546Spatrick }; 1047061da546Spatrick 1048061da546Spatrick class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 1049061da546Spatrick public: 1050061da546Spatrick CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 1051061da546Spatrick : CommandObjectParsed( 1052061da546Spatrick interpreter, "frame recognizer info", 1053061da546Spatrick "Show which frame recognizer is applied a stack frame (if any).", 1054061da546Spatrick nullptr) { 1055061da546Spatrick CommandArgumentEntry arg; 1056061da546Spatrick CommandArgumentData index_arg; 1057061da546Spatrick 1058061da546Spatrick // Define the first (and only) variant of this arg. 1059061da546Spatrick index_arg.arg_type = eArgTypeFrameIndex; 1060061da546Spatrick index_arg.arg_repetition = eArgRepeatPlain; 1061061da546Spatrick 1062061da546Spatrick // There is only one variant this argument could be; put it into the 1063061da546Spatrick // argument entry. 1064061da546Spatrick arg.push_back(index_arg); 1065061da546Spatrick 1066061da546Spatrick // Push the data for the first argument into the m_arguments vector. 1067061da546Spatrick m_arguments.push_back(arg); 1068061da546Spatrick } 1069061da546Spatrick 1070061da546Spatrick ~CommandObjectFrameRecognizerInfo() override = default; 1071061da546Spatrick 1072061da546Spatrick protected: 1073061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override { 1074*dda28197Spatrick const char *frame_index_str = command.GetArgumentAtIndex(0); 1075*dda28197Spatrick uint32_t frame_index; 1076*dda28197Spatrick if (!llvm::to_integer(frame_index_str, frame_index)) { 1077*dda28197Spatrick result.AppendErrorWithFormat("'%s' is not a valid frame index.", 1078*dda28197Spatrick frame_index_str); 1079*dda28197Spatrick result.SetStatus(eReturnStatusFailed); 1080*dda28197Spatrick return false; 1081*dda28197Spatrick } 1082*dda28197Spatrick 1083061da546Spatrick Process *process = m_exe_ctx.GetProcessPtr(); 1084061da546Spatrick if (process == nullptr) { 1085061da546Spatrick result.AppendError("no process"); 1086061da546Spatrick result.SetStatus(eReturnStatusFailed); 1087061da546Spatrick return false; 1088061da546Spatrick } 1089061da546Spatrick Thread *thread = m_exe_ctx.GetThreadPtr(); 1090061da546Spatrick if (thread == nullptr) { 1091061da546Spatrick result.AppendError("no thread"); 1092061da546Spatrick result.SetStatus(eReturnStatusFailed); 1093061da546Spatrick return false; 1094061da546Spatrick } 1095061da546Spatrick if (command.GetArgumentCount() != 1) { 1096061da546Spatrick result.AppendErrorWithFormat( 1097061da546Spatrick "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 1098061da546Spatrick result.SetStatus(eReturnStatusFailed); 1099061da546Spatrick return false; 1100061da546Spatrick } 1101061da546Spatrick 1102061da546Spatrick StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 1103061da546Spatrick if (!frame_sp) { 1104061da546Spatrick result.AppendErrorWithFormat("no frame with index %u", frame_index); 1105061da546Spatrick result.SetStatus(eReturnStatusFailed); 1106061da546Spatrick return false; 1107061da546Spatrick } 1108061da546Spatrick 1109061da546Spatrick auto recognizer = 1110061da546Spatrick StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp); 1111061da546Spatrick 1112061da546Spatrick Stream &output_stream = result.GetOutputStream(); 1113061da546Spatrick output_stream.Printf("frame %d ", frame_index); 1114061da546Spatrick if (recognizer) { 1115061da546Spatrick output_stream << "is recognized by "; 1116061da546Spatrick output_stream << recognizer->GetName(); 1117061da546Spatrick } else { 1118061da546Spatrick output_stream << "not recognized by any recognizer"; 1119061da546Spatrick } 1120061da546Spatrick output_stream.EOL(); 1121061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult); 1122061da546Spatrick return result.Succeeded(); 1123061da546Spatrick } 1124061da546Spatrick }; 1125061da546Spatrick 1126061da546Spatrick class CommandObjectFrameRecognizer : public CommandObjectMultiword { 1127061da546Spatrick public: 1128061da546Spatrick CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 1129061da546Spatrick : CommandObjectMultiword( 1130061da546Spatrick interpreter, "frame recognizer", 1131061da546Spatrick "Commands for editing and viewing frame recognizers.", 1132061da546Spatrick "frame recognizer [<sub-command-options>] ") { 1133061da546Spatrick LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd( 1134061da546Spatrick interpreter))); 1135061da546Spatrick LoadSubCommand( 1136061da546Spatrick "clear", 1137061da546Spatrick CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 1138061da546Spatrick LoadSubCommand( 1139061da546Spatrick "delete", 1140061da546Spatrick CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 1141061da546Spatrick LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList( 1142061da546Spatrick interpreter))); 1143061da546Spatrick LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo( 1144061da546Spatrick interpreter))); 1145061da546Spatrick } 1146061da546Spatrick 1147061da546Spatrick ~CommandObjectFrameRecognizer() override = default; 1148061da546Spatrick }; 1149061da546Spatrick 1150061da546Spatrick #pragma mark CommandObjectMultiwordFrame 1151061da546Spatrick 1152061da546Spatrick // CommandObjectMultiwordFrame 1153061da546Spatrick 1154061da546Spatrick CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1155061da546Spatrick CommandInterpreter &interpreter) 1156061da546Spatrick : CommandObjectMultiword(interpreter, "frame", 1157061da546Spatrick "Commands for selecting and " 1158061da546Spatrick "examing the current " 1159061da546Spatrick "thread's stack frames.", 1160061da546Spatrick "frame <subcommand> [<subcommand-options>]") { 1161061da546Spatrick LoadSubCommand("diagnose", 1162061da546Spatrick CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1163061da546Spatrick LoadSubCommand("info", 1164061da546Spatrick CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1165061da546Spatrick LoadSubCommand("select", 1166061da546Spatrick CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1167061da546Spatrick LoadSubCommand("variable", 1168061da546Spatrick CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 1169061da546Spatrick #if LLDB_ENABLE_PYTHON 1170061da546Spatrick LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer( 1171061da546Spatrick interpreter))); 1172061da546Spatrick #endif 1173061da546Spatrick } 1174061da546Spatrick 1175061da546Spatrick CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1176