Index: lldb/source/Commands/CommandObjectFrame.cpp =================================================================== --- lldb/source/Commands/CommandObjectFrame.cpp +++ lldb/source/Commands/CommandObjectFrame.cpp @@ -735,20 +735,58 @@ #pragma mark CommandObjectFrameRecognizer +#define LLDB_OPTIONS_frame_recognizer_dummy +#include "CommandOptions.inc" + +class FrameRecognizerDummyOptionGroup : public OptionGroup { +public: + FrameRecognizerDummyOptionGroup() : OptionGroup() {} + + ~FrameRecognizerDummyOptionGroup() override = default; + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_frame_recognizer_dummy_options); + } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = + g_frame_recognizer_dummy_options[option_idx].short_option; + + switch (short_option) { + case 'D': + m_use_dummy = true; + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_use_dummy = false; + } + + bool m_use_dummy; +}; + #define LLDB_OPTIONS_frame_recognizer_add #include "CommandOptions.inc" class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { private: - class CommandOptions : public Options { + class CommandOptions : public OptionGroup { public: - CommandOptions() : Options() {} + CommandOptions() = default; ~CommandOptions() override = default; Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override { Status error; - const int short_option = m_getopt_table[option_idx].val; + const int short_option = + g_frame_recognizer_add_options[option_idx].short_option; switch (short_option) { case 'l': @@ -788,9 +826,11 @@ bool m_regex; }; + FrameRecognizerDummyOptionGroup m_dummy_options; CommandOptions m_options; + OptionGroupOptions m_all_options; - Options *GetOptions() override { return &m_options; } + Options *GetOptions() override { return &m_all_options; } protected: bool DoExecute(Args &command, CommandReturnObject &result) override; @@ -800,6 +840,9 @@ : CommandObjectParsed(interpreter, "frame recognizer add", "Add a new frame recognizer.", nullptr), m_options() { + m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_ALL); + m_all_options.Append(&m_options); + m_all_options.Finalize(); SetHelpLong(R"( Frame recognizers allow for retrieving information about special frames based on ABI, arguments or other special properties of that frame, even without source @@ -898,14 +941,16 @@ RegularExpressionSP(new RegularExpression(m_options.m_module)); auto func = RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); - GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( - recognizer_sp, module, func); + GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy) + .GetFrameRecognizerManager() + .AddRecognizer(recognizer_sp, module, func); } else { auto module = ConstString(m_options.m_module); std::vector symbols(m_options.m_symbols.begin(), m_options.m_symbols.end()); - GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( - recognizer_sp, module, symbols); + GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy) + .GetFrameRecognizerManager() + .AddRecognizer(recognizer_sp, module, symbols); } #endif @@ -914,16 +959,24 @@ } class CommandObjectFrameRecognizerClear : public CommandObjectParsed { + FrameRecognizerDummyOptionGroup m_dummy_options; + OptionGroupOptions m_all_options; + public: CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "frame recognizer clear", - "Delete all frame recognizers.", nullptr) {} + "Delete all frame recognizers.", nullptr) { + m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_ALL); + m_all_options.Finalize(); + } ~CommandObjectFrameRecognizerClear() override = default; + Options *GetOptions() override { return &m_all_options; } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { - GetSelectedOrDummyTarget() + GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy) .GetFrameRecognizerManager() .RemoveAllRecognizers(); result.SetStatus(eReturnStatusSuccessFinishResult); @@ -932,23 +985,32 @@ }; class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { + FrameRecognizerDummyOptionGroup m_dummy_options; + OptionGroupOptions m_all_options; + public: CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "frame recognizer delete", - "Delete an existing frame recognizer.", nullptr) {} + "Delete an existing frame recognizer.", nullptr) { + m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_ALL); + m_all_options.Finalize(); + } ~CommandObjectFrameRecognizerDelete() override = default; + Options *GetOptions() override { return &m_all_options; } + void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override { if (request.GetCursorIndex() != 0) return; - GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( - [&request](uint32_t rid, std::string rname, std::string module, - llvm::ArrayRef symbols, - bool regexp) { + GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy) + .GetFrameRecognizerManager() + .ForEach([&request](uint32_t rid, std::string rname, std::string module, + llvm::ArrayRef symbols, + bool regexp) { StreamString strm; if (rname.empty()) rname = "(internal)"; @@ -977,7 +1039,7 @@ return false; } - GetSelectedOrDummyTarget() + GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy) .GetFrameRecognizerManager() .RemoveAllRecognizers(); result.SetStatus(eReturnStatusSuccessFinishResult); @@ -999,7 +1061,7 @@ return false; } - if (!GetSelectedOrDummyTarget() + if (!GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy) .GetFrameRecognizerManager() .RemoveRecognizerWithID(recognizer_id)) { result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", @@ -1013,21 +1075,31 @@ }; class CommandObjectFrameRecognizerList : public CommandObjectParsed { + FrameRecognizerDummyOptionGroup m_dummy_options; + OptionGroupOptions m_all_options; + public: CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "frame recognizer list", "Show a list of active frame recognizers.", - nullptr) {} + nullptr) { + m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_ALL); + m_all_options.Finalize(); + } ~CommandObjectFrameRecognizerList() override = default; + Options *GetOptions() override { return &m_all_options; } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { bool any_printed = false; - GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( - [&result, &any_printed]( - uint32_t recognizer_id, std::string name, std::string module, - llvm::ArrayRef symbols, bool regexp) { + GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy) + .GetFrameRecognizerManager() + .ForEach([&result, &any_printed](uint32_t recognizer_id, + std::string name, std::string module, + llvm::ArrayRef symbols, + bool regexp) { Stream &stream = result.GetOutputStream(); if (name.empty()) Index: lldb/source/Commands/Options.td =================================================================== --- lldb/source/Commands/Options.td +++ lldb/source/Commands/Options.td @@ -387,6 +387,13 @@ Desc<"A relative frame index offset from the current frame index.">; } +let Command = "frame recognizer dummy" in { + def recognizer_dummy_options_dummy : + Option<"dummy-frame-recognizer", "D">, Group<1>, + Desc<"Act on Dummy frame recognizers - i.e. frame recognizers added before" + " a file is provided, which prime new targets.">; +} + let Command = "frame recognizer add" in { def frame_recognizer_shlib : Option<"shlib", "s">, Arg<"ShlibName">, Completion<"Module">, Index: lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py =================================================================== --- lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py +++ lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py @@ -205,6 +205,66 @@ self.expect("frame recognizer info 0", substrs=['frame 0 is recognized by recognizer.MyFrameRecognizer']) + @skipUnlessDarwin + def test_frame_recognizer_dummy_target(self): + self.build() + exe = self.getBuildArtifact("a.out") + + # Clear internal & plugins recognizers that get initialized at launch. + self.runCmd("frame recognizer clear -D") + + self.runCmd("command script import " + os.path.join(self.getSourceDir(), "recognizer.py")) + + # Add a frame recognizer to the dummy target. + self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo") + # Should be in the dummy target (which is used even without '-D' as + # there is no selected target). + self.expect("frame recognizer list -D", + substrs=['recognizer.MyFrameRecognizer, module a.out, symbol foo']) + self.expect("frame recognizer list", + substrs=['recognizer.MyFrameRecognizer, module a.out, symbol foo']) + + # Create a real target now. + lldbutil.run_to_name_breakpoint(self, "foo", exe_name = exe) + + # The frame recognizer is still in the dummy target. + self.expect("frame recognizer list -D", + substrs=['recognizer.MyFrameRecognizer, module a.out, symbol foo']) + # And also in the real target. + self.expect("frame recognizer list", + substrs=['recognizer.MyFrameRecognizer, module a.out, symbol foo']) + + # Delete recognizers from the dummy target. + self.runCmd("frame recognizer clear -D") + + # The recognizer should be gone from the dummy target. + self.expect("frame recognizer list -D", + matching=False, substrs=['MyFrameRecognizer']) + # But the real target should still have it. + self.expect("frame recognizer list", + substrs=['recognizer.MyFrameRecognizer, module a.out, symbol foo']) + + # Add a recognizer to the real target now. + self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n bar") + # The dummy target should not have this new recognizer. + self.expect("frame recognizer list -D", + matching=False, substrs=['MyFrameRecognizer']) + self.runCmd("frame recognizer clear") + + # Add a recognizer to the dummy target. + self.runCmd("frame recognizer add -D -l recognizer.MyFrameRecognizer -s a.out -n bar") + # The recognizer should be in the dummy target. + self.expect("frame recognizer list -D", + substrs=['recognizer.MyFrameRecognizer, module a.out, symbol bar']) + # The recognizer shouldn't be in the real target. + self.expect("frame recognizer list", matching=False, + substrs=['recognizer.MyFrameRecognizer, module a.out, symbol bar']) + + # Delete the recognizer from the dummy target by index. + self.runCmd("frame recognizer delete -D 0") + self.expect("frame recognizer list -D", + matching=False, substrs=['MyFrameRecognizer']) + @no_debug_info_test def test_frame_recognizer_delete_invalid_arg(self): self.expect("frame recognizer delete a", error=True, @@ -212,7 +272,7 @@ self.expect("frame recognizer delete \"\"", error=True, substrs=["error: '' is not a valid recognizer id."]) self.expect("frame recognizer delete -1", error=True, - substrs=["error: '-1' is not a valid recognizer id."]) + substrs=["error: unknown or ambiguous option"]) self.expect("frame recognizer delete 4294967297", error=True, substrs=["error: '4294967297' is not a valid recognizer id."])