diff options
Diffstat (limited to 'lldb/source')
-rw-r--r-- | lldb/source/API/SBFrame.cpp | 25 | ||||
-rw-r--r-- | lldb/source/API/SBVariablesOptions.cpp | 23 | ||||
-rw-r--r-- | lldb/source/API/SystemInitializerFull.cpp | 11 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectFrame.cpp | 386 | ||||
-rw-r--r-- | lldb/source/Interpreter/OptionGroupVariable.cpp | 7 | ||||
-rw-r--r-- | lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp | 64 | ||||
-rw-r--r-- | lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h | 15 | ||||
-rw-r--r-- | lldb/source/Target/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lldb/source/Target/StackFrame.cpp | 18 | ||||
-rw-r--r-- | lldb/source/Target/StackFrameRecognizer.cpp | 190 |
10 files changed, 729 insertions, 11 deletions
diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp index 8a9088de176..33348f8bcdf 100644 --- a/lldb/source/API/SBFrame.cpp +++ b/lldb/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" @@ -960,6 +961,7 @@ SBValueList SBFrame::GetVariables(const lldb::SBVariablesOptions &options) { 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 = @@ -967,10 +969,11 @@ SBValueList SBFrame::GetVariables(const lldb::SBVariablesOptions &options) { const lldb::DynamicValueType use_dynamic = options.GetUseDynamic(); if (log) - log->Printf("SBFrame::GetVariables (arguments=%i, locals=%i, statics=%i, " - "in_scope_only=%i runtime=%i dynamic=%i)", - arguments, locals, statics, in_scope_only, - include_runtime_support_values, use_dynamic); + log->Printf( + "SBFrame::GetVariables (arguments=%i, recognized_arguments=%i, " + "locals=%i, statics=%i, in_scope_only=%i runtime=%i dynamic=%i)", + arguments, recognized_arguments, locals, statics, in_scope_only, + include_runtime_support_values, use_dynamic); std::set<VariableSP> variable_set; Process *process = exe_ctx.GetProcessPtr(); @@ -1032,6 +1035,20 @@ SBValueList SBFrame::GetVariables(const lldb::SBVariablesOptions &options) { } } } + if (recognized_arguments) { + auto recognized_frame = frame->GetRecognizedFrame(); + if (recognized_frame) { + ValueObjectListSP recognized_arg_list = + recognized_frame->GetRecognizedArguments(); + if (recognized_arg_list) { + for (auto &rec_value_sp : recognized_arg_list->GetObjects()) { + SBValue value_sb; + value_sb.SetSP(rec_value_sp, use_dynamic); + value_list.Append(value_sb); + } + } + } + } } else { if (log) log->Printf("SBFrame::GetVariables () => error: could not " diff --git a/lldb/source/API/SBVariablesOptions.cpp b/lldb/source/API/SBVariablesOptions.cpp index e12b9696521..ae069756de1 100644 --- a/lldb/source/API/SBVariablesOptions.cpp +++ b/lldb/source/API/SBVariablesOptions.cpp @@ -16,9 +16,9 @@ using namespace lldb_private; class VariablesOptionsImpl { public: VariablesOptionsImpl() - : m_include_arguments(false), m_include_locals(false), - m_include_statics(false), m_in_scope_only(false), - m_include_runtime_support_values(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) {} VariablesOptionsImpl(const VariablesOptionsImpl &) = default; @@ -31,6 +31,14 @@ public: 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 +65,7 @@ public: 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 +99,14 @@ void SBVariablesOptions::SetIncludeArguments(bool arguments) { 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(); } diff --git a/lldb/source/API/SystemInitializerFull.cpp b/lldb/source/API/SystemInitializerFull.cpp index fab9171c478..2e649d5baea 100644 --- a/lldb/source/API/SystemInitializerFull.cpp +++ b/lldb/source/API/SystemInitializerFull.cpp @@ -235,6 +235,13 @@ LLDBSWIGPythonCreateOSPlugin(const char *python_class_name, 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); @@ -423,7 +430,9 @@ void SystemInitializerFull::InitializeSWIG() { LLDBSwigPython_MightHaveChildrenSynthProviderInstance, LLDBSwigPython_GetValueSynthProviderInstance, LLDBSwigPythonCallCommand, LLDBSwigPythonCallCommandObject, LLDBSwigPythonCallModuleInit, - LLDBSWIGPythonCreateOSPlugin, LLDBSWIGPythonRunScriptKeywordProcess, + LLDBSWIGPythonCreateOSPlugin, LLDBSWIGPython_CreateFrameRecognizer, + LLDBSwigPython_GetRecognizedArguments, + LLDBSWIGPythonRunScriptKeywordProcess, LLDBSWIGPythonRunScriptKeywordThread, LLDBSWIGPythonRunScriptKeywordTarget, LLDBSWIGPythonRunScriptKeywordFrame, LLDBSWIGPythonRunScriptKeywordValue, LLDBSWIGPython_GetDynamicSetting, diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp index 5424bcdf103..0dface68714 100644 --- a/lldb/source/Commands/CommandObjectFrame.cpp +++ b/lldb/source/Commands/CommandObjectFrame.cpp @@ -24,6 +24,7 @@ #include "lldb/DataFormatters/ValueObjectPrinter.h" #include "lldb/Host/Host.h" #include "lldb/Host/OptionParser.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionGroupFormat.h" @@ -40,6 +41,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" @@ -715,6 +717,23 @@ protected: 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 (auto &rec_value_sp : recognized_arg_list->GetObjects()) { + options.SetFormat(m_option_format.GetFormat()); + options.SetVariableFormatDisplayLanguage( + rec_value_sp->GetPreferredDisplayLanguage()); + options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); + rec_value_sp->Dump(result.GetOutputStream(), options); + } + } + } + } + if (m_interpreter.TruncationWarningNecessary()) { result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), m_cmd_name.c_str()); @@ -738,6 +757,368 @@ protected: OptionGroupValueObjectDisplay m_varobj_options; }; +#pragma mark CommandObjectFrameRecognizer + +static OptionDefinition g_frame_recognizer_add_options[] = { + // clang-format off + { LLDB_OPT_SET_ALL, false, "shlib", 's', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Name of the module or shared library that this recognizer applies to." }, + { LLDB_OPT_SET_ALL, false, "function", 'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeName, "Name of the function that this recognizer applies to." }, + { LLDB_OPT_SET_2, false, "python-class", 'l', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypePythonClass, "Give the name of a Python class to use for this frame recognizer." }, + { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Function name and module name are actually regular expressions." } + // 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 's': + 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<OptionDefinition> 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", + "Add a new frame recognizer.", nullptr), + m_options() { + 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 +code or debug info. Currently, one use case is to extract function arguments +that would otherwise be unaccesible, or augment existing arguments. + +Adding a custom frame recognizer is possible by implementing a Python class +and using the 'frame recognizer add' command. The Python class should have a +'get_recognized_arguments' method and it will receive an argument of type +lldb.SBFrame representing the current frame that we are trying to recognize. +The method should return a (possibly empty) list of lldb.SBValue objects that +represent the recognized arguments. + +An example of a recognizer that retrieves the file descriptor values from libc +functions 'read', 'write' and 'close' follows: + + class LibcFdRecognizer(object): + def get_recognized_arguments(self, frame): + if frame.name in ["read", "write", "close"]: + fd = frame.EvaluateExpression("$arg1").unsigned + value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd) + return [value] + return [] + +The file containing this implementation can be imported via 'command script +import' and then we can register this recognizer with 'frame recognizer add'. +It's important to restrict the recognizer to the libc library (which is +libsystem_kernel.dylib on macOS) to avoid matching functions with the same name +in other modules: + +(lldb) command script import .../fd_recognizer.py +(lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib + +When the program is stopped at the beginning of the 'read' function in libc, we +can view the recognizer arguments in 'frame variable': + +(lldb) b read +(lldb) r +Process 1234 stopped +* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 + frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read +(lldb) frame variable +(int) fd = 3 + + )"); + } + ~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 (-l argument).\n", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (m_options.m_module.empty()) { + result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (m_options.m_function.empty()) { + result.AppendErrorWithFormat("%s needs a function name (-n argument).\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 frame recognizer"); + } + + 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 CommandObjectFrameRecognizerClear : public CommandObjectParsed { +public: + CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "frame recognizer clear", + "Delete all frame recognizers.", nullptr) {} + + ~CommandObjectFrameRecognizerClear() override = default; + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + StackFrameRecognizerManager::RemoveAllRecognizers(); + result.SetStatus(eReturnStatusSuccessFinishResult); + return result.Succeeded(); + } +}; + +class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { + public: + CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "frame recognizer delete", + "Delete an existing frame recognizer.", nullptr) {} + + ~CommandObjectFrameRecognizerDelete() override = default; + + protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (command.GetArgumentCount() == 0) { + if (!m_interpreter.Confirm( + "About to delete all frame recognizers, do you want to do that?", + true)) { + result.AppendMessage("Operation cancelled..."); + result.SetStatus(eReturnStatusFailed); + return false; + } + + StackFrameRecognizerManager::RemoveAllRecognizers(); + result.SetStatus(eReturnStatusSuccessFinishResult); + return result.Succeeded(); + } + + if (command.GetArgumentCount() != 1) { + result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + uint32_t recognizer_id = + StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); + + StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id); + result.SetStatus(eReturnStatusSuccessFinishResult); + return result.Succeeded(); + } +}; + +class CommandObjectFrameRecognizerList : public CommandObjectParsed { + public: + CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "frame recognizer list", + "Show a list of active frame recognizers.", + nullptr) {} + + ~CommandObjectFrameRecognizerList() override = default; + + protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + bool any_printed = false; + StackFrameRecognizerManager::ForEach( + [&result, &any_printed](uint32_t recognizer_id, std::string name, + std::string function, std::string symbol, + bool regexp) { + if (name == "") name = "(internal)"; + result.GetOutputStream().Printf( + "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(), + function.c_str(), symbol.c_str(), regexp ? " (regexp)" : ""); + any_printed = true; + }); + + if (any_printed) + result.SetStatus(eReturnStatusSuccessFinishResult); + else { + result.GetOutputStream().PutCString("no matching results found.\n"); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + return result.Succeeded(); + } +}; + +class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { + public: + CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "frame recognizer info", + "Show which frame recognizer is applied a stack frame (if any).", + nullptr) { + CommandArgumentEntry arg; + CommandArgumentData index_arg; + + // Define the first (and only) variant of this arg. + index_arg.arg_type = eArgTypeFrameIndex; + index_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg.push_back(index_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg); + } + + ~CommandObjectFrameRecognizerInfo() override = default; + + protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + Process *process = m_exe_ctx.GetProcessPtr(); + if (process == nullptr) { + result.AppendError("no process"); + result.SetStatus(eReturnStatusFailed); + return false; + } + Thread *thread = m_exe_ctx.GetThreadPtr(); + if (thread == nullptr) { + result.AppendError("no thread"); + result.SetStatus(eReturnStatusFailed); + return false; + } + if (command.GetArgumentCount() != 1) { + result.AppendErrorWithFormat( + "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + uint32_t frame_index = + StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); + StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); + if (!frame_sp) { + result.AppendErrorWithFormat("no frame with index %u", frame_index); + result.SetStatus(eReturnStatusFailed); + return false; + } + + auto recognizer = + StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp); + + Stream &output_stream = result.GetOutputStream(); + output_stream.Printf("frame %d ", frame_index); + if (recognizer) { + output_stream << "is recognized by "; + output_stream << recognizer->GetName(); + } else { + output_stream << "not recognized by any recognizer"; + } + output_stream.EOL(); + result.SetStatus(eReturnStatusSuccessFinishResult); + return result.Succeeded(); + } +}; + +class CommandObjectFrameRecognizer : public CommandObjectMultiword { + public: + CommandObjectFrameRecognizer(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "frame recognizer", + "Commands for editing and viewing frame recognizers.", + "frame recognizer [<sub-command-options>] ") { + LoadSubCommand( + "add", + CommandObjectSP(new CommandObjectFrameRecognizerAdd(interpreter))); + LoadSubCommand( + "clear", + CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); + LoadSubCommand( + "delete", + CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); + LoadSubCommand( + "list", + CommandObjectSP(new CommandObjectFrameRecognizerList(interpreter))); + LoadSubCommand( + "info", + CommandObjectSP(new CommandObjectFrameRecognizerInfo(interpreter))); + } + + ~CommandObjectFrameRecognizer() override = default; +}; + #pragma mark CommandObjectMultiwordFrame //------------------------------------------------------------------------- @@ -758,6 +1139,11 @@ CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( CommandObjectSP(new CommandObjectFrameSelect(interpreter))); LoadSubCommand("variable", CommandObjectSP(new CommandObjectFrameVariable(interpreter))); +#ifndef LLDB_DISABLE_PYTHON + LoadSubCommand( + "recognizer", + CommandObjectSP(new CommandObjectFrameRecognizer(interpreter))); +#endif } CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; diff --git a/lldb/source/Interpreter/OptionGroupVariable.cpp b/lldb/source/Interpreter/OptionGroupVariable.cpp index 1bcddb4b49f..f35aeb6aa55 100644 --- a/lldb/source/Interpreter/OptionGroupVariable.cpp +++ b/lldb/source/Interpreter/OptionGroupVariable.cpp @@ -28,6 +28,9 @@ static constexpr OptionDefinition g_variable_options[] = { {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-args", 'a', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Omit function arguments."}, + {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-recognized-args", 't', + OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, + "Omit recognized function arguments."}, {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-locals", 'l', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Omit local variables."}, @@ -101,6 +104,9 @@ OptionGroupVariable::SetOptionValue(uint32_t option_idx, case 's': show_scope = true; break; + case 't': + show_recognized_args = false; + break; case 'y': error = summary.SetCurrentValue(option_arg); break; @@ -119,6 +125,7 @@ OptionGroupVariable::SetOptionValue(uint32_t option_idx, void OptionGroupVariable::OptionParsingStarting( ExecutionContext *execution_context) { show_args = true; // Frame option only + show_recognized_args = true; // Frame option only show_locals = true; // Frame option only show_globals = false; // Frame option only show_decl = false; diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 0db28294ebd..af3687a9954 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -27,6 +27,7 @@ #include <string> #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 @@ static ScriptInterpreterPython::SWIGPythonCallModuleInit 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 @@ -1498,6 +1503,61 @@ bool ScriptInterpreterPython::GenerateTypeSynthClass(StringList &user_input, 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); + + 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') @@ -3185,6 +3245,8 @@ void ScriptInterpreterPython::InitializeInterpreter( 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, @@ -3213,6 +3275,8 @@ void ScriptInterpreterPython::InitializeInterpreter( 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; diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h index ef29a9628be..7314bba7cc6 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -94,6 +94,12 @@ public: 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); @@ -232,6 +238,13 @@ public: implementor_sp) 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, lldb::ProcessSP process_sp) override; @@ -426,6 +439,8 @@ public: 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, diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt index df137c314af..265b3a80779 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -28,6 +28,7 @@ add_lldb_library(lldbTarget SectionLoadList.cpp StackFrame.cpp StackFrameList.cpp + StackFrameRecognizer.cpp StackID.cpp StopInfo.cpp StructuredDataPlugin.cpp diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 00be79d6f31..6340459dea3 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -31,6 +31,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" #include "lldb/Utility/RegisterValue.h" @@ -58,7 +59,8 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, m_id(pc, cfa, nullptr), m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid), m_stack_frame_kind(kind), m_variable_list_sp(), - m_variable_list_value_objects(), m_disassembly(), m_mutex() { + m_variable_list_value_objects(), m_recognized_frame_sp(), 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 +84,8 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(), m_frame_base_error(), m_cfa_is_valid(true), m_stack_frame_kind(StackFrame::Kind::Regular), m_variable_list_sp(), - m_variable_list_value_objects(), m_disassembly(), m_mutex() { + m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(), + m_mutex() { if (sc_ptr != nullptr) { m_sc = *sc_ptr; m_flags.Set(m_sc.GetResolvedMask()); @@ -107,7 +110,8 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(), m_frame_base_error(), m_cfa_is_valid(true), m_stack_frame_kind(StackFrame::Kind::Regular), m_variable_list_sp(), - m_variable_list_value_objects(), m_disassembly(), m_mutex() { + m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(), + m_mutex() { if (sc_ptr != nullptr) { m_sc = *sc_ptr; m_flags.Set(m_sc.GetResolvedMask()); @@ -1952,3 +1956,11 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source, } return true; } + +RecognizedStackFrameSP StackFrame::GetRecognizedFrame() { + if (!m_recognized_frame_sp) { + m_recognized_frame_sp = + StackFrameRecognizerManager::RecognizeFrame(CalculateStackFrame()); + } + return m_recognized_frame_sp; +} diff --git a/lldb/source/Target/StackFrameRecognizer.cpp b/lldb/source/Target/StackFrameRecognizer.cpp index e69de29bb2d..cb8603699c3 100644 --- a/lldb/source/Target/StackFrameRecognizer.cpp +++ b/lldb/source/Target/StackFrameRecognizer.cpp @@ -0,0 +1,190 @@ +//===-- 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 <vector> +// 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_front({(uint32_t)m_recognizers.size(), false, recognizer, false, module, RegularExpressionSP(), + symbol, RegularExpressionSP(), + first_instruction_only}); + } + + void AddRecognizer(StackFrameRecognizerSP recognizer, + RegularExpressionSP module, RegularExpressionSP symbol, + bool first_instruction_only) { + m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, true, ConstString(), module, + ConstString(), symbol, first_instruction_only}); + } + + void ForEach( + std::function<void(uint32_t recognized_id, std::string recognizer_name, std::string module, + std::string symbol, bool regexp)> const &callback) { + for (auto entry : m_recognizers) { + if (entry.is_regexp) { + callback(entry.recognizer_id, entry.recognizer->GetName(), entry.module_regexp->GetText(), + entry.symbol_regexp->GetText(), true); + } else { + callback(entry.recognizer_id, entry.recognizer->GetName(), entry.module.GetCString(), + entry.symbol.GetCString(), false); + } + } + } + + bool RemoveRecognizerWithID(uint32_t recognizer_id) { + if (recognizer_id >= m_recognizers.size()) return false; + if (m_recognizers[recognizer_id].deleted) return false; + m_recognizers[recognizer_id].deleted = true; + return true; + } + + void RemoveAllRecognizers() { + m_recognizers.clear(); + } + + StackFrameRecognizerSP GetRecognizerForFrame(StackFrameSP frame) { + const SymbolContext &symctx = + frame->GetSymbolContext(eSymbolContextModule | eSymbolContextFunction); + ConstString function_name = symctx.GetFunctionName(); + ModuleSP module_sp = symctx.module_sp; + if (!module_sp) return StackFrameRecognizerSP(); + ConstString module_name = module_sp->GetFileSpec().GetFilename(); + Symbol *symbol = symctx.symbol; + if (!symbol) return StackFrameRecognizerSP(); + Address start_addr = symbol->GetAddress(); + Address current_addr = frame->GetFrameCodeAddress(); + + for (auto entry : m_recognizers) { + if (entry.deleted) continue; + 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; + + return entry.recognizer; + } + return StackFrameRecognizerSP(); + } + + RecognizedStackFrameSP RecognizeFrame(StackFrameSP frame) { + auto recognizer = GetRecognizerForFrame(frame); + if (!recognizer) return RecognizedStackFrameSP(); + return recognizer->RecognizeFrame(frame); + } + + private: + struct RegisteredEntry { + uint32_t recognizer_id; + bool deleted; + StackFrameRecognizerSP recognizer; + bool is_regexp; + ConstString module; + RegularExpressionSP module_regexp; + ConstString symbol; + RegularExpressionSP symbol_regexp; + bool first_instruction_only; + }; + + std::deque<RegisteredEntry> 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); +} + +void StackFrameRecognizerManager::ForEach( + std::function<void(uint32_t recognized_id, std::string recognizer_name, std::string module, + std::string symbol, bool regexp)> const &callback) { + GetStackFrameRecognizerManagerImpl().ForEach(callback); +} + +void StackFrameRecognizerManager::RemoveAllRecognizers() { + GetStackFrameRecognizerManagerImpl().RemoveAllRecognizers(); +} + +bool StackFrameRecognizerManager::RemoveRecognizerWithID(uint32_t recognizer_id) { + return GetStackFrameRecognizerManagerImpl().RemoveRecognizerWithID(recognizer_id); +} + +RecognizedStackFrameSP StackFrameRecognizerManager::RecognizeFrame( + StackFrameSP frame) { + return GetStackFrameRecognizerManagerImpl().RecognizeFrame(frame); +} + +StackFrameRecognizerSP StackFrameRecognizerManager::GetRecognizerForFrame( + lldb::StackFrameSP frame) { + return GetStackFrameRecognizerManagerImpl().GetRecognizerForFrame(frame); +} |