Index: include/lldb/API/SBVariablesOptions.h =================================================================== --- include/lldb/API/SBVariablesOptions.h +++ include/lldb/API/SBVariablesOptions.h @@ -33,6 +33,10 @@ void SetIncludeArguments(bool); + bool GetIncludeRecognizedArguments() const; + + void SetIncludeRecognizedArguments(bool); + bool GetIncludeLocals() const; void SetIncludeLocals(bool); Index: include/lldb/Interpreter/OptionGroupVariable.h =================================================================== --- include/lldb/Interpreter/OptionGroupVariable.h +++ include/lldb/Interpreter/OptionGroupVariable.h @@ -39,6 +39,7 @@ bool include_frame_options : 1, show_args : 1, // Frame option only (include_frame_options == true) + show_recognized_args : 1, // Frame option only (include_frame_options == true) show_locals : 1, // Frame option only (include_frame_options == true) show_globals : 1, // Frame option only (include_frame_options == true) use_regex : 1, show_scope : 1, show_decl : 1; Index: include/lldb/Interpreter/ScriptInterpreter.h =================================================================== --- include/lldb/Interpreter/ScriptInterpreter.h +++ include/lldb/Interpreter/ScriptInterpreter.h @@ -171,6 +171,16 @@ CreateScriptCommandObject(const char *class_name) { return StructuredData::GenericSP(); } + + virtual StructuredData::GenericSP + CreateFrameRecognizer(const char *class_name) { + return StructuredData::GenericSP(); + } + + virtual lldb::ValueObjectListSP + GetRecognizedArguments(const StructuredData::ObjectSP &implementor, lldb::StackFrameSP frame_sp) { + return lldb::ValueObjectListSP(); + } virtual StructuredData::GenericSP OSPlugin_CreatePluginObject(const char *class_name, Index: include/lldb/Target/StackFrame.h =================================================================== --- include/lldb/Target/StackFrame.h +++ include/lldb/Target/StackFrame.h @@ -516,6 +516,8 @@ void CalculateExecutionContext(ExecutionContext &exe_ctx) override; + lldb::RecognizedStackFrameSP GetRecognizedFrame(); + protected: friend class StackFrameList; @@ -553,6 +555,8 @@ ValueObjectList m_variable_list_value_objects; // Value objects for each // variable in // m_variable_list_sp + bool m_recognized; + lldb::RecognizedStackFrameSP m_recognized_frame; StreamString m_disassembly; std::recursive_mutex m_mutex; Index: include/lldb/Target/StackFrameRecognizer.h =================================================================== --- include/lldb/Target/StackFrameRecognizer.h +++ include/lldb/Target/StackFrameRecognizer.h @@ -0,0 +1,84 @@ +//===-- FrameRecognizer.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_FrameRecognizer_h_ +#define liblldb_FrameRecognizer_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/ValueObjectList.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Utility/StructuredData.h" +#include "lldb/lldb-private-forward.h" +#include "lldb/lldb-public.h" + +namespace lldb_private { + +class RecognizedStackFrame + : std::enable_shared_from_this { +public: + virtual lldb::ValueObjectListSP GetRecognizedArguments() { + return m_arguments; + } + virtual ~RecognizedStackFrame(){}; + +protected: + lldb::ValueObjectListSP m_arguments; +}; + +class StackFrameRecognizer + : std::enable_shared_from_this { +public: + virtual lldb::RecognizedStackFrameSP + RecognizeFrame(lldb::StackFrameSP frame) { + return lldb::RecognizedStackFrameSP(); + }; + + virtual ~StackFrameRecognizer(){}; +}; + +#ifndef LLDB_DISABLE_PYTHON + +class ScriptedStackFrameRecognizer : public StackFrameRecognizer { + lldb_private::ScriptInterpreter *m_interpreter; + lldb_private::StructuredData::ObjectSP m_python_object_sp; + std::string m_python_class; +public: + ScriptedStackFrameRecognizer(lldb_private::ScriptInterpreter *interpreter, const char *pclass); + ~ScriptedStackFrameRecognizer() {} + + const char *GetPythonClassName() { return m_python_class.c_str(); } + + lldb::RecognizedStackFrameSP RecognizeFrame(lldb::StackFrameSP frame) override; + +private: + DISALLOW_COPY_AND_ASSIGN(ScriptedStackFrameRecognizer); +}; +#endif + + +class StackFrameRecognizerManager { +public: + static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, + ConstString &module, ConstString &symbol, + bool first_instruction_only = true); + + static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, + lldb::RegularExpressionSP module, + lldb::RegularExpressionSP symbol, + bool first_instruction_only = true); + + static lldb::RecognizedStackFrameSP RecognizeFrame(lldb::StackFrameSP frame); +}; + +} // namespace lldb_private + +#endif // liblldb_FrameRecognizer_h_ Index: include/lldb/lldb-forward.h =================================================================== --- include/lldb/lldb-forward.h +++ include/lldb/lldb-forward.h @@ -184,6 +184,7 @@ class ProcessLaunchInfo; class Property; struct PropertyDefinition; +class RecognizedStackFrame; class RegisterCheckpoint; class RegisterContext; class RegisterLocation; @@ -207,6 +208,8 @@ class StackFrame; class StackFrameImpl; class StackFrameList; +class StackFrameRecognizer; +class StackFrameRecognizerManager; class StackID; class StopInfo; class Stoppoint; @@ -413,6 +416,8 @@ typedef std::weak_ptr QueueWP; typedef std::shared_ptr QueueItemSP; typedef std::shared_ptr REPLSP; +typedef std::shared_ptr + RecognizedStackFrameSP; typedef std::shared_ptr ScriptSummaryFormatSP; typedef std::shared_ptr ScriptInterpreterSP; @@ -428,6 +433,8 @@ typedef std::unique_ptr StackFrameUP; typedef std::weak_ptr StackFrameWP; typedef std::shared_ptr StackFrameListSP; +typedef std::shared_ptr + StackFrameRecognizerSP; typedef std::shared_ptr StopInfoSP; typedef std::shared_ptr StoppointLocationSP; typedef std::shared_ptr StreamSP; Index: packages/Python/lldbsuite/test/functionalities/frame-recognizer/Makefile =================================================================== --- packages/Python/lldbsuite/test/functionalities/frame-recognizer/Makefile +++ packages/Python/lldbsuite/test/functionalities/frame-recognizer/Makefile @@ -0,0 +1,10 @@ +LEVEL = ../../make + +OBJC_SOURCES := main.m + +CFLAGS_EXTRAS += -g0 # No debug info. +MAKE_DSYM := NO + +include $(LEVEL)/Makefile.rules + +LDFLAGS += -framework Foundation Index: packages/Python/lldbsuite/test/functionalities/frame-recognizer/TestFrameRecognizer.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/frame-recognizer/TestFrameRecognizer.py +++ packages/Python/lldbsuite/test/functionalities/frame-recognizer/TestFrameRecognizer.py @@ -0,0 +1,52 @@ +# encoding: utf-8 +""" +Test lldb's frame recognizers. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +import recognizer + +class FrameRecognizerTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + @skipUnlessDarwin + def test_frame_recognizer_1(self): + self.build() + + target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) + self.assertTrue(target, VALID_TARGET) + + self.runCmd("command script import " + os.path.join(self.getSourceDir(), "recognizer.py")) + self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -m a.out -n foo") + + self.runCmd("b foo") + self.runCmd("r") + + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs=['stopped', 'stop reason = breakpoint']) + + process = target.GetProcess() + thread = process.GetSelectedThread() + frame = thread.GetSelectedFrame() + + self.assertEqual(frame.GetSymbol().GetName(), "foo") + self.assertFalse(frame.GetLineEntry().IsValid()) + + self.expect("frame variable -t", + substrs=['(int) a = 42', '(int) b = 56']) + + opts = lldb.SBVariablesOptions(); + opts.SetIncludeRecognizedArguments(True); + variables = frame.GetVariables(opts); + + self.assertEqual(variables.GetSize(), 2) + self.assertEqual(variables.GetValueAtIndex(0).name, "a") + self.assertEqual(variables.GetValueAtIndex(0).signed, 42) + self.assertEqual(variables.GetValueAtIndex(1).name, "b") + self.assertEqual(variables.GetValueAtIndex(1).signed, 56) Index: packages/Python/lldbsuite/test/functionalities/frame-recognizer/main.m =================================================================== --- packages/Python/lldbsuite/test/functionalities/frame-recognizer/main.m +++ packages/Python/lldbsuite/test/functionalities/frame-recognizer/main.m @@ -0,0 +1,21 @@ +//===-- main.m ------------------------------------------------*- ObjC -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#import + +void foo(int a, int b) +{ + printf("%d %d\n", a, b); +} + +int main (int argc, const char * argv[]) +{ + foo(42, 56); + return 0; +} Index: packages/Python/lldbsuite/test/functionalities/frame-recognizer/recognizer.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/frame-recognizer/recognizer.py +++ packages/Python/lldbsuite/test/functionalities/frame-recognizer/recognizer.py @@ -0,0 +1,11 @@ +# encoding: utf-8 + +import lldb + +class MyFrameRecognizer(object): + def get_recognized_arguments(self, frame): + arg1 = frame.EvaluateExpression("$arg1").signed + arg2 = frame.EvaluateExpression("$arg2").signed + val1 = lldb.target.CreateValueFromExpression("a", "%d" % arg1) + val2 = lldb.target.CreateValueFromExpression("b", "%d" % arg2) + return [val1, val2] Index: scripts/Python/python-wrapper.swig =================================================================== --- scripts/Python/python-wrapper.swig +++ scripts/Python/python-wrapper.swig @@ -690,6 +690,52 @@ } SWIGEXPORT void* +LLDBSWIGPython_CreateFrameRecognizer +( + const char *python_class_name, + const char *session_dictionary_name +) +{ + using namespace lldb_private; + + if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name) + Py_RETURN_NONE; + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName(session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary(python_class_name, dict); + + if (!pfunc.IsAllocated()) + Py_RETURN_NONE; + + auto result = pfunc(); + + if (result.IsAllocated()) + return result.release(); + + Py_RETURN_NONE; +} + +SWIGEXPORT PyObject* +LLDBSwigPython_GetRecognizedArguments +( + PyObject *implementor, + const lldb::StackFrameSP& frame_sp +) +{ + using namespace lldb_private; + + static char callee_name[] = "get_recognized_arguments"; + + lldb::SBFrame frame_sb(frame_sp); + PyObject *arg = SBTypeToSWIGWrapper(frame_sb); + + PyObject* result = PyObject_CallMethodObjArgs(implementor, PyString_FromString(callee_name), arg, NULL); + return result; +} + +SWIGEXPORT void* LLDBSWIGPython_GetDynamicSetting (void* module, const char* setting, const lldb::TargetSP& target_sp) { using namespace lldb_private; Index: scripts/interface/SBVariablesOptions.i =================================================================== --- scripts/interface/SBVariablesOptions.i +++ scripts/interface/SBVariablesOptions.i @@ -26,7 +26,13 @@ void SetIncludeArguments (bool); - + + bool + GetIncludeRecognizedArguments () const; + + void + SetIncludeRecognizedArguments (bool); + bool GetIncludeLocals () const; Index: source/API/SBFrame.cpp =================================================================== --- source/API/SBFrame.cpp +++ source/API/SBFrame.cpp @@ -36,6 +36,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.h" +#include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Target/StackID.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -978,6 +979,7 @@ const bool statics = options.GetIncludeStatics(); const bool arguments = options.GetIncludeArguments(); + const bool recognized_arguments = options.GetIncludeRecognizedArguments(); const bool locals = options.GetIncludeLocals(); const bool in_scope_only = options.GetInScopeOnly(); const bool include_runtime_support_values = @@ -985,9 +987,9 @@ const lldb::DynamicValueType use_dynamic = options.GetUseDynamic(); if (log) - log->Printf("SBFrame::GetVariables (arguments=%i, locals=%i, statics=%i, " + log->Printf("SBFrame::GetVariables (arguments=%i, recognized_arguments=%i, locals=%i, statics=%i, " "in_scope_only=%i runtime=%i dynamic=%i)", - arguments, locals, statics, in_scope_only, + arguments, recognized_arguments, locals, statics, in_scope_only, include_runtime_support_values, use_dynamic); std::set variable_set; @@ -1050,6 +1052,20 @@ } } } + if (recognized_arguments) { + auto recognized_frame = frame->GetRecognizedFrame(); + if (recognized_frame) { + ValueObjectListSP recognized_arg_list = recognized_frame->GetRecognizedArguments(); + if (recognized_arg_list) { + for (size_t i = 0; i < recognized_arg_list->GetSize(); i++) { + SBValue value_sb; + value_sb.SetSP(recognized_arg_list->GetValueObjectAtIndex(i), use_dynamic); + value_list.Append(value_sb); + } + } + } + + } } else { if (log) log->Printf("SBFrame::GetVariables () => error: could not " Index: source/API/SBVariablesOptions.cpp =================================================================== --- source/API/SBVariablesOptions.cpp +++ source/API/SBVariablesOptions.cpp @@ -16,7 +16,7 @@ class VariablesOptionsImpl { public: VariablesOptionsImpl() - : m_include_arguments(false), m_include_locals(false), + : m_include_arguments(false), m_include_recognized_arguments(false), m_include_locals(false), m_include_statics(false), m_in_scope_only(false), m_include_runtime_support_values(false), m_use_dynamic(lldb::eNoDynamicValues) {} @@ -31,6 +31,10 @@ void SetIncludeArguments(bool b) { m_include_arguments = b; } + bool GetIncludeRecognizedArguments() const { return m_include_recognized_arguments; } + + void SetIncludeRecognizedArguments(bool b) { m_include_recognized_arguments = b; } + bool GetIncludeLocals() const { return m_include_locals; } void SetIncludeLocals(bool b) { m_include_locals = b; } @@ -57,6 +61,7 @@ private: bool m_include_arguments : 1; + bool m_include_recognized_arguments : 1; bool m_include_locals : 1; bool m_include_statics : 1; bool m_in_scope_only : 1; @@ -90,6 +95,14 @@ m_opaque_ap->SetIncludeArguments(arguments); } +bool SBVariablesOptions::GetIncludeRecognizedArguments() const { + return m_opaque_ap->GetIncludeRecognizedArguments(); +} + +void SBVariablesOptions::SetIncludeRecognizedArguments(bool arguments) { + m_opaque_ap->SetIncludeRecognizedArguments(arguments); +} + bool SBVariablesOptions::GetIncludeLocals() const { return m_opaque_ap->GetIncludeLocals(); } Index: source/API/SystemInitializerFull.cpp =================================================================== --- source/API/SystemInitializerFull.cpp +++ source/API/SystemInitializerFull.cpp @@ -222,6 +222,13 @@ const char *session_dictionary_name, const lldb::ProcessSP &process_sp); +extern "C" void *LLDBSWIGPython_CreateFrameRecognizer( + const char *python_class_name, + const char *session_dictionary_name); + +extern "C" void *LLDBSwigPython_GetRecognizedArguments(void *implementor, + const lldb::StackFrameSP& frame_sp); + extern "C" bool LLDBSWIGPythonRunScriptKeywordProcess( const char *python_function_name, const char *session_dictionary_name, lldb::ProcessSP &process, std::string &output); @@ -409,7 +416,9 @@ LLDBSwigPython_MightHaveChildrenSynthProviderInstance, LLDBSwigPython_GetValueSynthProviderInstance, LLDBSwigPythonCallCommand, LLDBSwigPythonCallCommandObject, LLDBSwigPythonCallModuleInit, - LLDBSWIGPythonCreateOSPlugin, LLDBSWIGPythonRunScriptKeywordProcess, + LLDBSWIGPythonCreateOSPlugin, LLDBSWIGPython_CreateFrameRecognizer, + LLDBSwigPython_GetRecognizedArguments, + LLDBSWIGPythonRunScriptKeywordProcess, LLDBSWIGPythonRunScriptKeywordThread, LLDBSWIGPythonRunScriptKeywordTarget, LLDBSWIGPythonRunScriptKeywordFrame, LLDBSWIGPythonRunScriptKeywordValue, LLDBSWIGPython_GetDynamicSetting, Index: source/Commands/CommandObjectFrame.cpp =================================================================== --- source/Commands/CommandObjectFrame.cpp +++ source/Commands/CommandObjectFrame.cpp @@ -40,6 +40,7 @@ #include "lldb/Symbol/VariableList.h" #include "lldb/Target/Process.h" #include "lldb/Target/StackFrame.h" +#include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -711,6 +712,24 @@ } result.SetStatus(eReturnStatusSuccessFinishResult); } + + if (m_option_variable.show_recognized_args) { + auto recognized_frame = frame->GetRecognizedFrame(); + if (recognized_frame) { + ValueObjectListSP recognized_arg_list = recognized_frame->GetRecognizedArguments(); + if (recognized_arg_list) { + for (size_t i = 0; i < recognized_arg_list->GetSize(); i++) { + valobj_sp = recognized_arg_list->GetValueObjectAtIndex(i); + + options.SetFormat(m_option_format.GetFormat()); + options.SetVariableFormatDisplayLanguage( + valobj_sp->GetPreferredDisplayLanguage()); + options.SetRootValueObjectName(valobj_sp->GetName().AsCString()); + valobj_sp->Dump(result.GetOutputStream(), options); + } + } + } + } if (m_interpreter.TruncationWarningNecessary()) { result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), @@ -735,6 +754,126 @@ OptionGroupValueObjectDisplay m_varobj_options; }; +#pragma mark CommandObjectFrameRecognizer + +static OptionDefinition g_frame_recognizer_add_options[] = { + // clang-format off + { LLDB_OPT_SET_ALL, false, "module", 'm', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "TODO" }, + { LLDB_OPT_SET_ALL, false, "function", 'n', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "TODO" }, + { LLDB_OPT_SET_2, false, "python-class", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "TODO" }, + { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "TODO" } + // clang-format on +}; + +class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { +private: + class CommandOptions : public Options { + public: + CommandOptions() : Options() {} + ~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; + + switch (short_option) { + case 'l': + m_class_name = std::string(option_arg); + break; + case 'm': + m_module = std::string(option_arg); + break; + case 'n': + m_function = std::string(option_arg); + break; + case 'x': + m_regex = true; + break; + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); + break; + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_module = ""; + m_function = ""; + m_class_name = ""; + m_regex = false; + } + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_frame_recognizer_add_options); + } + + // Instance variables to hold the values for command options. + std::string m_class_name; + std::string m_module; + std::string m_function; + bool m_regex; + }; + + CommandOptions m_options; + + Options *GetOptions() override { return &m_options; } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override; + +public: + CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) : + CommandObjectParsed(interpreter, "frame recognizer add", "TODO", nullptr), + m_options() {} + ~CommandObjectFrameRecognizerAdd() override = default; +}; + +bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, CommandReturnObject &result) { + if (m_options.m_class_name.empty()) { + result.AppendErrorWithFormat("%s needs a Python class name.\n", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); + + if (interpreter && !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { + result.AppendWarning("The provided class does not exist - please define it " + "before attempting to use this synthetic provider"); + } + + StackFrameRecognizerSP recognizer_sp = StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(interpreter, m_options.m_class_name.c_str())); + if (m_options.m_regex) { + auto module = RegularExpressionSP(new RegularExpression(m_options.m_module)); + auto func = RegularExpressionSP(new RegularExpression(m_options.m_function)); + StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); + } else { + auto module = ConstString(m_options.m_module); + auto func = ConstString(m_options.m_function); + StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); + } + + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return result.Succeeded(); +} + +class CommandObjectFrameRecognizer : public CommandObjectMultiword { +public: + CommandObjectFrameRecognizer(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "frame recognizer", + "Commands for editing frame recognizers.", + "frame recognizer [] ") { + LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(interpreter))); + //LoadSubCommand("clear", CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); + //LoadSubCommand("delete", CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); + //LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(interpreter))); + } + + ~CommandObjectFrameRecognizer() override = default; +}; + #pragma mark CommandObjectMultiwordFrame //------------------------------------------------------------------------- @@ -755,6 +894,9 @@ CommandObjectSP(new CommandObjectFrameSelect(interpreter))); LoadSubCommand("variable", CommandObjectSP(new CommandObjectFrameVariable(interpreter))); +#ifndef LLDB_DISABLE_PYTHON + LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(interpreter))); +#endif } CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; Index: source/Interpreter/OptionGroupVariable.cpp =================================================================== --- source/Interpreter/OptionGroupVariable.cpp +++ source/Interpreter/OptionGroupVariable.cpp @@ -28,6 +28,9 @@ {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-args", 'a', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Omit function arguments."}, + {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "recognized-args", 't', + OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, + "Show recognized function arguments."}, {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-locals", 'l', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Omit local variables."}, @@ -101,6 +104,9 @@ case 's': show_scope = true; break; + case 't': + show_recognized_args = true; + break; case 'y': error = summary.SetCurrentValue(option_arg); break; @@ -119,6 +125,7 @@ void OptionGroupVariable::OptionParsingStarting( ExecutionContext *execution_context) { show_args = true; // Frame option only + show_recognized_args = false; // Frame option only show_locals = true; // Frame option only show_globals = false; // Frame option only show_decl = false; Index: source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h =================================================================== --- source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h +++ source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -85,6 +85,11 @@ const char *session_dictionary_name, const lldb::ProcessSP &process_sp); + typedef void *(*SWIGPythonCreateFrameRecognizer)(const char *python_class_name, + const char *session_dictionary_name); + + typedef void *(*SWIGPythonGetRecognizedArguments)(void *implementor, const lldb::StackFrameSP &frame_sp); + typedef size_t (*SWIGPythonCalculateNumChildren)(void *implementor, uint32_t max); @@ -208,6 +213,12 @@ lldb::StateType ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp, bool &script_error) override; + + StructuredData::GenericSP + CreateFrameRecognizer(const char *class_name) override; + + lldb::ValueObjectListSP + GetRecognizedArguments(const StructuredData::ObjectSP &implementor, lldb::StackFrameSP frame_sp) override; StructuredData::GenericSP OSPlugin_CreatePluginObject(const char *class_name, @@ -405,6 +416,8 @@ SWIGPythonCallCommandObject swig_call_command_object, SWIGPythonCallModuleInit swig_call_module_init, SWIGPythonCreateOSPlugin swig_create_os_plugin, + SWIGPythonCreateFrameRecognizer swig_create_frame_recognizer, + SWIGPythonGetRecognizedArguments swig_get_recognized_arguments, SWIGPythonScriptKeyword_Process swig_run_script_keyword_process, SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, Index: source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp =================================================================== --- source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -27,6 +27,7 @@ #include #include "lldb/API/SBValue.h" +#include "lldb/API/SBFrame.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Breakpoint/WatchpointOptions.h" @@ -91,6 +92,10 @@ g_swig_call_module_init = nullptr; static ScriptInterpreterPython::SWIGPythonCreateOSPlugin g_swig_create_os_plugin = nullptr; +static ScriptInterpreterPython::SWIGPythonCreateFrameRecognizer + g_swig_create_frame_recognizer = nullptr; +static ScriptInterpreterPython::SWIGPythonGetRecognizedArguments + g_swig_get_recognized_arguments = nullptr; static ScriptInterpreterPython::SWIGPythonScriptKeyword_Process g_swig_run_script_keyword_process = nullptr; static ScriptInterpreterPython::SWIGPythonScriptKeyword_Thread @@ -1428,6 +1433,62 @@ return true; } +StructuredData::GenericSP +ScriptInterpreterPython::CreateFrameRecognizer(const char *class_name) { + if (class_name == nullptr || class_name[0] == '\0') + return StructuredData::GenericSP(); + + void *ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + ret_val = g_swig_create_frame_recognizer(class_name, m_dictionary_name.c_str()); + } + + return StructuredData::GenericSP(new StructuredPythonObject(ret_val)); +} + +lldb::ValueObjectListSP +ScriptInterpreterPython::GetRecognizedArguments(const StructuredData::ObjectSP &os_plugin_object_sp, lldb::StackFrameSP frame_sp) { + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + static char callee_name[] = "get_recognized_arguments"; + + if (!os_plugin_object_sp) + return ValueObjectListSP(); + + StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric(); + if (!generic) + return nullptr; + + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)generic->GetValue()); + + if (!implementor.IsAllocated()) + return ValueObjectListSP(); + + PythonObject py_return(PyRefType::Owned, + (PyObject *)g_swig_get_recognized_arguments(implementor.get(), frame_sp)); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + if (py_return.get()) { + PythonList result_list(PyRefType::Borrowed, py_return.get()); + ValueObjectListSP result = ValueObjectListSP(new ValueObjectList()); + for (int i = 0; i < result_list.GetSize(); i++) { + PyObject *item = result_list.GetItemAtIndex(i).get(); + lldb::SBValue *sb_value_ptr = (lldb::SBValue *)g_swig_cast_to_sbvalue(item); + if (sb_value_ptr->IsValid()) + result->Append(sb_value_ptr->GetSP()); + } + return result; + } + return ValueObjectListSP(); +} + StructuredData::GenericSP ScriptInterpreterPython::OSPlugin_CreatePluginObject( const char *class_name, lldb::ProcessSP process_sp) { if (class_name == nullptr || class_name[0] == '\0') @@ -3034,6 +3095,8 @@ SWIGPythonCallCommandObject swig_call_command_object, SWIGPythonCallModuleInit swig_call_module_init, SWIGPythonCreateOSPlugin swig_create_os_plugin, + SWIGPythonCreateFrameRecognizer swig_create_frame_recognizer, + SWIGPythonGetRecognizedArguments swig_get_recognized_arguments, SWIGPythonScriptKeyword_Process swig_run_script_keyword_process, SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, @@ -3060,6 +3123,8 @@ g_swig_call_command_object = swig_call_command_object; g_swig_call_module_init = swig_call_module_init; g_swig_create_os_plugin = swig_create_os_plugin; + g_swig_create_frame_recognizer = swig_create_frame_recognizer; + g_swig_get_recognized_arguments = swig_get_recognized_arguments; g_swig_run_script_keyword_process = swig_run_script_keyword_process; g_swig_run_script_keyword_thread = swig_run_script_keyword_thread; g_swig_run_script_keyword_target = swig_run_script_keyword_target; Index: source/Target/CMakeLists.txt =================================================================== --- source/Target/CMakeLists.txt +++ source/Target/CMakeLists.txt @@ -28,6 +28,7 @@ SectionLoadList.cpp StackFrame.cpp StackFrameList.cpp + StackFrameRecognizer.cpp StackID.cpp StopInfo.cpp StructuredDataPlugin.cpp Index: source/Target/StackFrame.cpp =================================================================== --- source/Target/StackFrame.cpp +++ source/Target/StackFrame.cpp @@ -32,6 +32,7 @@ #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -58,7 +59,7 @@ m_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid), m_stop_id(stop_id), m_stop_id_is_valid(stop_id_is_valid), m_is_history_frame(is_history_frame), m_variable_list_sp(), - m_variable_list_value_objects(), m_disassembly(), m_mutex() { + m_variable_list_value_objects(), m_recognized(), m_recognized_frame(), m_disassembly(), m_mutex() { // If we don't have a CFA value, use the frame index for our StackID so that // recursive functions properly aren't confused with one another on a history // stack. @@ -82,7 +83,7 @@ m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(), m_frame_base_error(), m_cfa_is_valid(true), m_stop_id(0), m_stop_id_is_valid(false), m_is_history_frame(false), - m_variable_list_sp(), m_variable_list_value_objects(), m_disassembly(), + m_variable_list_sp(), m_variable_list_value_objects(), m_recognized(), m_recognized_frame(), m_disassembly(), m_mutex() { if (sc_ptr != nullptr) { m_sc = *sc_ptr; @@ -108,7 +109,7 @@ m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(), m_frame_base_error(), m_cfa_is_valid(true), m_stop_id(0), m_stop_id_is_valid(false), m_is_history_frame(false), - m_variable_list_sp(), m_variable_list_value_objects(), m_disassembly(), + m_variable_list_sp(), m_variable_list_value_objects(), m_recognized(), m_recognized_frame(), m_disassembly(), m_mutex() { if (sc_ptr != nullptr) { m_sc = *sc_ptr; @@ -1910,3 +1911,12 @@ } return true; } + +RecognizedStackFrameSP StackFrame::GetRecognizedFrame() { + if (!m_recognized) { + m_recognized_frame = + StackFrameRecognizerManager::RecognizeFrame(CalculateStackFrame()); + m_recognized = true; + } + return m_recognized_frame; +} Index: source/Target/StackFrameRecognizer.cpp =================================================================== --- source/Target/StackFrameRecognizer.cpp +++ source/Target/StackFrameRecognizer.cpp @@ -0,0 +1,134 @@ +//===-- StackFrameRecognizer.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +#include +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Module.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/StackFrameRecognizer.h" +#include "lldb/Utility/RegularExpression.h" + +using namespace lldb; +using namespace lldb_private; + +class ScriptedRecognizedStackFrame : public RecognizedStackFrame { +public: + ScriptedRecognizedStackFrame(ValueObjectListSP args) { + m_arguments = args; + } +}; + +ScriptedStackFrameRecognizer::ScriptedStackFrameRecognizer(ScriptInterpreter *interpreter, const char *pclass) : + m_interpreter(interpreter), m_python_class(pclass) { + m_python_object_sp = m_interpreter->CreateFrameRecognizer(m_python_class.c_str()); +} + +RecognizedStackFrameSP +ScriptedStackFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame) { + if (!m_python_object_sp || !m_interpreter) + return RecognizedStackFrameSP(); + + ValueObjectListSP args = m_interpreter->GetRecognizedArguments(m_python_object_sp, frame); + + return RecognizedStackFrameSP(new ScriptedRecognizedStackFrame(args)); +} + +class StackFrameRecognizerManagerImpl { +public: + void AddRecognizer(StackFrameRecognizerSP recognizer, ConstString &module, + ConstString &symbol, bool first_instruction_only) { + m_recognizers.push_back({recognizer, module, RegularExpressionSP(), symbol, + RegularExpressionSP(), first_instruction_only}); + } + + void AddRecognizer(StackFrameRecognizerSP recognizer, + RegularExpressionSP module, RegularExpressionSP symbol, + bool first_instruction_only) { + m_recognizers.push_back({recognizer, ConstString(), module, ConstString(), + symbol, first_instruction_only}); + } + + RecognizedStackFrameSP RecognizeFrame(StackFrameSP frame) { + const SymbolContext &symctx = + frame->GetSymbolContext(eSymbolContextModule | eSymbolContextFunction); + ConstString function_name = symctx.GetFunctionName(); + ConstString module_name = symctx.module_sp->GetFileSpec().GetFilename(); + Address start_addr = symctx.symbol->GetAddress(); + Address current_addr = frame->GetFrameCodeAddress(); + + for (auto entry : m_recognizers) { + if (entry.module) + if (entry.module != module_name) + continue; + + if (entry.module_regexp) + if (!entry.module_regexp->Execute(module_name.GetStringRef())) + continue; + + if (entry.symbol) + if (entry.symbol != function_name) + continue; + + if (entry.symbol_regexp) + if (!entry.symbol_regexp->Execute(function_name.GetStringRef())) + continue; + + if (entry.first_instruction_only) + if (start_addr != current_addr) + continue; + + auto recognized_frame = entry.recognizer->RecognizeFrame(frame); + if (recognized_frame) + return recognized_frame; + } + return RecognizedStackFrameSP(); + } + +private: + struct RegisteredEntry { + StackFrameRecognizerSP recognizer; + ConstString module; + RegularExpressionSP module_regexp; + ConstString symbol; + RegularExpressionSP symbol_regexp; + bool first_instruction_only; + }; + + std::vector m_recognizers; +}; + +StackFrameRecognizerManagerImpl &GetStackFrameRecognizerManagerImpl() { + static StackFrameRecognizerManagerImpl instance = + StackFrameRecognizerManagerImpl(); + return instance; +} + +void StackFrameRecognizerManager::AddRecognizer( + StackFrameRecognizerSP recognizer, ConstString &module, ConstString &symbol, + bool first_instruction_only) { + GetStackFrameRecognizerManagerImpl().AddRecognizer(recognizer, module, symbol, + first_instruction_only); +} + +void StackFrameRecognizerManager::AddRecognizer( + StackFrameRecognizerSP recognizer, RegularExpressionSP module, + RegularExpressionSP symbol, bool first_instruction_only) { + GetStackFrameRecognizerManagerImpl().AddRecognizer(recognizer, module, symbol, + first_instruction_only); +} + +RecognizedStackFrameSP +StackFrameRecognizerManager::RecognizeFrame(StackFrameSP frame) { + return GetStackFrameRecognizerManagerImpl().RecognizeFrame(frame); +}