forked from OSchip/llvm-project
[lldb] Introduce StackFrameRecognizer
This patch introduces a concept of "frame recognizer" and "recognized frame". This should be an extensible mechanism that retrieves information about special frames based on ABI, arguments or other special properties of that frame, even without source code. A few examples where that could be useful could be 1) objc_exception_throw, where we'd like to get the current exception, 2) terminate_with_reason and extracting the current terminate string, 3) recognizing Objective-C frames and automatically extracting the receiver+selector, or perhaps all arguments (based on selector). Differential Revision: https://reviews.llvm.org/D44603 llvm-svn: 345678
This commit is contained in:
parent
1079d7ccfe
commit
ac0ba8c524
|
@ -33,6 +33,10 @@ public:
|
||||||
|
|
||||||
void SetIncludeArguments(bool);
|
void SetIncludeArguments(bool);
|
||||||
|
|
||||||
|
bool GetIncludeRecognizedArguments() const;
|
||||||
|
|
||||||
|
void SetIncludeRecognizedArguments(bool);
|
||||||
|
|
||||||
bool GetIncludeLocals() const;
|
bool GetIncludeLocals() const;
|
||||||
|
|
||||||
void SetIncludeLocals(bool);
|
void SetIncludeLocals(bool);
|
||||||
|
|
|
@ -39,6 +39,8 @@ public:
|
||||||
|
|
||||||
bool include_frame_options : 1,
|
bool include_frame_options : 1,
|
||||||
show_args : 1, // Frame option only (include_frame_options == true)
|
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_locals : 1, // Frame option only (include_frame_options == true)
|
||||||
show_globals : 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;
|
use_regex : 1, show_scope : 1, show_decl : 1;
|
||||||
|
|
|
@ -173,6 +173,17 @@ public:
|
||||||
return StructuredData::GenericSP();
|
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
|
virtual StructuredData::GenericSP
|
||||||
OSPlugin_CreatePluginObject(const char *class_name,
|
OSPlugin_CreatePluginObject(const char *class_name,
|
||||||
lldb::ProcessSP process_sp) {
|
lldb::ProcessSP process_sp) {
|
||||||
|
|
|
@ -544,6 +544,8 @@ public:
|
||||||
|
|
||||||
void CalculateExecutionContext(ExecutionContext &exe_ctx) override;
|
void CalculateExecutionContext(ExecutionContext &exe_ctx) override;
|
||||||
|
|
||||||
|
lldb::RecognizedStackFrameSP GetRecognizedFrame();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class StackFrameList;
|
friend class StackFrameList;
|
||||||
|
|
||||||
|
@ -578,6 +580,7 @@ private:
|
||||||
ValueObjectList m_variable_list_value_objects; // Value objects for each
|
ValueObjectList m_variable_list_value_objects; // Value objects for each
|
||||||
// variable in
|
// variable in
|
||||||
// m_variable_list_sp
|
// m_variable_list_sp
|
||||||
|
lldb::RecognizedStackFrameSP m_recognized_frame_sp;
|
||||||
StreamString m_disassembly;
|
StreamString m_disassembly;
|
||||||
std::recursive_mutex m_mutex;
|
std::recursive_mutex m_mutex;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
//===-- StackFrameRecognizer.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_StackFrameRecognizer_h_
|
||||||
|
#define liblldb_StackFrameRecognizer_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
|
||||||
|
///
|
||||||
|
/// This class provides extra information about a stack frame that was
|
||||||
|
/// provided by a specific stack frame recognizer. Right now, this class only
|
||||||
|
/// holds recognized arguments (via GetRecognizedArguments).
|
||||||
|
|
||||||
|
class RecognizedStackFrame
|
||||||
|
: std::enable_shared_from_this<RecognizedStackFrame> {
|
||||||
|
public:
|
||||||
|
virtual lldb::ValueObjectListSP GetRecognizedArguments() {
|
||||||
|
return m_arguments;
|
||||||
|
}
|
||||||
|
virtual ~RecognizedStackFrame(){};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
lldb::ValueObjectListSP m_arguments;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @class StackFrameRecognizer
|
||||||
|
///
|
||||||
|
/// A base class for frame recognizers. Subclasses (actual frame recognizers)
|
||||||
|
/// should implement RecognizeFrame to provide a RecognizedStackFrame for a
|
||||||
|
/// given stack frame.
|
||||||
|
|
||||||
|
class StackFrameRecognizer
|
||||||
|
: std::enable_shared_from_this<StackFrameRecognizer> {
|
||||||
|
public:
|
||||||
|
virtual lldb::RecognizedStackFrameSP RecognizeFrame(
|
||||||
|
lldb::StackFrameSP frame) {
|
||||||
|
return lldb::RecognizedStackFrameSP();
|
||||||
|
};
|
||||||
|
virtual std::string GetName() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~StackFrameRecognizer(){};
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef LLDB_DISABLE_PYTHON
|
||||||
|
|
||||||
|
/// @class ScriptedStackFrameRecognizer
|
||||||
|
///
|
||||||
|
/// Python implementation for frame recognizers. An instance of this class
|
||||||
|
/// tracks a particular Python classobject, which will be asked to recognize
|
||||||
|
/// stack frames.
|
||||||
|
|
||||||
|
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() {}
|
||||||
|
|
||||||
|
std::string GetName() override {
|
||||||
|
return GetPythonClassName();
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
///
|
||||||
|
/// Static class that provides a registry of known stack frame recognizers.
|
||||||
|
/// Has static methods to add, enumerate, remove, query and invoke recognizers.
|
||||||
|
|
||||||
|
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 void ForEach(
|
||||||
|
std::function<void(uint32_t recognizer_id, std::string recognizer_name,
|
||||||
|
std::string module, std::string symbol,
|
||||||
|
bool regexp)> const &callback);
|
||||||
|
|
||||||
|
static bool RemoveRecognizerWithID(uint32_t recognizer_id);
|
||||||
|
|
||||||
|
static void RemoveAllRecognizers();
|
||||||
|
|
||||||
|
static lldb::StackFrameRecognizerSP GetRecognizerForFrame(
|
||||||
|
lldb::StackFrameSP frame);
|
||||||
|
|
||||||
|
static lldb::RecognizedStackFrameSP RecognizeFrame(lldb::StackFrameSP frame);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lldb_private
|
||||||
|
|
||||||
|
#endif // liblldb_StackFrameRecognizer_h_
|
|
@ -184,6 +184,7 @@ class ProcessInstanceInfoMatch;
|
||||||
class ProcessLaunchInfo;
|
class ProcessLaunchInfo;
|
||||||
class Property;
|
class Property;
|
||||||
struct PropertyDefinition;
|
struct PropertyDefinition;
|
||||||
|
class RecognizedStackFrame;
|
||||||
class RegisterCheckpoint;
|
class RegisterCheckpoint;
|
||||||
class RegisterContext;
|
class RegisterContext;
|
||||||
class RegisterLocation;
|
class RegisterLocation;
|
||||||
|
@ -208,6 +209,8 @@ class SourceManagerImpl;
|
||||||
class StackFrame;
|
class StackFrame;
|
||||||
class StackFrameImpl;
|
class StackFrameImpl;
|
||||||
class StackFrameList;
|
class StackFrameList;
|
||||||
|
class StackFrameRecognizer;
|
||||||
|
class StackFrameRecognizerManager;
|
||||||
class StackID;
|
class StackID;
|
||||||
class StopInfo;
|
class StopInfo;
|
||||||
class Stoppoint;
|
class Stoppoint;
|
||||||
|
@ -414,6 +417,8 @@ typedef std::shared_ptr<lldb_private::Queue> QueueSP;
|
||||||
typedef std::weak_ptr<lldb_private::Queue> QueueWP;
|
typedef std::weak_ptr<lldb_private::Queue> QueueWP;
|
||||||
typedef std::shared_ptr<lldb_private::QueueItem> QueueItemSP;
|
typedef std::shared_ptr<lldb_private::QueueItem> QueueItemSP;
|
||||||
typedef std::shared_ptr<lldb_private::REPL> REPLSP;
|
typedef std::shared_ptr<lldb_private::REPL> REPLSP;
|
||||||
|
typedef std::shared_ptr<lldb_private::RecognizedStackFrame>
|
||||||
|
RecognizedStackFrameSP;
|
||||||
typedef std::shared_ptr<lldb_private::ScriptSummaryFormat>
|
typedef std::shared_ptr<lldb_private::ScriptSummaryFormat>
|
||||||
ScriptSummaryFormatSP;
|
ScriptSummaryFormatSP;
|
||||||
typedef std::shared_ptr<lldb_private::ScriptInterpreter> ScriptInterpreterSP;
|
typedef std::shared_ptr<lldb_private::ScriptInterpreter> ScriptInterpreterSP;
|
||||||
|
@ -429,6 +434,8 @@ typedef std::shared_ptr<lldb_private::StackFrame> StackFrameSP;
|
||||||
typedef std::unique_ptr<lldb_private::StackFrame> StackFrameUP;
|
typedef std::unique_ptr<lldb_private::StackFrame> StackFrameUP;
|
||||||
typedef std::weak_ptr<lldb_private::StackFrame> StackFrameWP;
|
typedef std::weak_ptr<lldb_private::StackFrame> StackFrameWP;
|
||||||
typedef std::shared_ptr<lldb_private::StackFrameList> StackFrameListSP;
|
typedef std::shared_ptr<lldb_private::StackFrameList> StackFrameListSP;
|
||||||
|
typedef std::shared_ptr<lldb_private::StackFrameRecognizer>
|
||||||
|
StackFrameRecognizerSP;
|
||||||
typedef std::shared_ptr<lldb_private::StopInfo> StopInfoSP;
|
typedef std::shared_ptr<lldb_private::StopInfo> StopInfoSP;
|
||||||
typedef std::shared_ptr<lldb_private::StoppointLocation> StoppointLocationSP;
|
typedef std::shared_ptr<lldb_private::StoppointLocation> StoppointLocationSP;
|
||||||
typedef std::shared_ptr<lldb_private::Stream> StreamSP;
|
typedef std::shared_ptr<lldb_private::Stream> StreamSP;
|
||||||
|
|
|
@ -875,6 +875,7 @@
|
||||||
2689004C13353E0400698AC0 /* SourceManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8F10F1B85900F91463 /* SourceManager.cpp */; };
|
2689004C13353E0400698AC0 /* SourceManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8F10F1B85900F91463 /* SourceManager.cpp */; };
|
||||||
268900F313353E6F00698AC0 /* StackFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3810F1B90C00F91463 /* StackFrame.cpp */; };
|
268900F313353E6F00698AC0 /* StackFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3810F1B90C00F91463 /* StackFrame.cpp */; };
|
||||||
268900F413353E6F00698AC0 /* StackFrameList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3910F1B90C00F91463 /* StackFrameList.cpp */; };
|
268900F413353E6F00698AC0 /* StackFrameList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3910F1B90C00F91463 /* StackFrameList.cpp */; };
|
||||||
|
8CF46A6220522A9800423DDF /* StackFrameRecognizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CF46A6120522A9000423DDF /* StackFrameRecognizer.cpp */; };
|
||||||
268900F513353E6F00698AC0 /* StackID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3A10F1B90C00F91463 /* StackID.cpp */; };
|
268900F513353E6F00698AC0 /* StackID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3A10F1B90C00F91463 /* StackID.cpp */; };
|
||||||
2689004D13353E0400698AC0 /* State.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9010F1B85900F91463 /* State.cpp */; };
|
2689004D13353E0400698AC0 /* State.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9010F1B85900F91463 /* State.cpp */; };
|
||||||
9A3D43ED1F3237F900EB767C /* StateTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A3D43E21F3237D500EB767C /* StateTest.cpp */; };
|
9A3D43ED1F3237F900EB767C /* StateTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A3D43E21F3237D500EB767C /* StateTest.cpp */; };
|
||||||
|
@ -2935,6 +2936,8 @@
|
||||||
26BC7DF510F1B81A00F91463 /* StackFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackFrame.h; path = include/lldb/Target/StackFrame.h; sourceTree = "<group>"; };
|
26BC7DF510F1B81A00F91463 /* StackFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackFrame.h; path = include/lldb/Target/StackFrame.h; sourceTree = "<group>"; };
|
||||||
26BC7F3910F1B90C00F91463 /* StackFrameList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StackFrameList.cpp; path = source/Target/StackFrameList.cpp; sourceTree = "<group>"; };
|
26BC7F3910F1B90C00F91463 /* StackFrameList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StackFrameList.cpp; path = source/Target/StackFrameList.cpp; sourceTree = "<group>"; };
|
||||||
26BC7DF610F1B81A00F91463 /* StackFrameList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackFrameList.h; path = include/lldb/Target/StackFrameList.h; sourceTree = "<group>"; };
|
26BC7DF610F1B81A00F91463 /* StackFrameList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackFrameList.h; path = include/lldb/Target/StackFrameList.h; sourceTree = "<group>"; };
|
||||||
|
8CF46A6120522A9000423DDF /* StackFrameRecognizer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = StackFrameRecognizer.cpp; path = source/Target/StackFrameRecognizer.cpp; sourceTree = "<group>"; };
|
||||||
|
8CFDB67920467B390052B399 /* StackFrameRecognizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = StackFrameRecognizer.h; path = include/lldb/Target/StackFrameRecognizer.h; sourceTree = "<group>"; };
|
||||||
26BC7F3A10F1B90C00F91463 /* StackID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StackID.cpp; path = source/Target/StackID.cpp; sourceTree = "<group>"; };
|
26BC7F3A10F1B90C00F91463 /* StackID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StackID.cpp; path = source/Target/StackID.cpp; sourceTree = "<group>"; };
|
||||||
26BC7DF710F1B81A00F91463 /* StackID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackID.h; path = include/lldb/Target/StackID.h; sourceTree = "<group>"; };
|
26BC7DF710F1B81A00F91463 /* StackID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackID.h; path = include/lldb/Target/StackID.h; sourceTree = "<group>"; };
|
||||||
26BC7E9010F1B85900F91463 /* State.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = State.cpp; path = source/Utility/State.cpp; sourceTree = "<group>"; };
|
26BC7E9010F1B85900F91463 /* State.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = State.cpp; path = source/Utility/State.cpp; sourceTree = "<group>"; };
|
||||||
|
@ -5687,6 +5690,8 @@
|
||||||
26BC7F3810F1B90C00F91463 /* StackFrame.cpp */,
|
26BC7F3810F1B90C00F91463 /* StackFrame.cpp */,
|
||||||
26BC7DF610F1B81A00F91463 /* StackFrameList.h */,
|
26BC7DF610F1B81A00F91463 /* StackFrameList.h */,
|
||||||
26BC7F3910F1B90C00F91463 /* StackFrameList.cpp */,
|
26BC7F3910F1B90C00F91463 /* StackFrameList.cpp */,
|
||||||
|
8CFDB67920467B390052B399 /* StackFrameRecognizer.h */,
|
||||||
|
8CF46A6120522A9000423DDF /* StackFrameRecognizer.cpp */,
|
||||||
26BC7DF710F1B81A00F91463 /* StackID.h */,
|
26BC7DF710F1B81A00F91463 /* StackID.h */,
|
||||||
26BC7F3A10F1B90C00F91463 /* StackID.cpp */,
|
26BC7F3A10F1B90C00F91463 /* StackID.cpp */,
|
||||||
2615DB841208A9C90021781D /* StopInfo.h */,
|
2615DB841208A9C90021781D /* StopInfo.h */,
|
||||||
|
@ -8241,6 +8246,7 @@
|
||||||
268900F213353E6F00698AC0 /* SectionLoadList.cpp in Sources */,
|
268900F213353E6F00698AC0 /* SectionLoadList.cpp in Sources */,
|
||||||
268900F313353E6F00698AC0 /* StackFrame.cpp in Sources */,
|
268900F313353E6F00698AC0 /* StackFrame.cpp in Sources */,
|
||||||
268900F413353E6F00698AC0 /* StackFrameList.cpp in Sources */,
|
268900F413353E6F00698AC0 /* StackFrameList.cpp in Sources */,
|
||||||
|
8CF46A6220522A9800423DDF /* StackFrameRecognizer.cpp in Sources */,
|
||||||
268900F513353E6F00698AC0 /* StackID.cpp in Sources */,
|
268900F513353E6F00698AC0 /* StackID.cpp in Sources */,
|
||||||
228B1B672113340200E61C70 /* ClangHighlighter.cpp in Sources */,
|
228B1B672113340200E61C70 /* ClangHighlighter.cpp in Sources */,
|
||||||
268900F613353E6F00698AC0 /* StopInfo.cpp in Sources */,
|
268900F613353E6F00698AC0 /* StopInfo.cpp in Sources */,
|
||||||
|
|
|
@ -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
|
|
@ -0,0 +1,102 @@
|
||||||
|
# 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.expect("frame recognizer list",
|
||||||
|
substrs=['no matching results found.'])
|
||||||
|
|
||||||
|
self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo")
|
||||||
|
|
||||||
|
self.expect("frame recognizer list",
|
||||||
|
substrs=['0: recognizer.MyFrameRecognizer, module a.out, function foo'])
|
||||||
|
|
||||||
|
self.runCmd("frame recognizer add -l recognizer.MyOtherFrameRecognizer -s a.out -n bar -x")
|
||||||
|
|
||||||
|
self.expect("frame recognizer list",
|
||||||
|
substrs=['0: recognizer.MyFrameRecognizer, module a.out, function foo',
|
||||||
|
'1: recognizer.MyOtherFrameRecognizer, module a.out, function bar (regexp)'
|
||||||
|
])
|
||||||
|
|
||||||
|
self.runCmd("frame recognizer delete 0")
|
||||||
|
|
||||||
|
self.expect("frame recognizer list",
|
||||||
|
substrs=['1: recognizer.MyOtherFrameRecognizer, module a.out, function bar (regexp)'])
|
||||||
|
|
||||||
|
self.runCmd("frame recognizer clear")
|
||||||
|
|
||||||
|
self.expect("frame recognizer list",
|
||||||
|
substrs=['no matching results found.'])
|
||||||
|
|
||||||
|
self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo")
|
||||||
|
|
||||||
|
lldbutil.run_break_set_by_symbol(self, "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",
|
||||||
|
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)
|
||||||
|
|
||||||
|
self.expect("frame recognizer info 0",
|
||||||
|
substrs=['frame 0 is recognized by recognizer.MyFrameRecognizer'])
|
||||||
|
|
||||||
|
self.expect("frame recognizer info 999", error=True,
|
||||||
|
substrs=['no frame with index 999'])
|
||||||
|
|
||||||
|
self.expect("frame recognizer info 1",
|
||||||
|
substrs=['frame 1 not recognized by any recognizer'])
|
||||||
|
|
||||||
|
# FIXME: The following doesn't work yet, but should be fixed.
|
||||||
|
"""
|
||||||
|
lldbutil.run_break_set_by_symbol(self, "bar")
|
||||||
|
self.runCmd("c")
|
||||||
|
|
||||||
|
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
|
||||||
|
substrs=['stopped', 'stop reason = breakpoint'])
|
||||||
|
|
||||||
|
self.expect("frame variable -t",
|
||||||
|
substrs=['(int *) a = '])
|
||||||
|
|
||||||
|
self.expect("frame variable -t *a",
|
||||||
|
substrs=['*a = 78'])
|
||||||
|
"""
|
|
@ -0,0 +1,28 @@
|
||||||
|
//===-- 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 <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
void foo(int a, int b)
|
||||||
|
{
|
||||||
|
printf("%d %d\n", a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bar(int *ptr)
|
||||||
|
{
|
||||||
|
printf("%d\n", *ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, const char * argv[])
|
||||||
|
{
|
||||||
|
foo(42, 56);
|
||||||
|
int i = 78;
|
||||||
|
bar(&i);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
import lldb
|
||||||
|
|
||||||
|
class MyFrameRecognizer(object):
|
||||||
|
def get_recognized_arguments(self, frame):
|
||||||
|
if frame.name == "foo":
|
||||||
|
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]
|
||||||
|
elif frame.name == "bar":
|
||||||
|
arg1 = frame.EvaluateExpression("$arg1").signed
|
||||||
|
val1 = lldb.target.CreateValueFromExpression("a", "(int *)%d" % arg1)
|
||||||
|
return [val1]
|
||||||
|
return []
|
||||||
|
|
||||||
|
class MyOtherFrameRecognizer(object):
|
||||||
|
def get_recognized_arguments(self, frame):
|
||||||
|
return []
|
|
@ -784,6 +784,52 @@ LLDBSWIGPythonCreateOSPlugin
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<PythonDictionary>(session_dictionary_name);
|
||||||
|
auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(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*
|
SWIGEXPORT void*
|
||||||
LLDBSWIGPython_GetDynamicSetting (void* module, const char* setting, const lldb::TargetSP& target_sp)
|
LLDBSWIGPython_GetDynamicSetting (void* module, const char* setting, const lldb::TargetSP& target_sp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,6 +27,12 @@ public:
|
||||||
void
|
void
|
||||||
SetIncludeArguments (bool);
|
SetIncludeArguments (bool);
|
||||||
|
|
||||||
|
bool
|
||||||
|
GetIncludeRecognizedArguments () const;
|
||||||
|
|
||||||
|
void
|
||||||
|
SetIncludeRecognizedArguments (bool);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GetIncludeLocals () const;
|
GetIncludeLocals () const;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "lldb/Target/Process.h"
|
#include "lldb/Target/Process.h"
|
||||||
#include "lldb/Target/RegisterContext.h"
|
#include "lldb/Target/RegisterContext.h"
|
||||||
#include "lldb/Target/StackFrame.h"
|
#include "lldb/Target/StackFrame.h"
|
||||||
|
#include "lldb/Target/StackFrameRecognizer.h"
|
||||||
#include "lldb/Target/StackID.h"
|
#include "lldb/Target/StackID.h"
|
||||||
#include "lldb/Target/Target.h"
|
#include "lldb/Target/Target.h"
|
||||||
#include "lldb/Target/Thread.h"
|
#include "lldb/Target/Thread.h"
|
||||||
|
@ -960,6 +961,7 @@ SBValueList SBFrame::GetVariables(const lldb::SBVariablesOptions &options) {
|
||||||
|
|
||||||
const bool statics = options.GetIncludeStatics();
|
const bool statics = options.GetIncludeStatics();
|
||||||
const bool arguments = options.GetIncludeArguments();
|
const bool arguments = options.GetIncludeArguments();
|
||||||
|
const bool recognized_arguments = options.GetIncludeRecognizedArguments();
|
||||||
const bool locals = options.GetIncludeLocals();
|
const bool locals = options.GetIncludeLocals();
|
||||||
const bool in_scope_only = options.GetInScopeOnly();
|
const bool in_scope_only = options.GetInScopeOnly();
|
||||||
const bool include_runtime_support_values =
|
const bool include_runtime_support_values =
|
||||||
|
@ -967,9 +969,10 @@ SBValueList SBFrame::GetVariables(const lldb::SBVariablesOptions &options) {
|
||||||
const lldb::DynamicValueType use_dynamic = options.GetUseDynamic();
|
const lldb::DynamicValueType use_dynamic = options.GetUseDynamic();
|
||||||
|
|
||||||
if (log)
|
if (log)
|
||||||
log->Printf("SBFrame::GetVariables (arguments=%i, locals=%i, statics=%i, "
|
log->Printf(
|
||||||
"in_scope_only=%i runtime=%i dynamic=%i)",
|
"SBFrame::GetVariables (arguments=%i, recognized_arguments=%i, "
|
||||||
arguments, locals, statics, in_scope_only,
|
"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);
|
include_runtime_support_values, use_dynamic);
|
||||||
|
|
||||||
std::set<VariableSP> variable_set;
|
std::set<VariableSP> variable_set;
|
||||||
|
@ -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 {
|
} else {
|
||||||
if (log)
|
if (log)
|
||||||
log->Printf("SBFrame::GetVariables () => error: could not "
|
log->Printf("SBFrame::GetVariables () => error: could not "
|
||||||
|
|
|
@ -16,9 +16,9 @@ using namespace lldb_private;
|
||||||
class VariablesOptionsImpl {
|
class VariablesOptionsImpl {
|
||||||
public:
|
public:
|
||||||
VariablesOptionsImpl()
|
VariablesOptionsImpl()
|
||||||
: m_include_arguments(false), m_include_locals(false),
|
: m_include_arguments(false), m_include_recognized_arguments(false),
|
||||||
m_include_statics(false), m_in_scope_only(false),
|
m_include_locals(false), m_include_statics(false),
|
||||||
m_include_runtime_support_values(false),
|
m_in_scope_only(false), m_include_runtime_support_values(false),
|
||||||
m_use_dynamic(lldb::eNoDynamicValues) {}
|
m_use_dynamic(lldb::eNoDynamicValues) {}
|
||||||
|
|
||||||
VariablesOptionsImpl(const VariablesOptionsImpl &) = default;
|
VariablesOptionsImpl(const VariablesOptionsImpl &) = default;
|
||||||
|
@ -31,6 +31,14 @@ public:
|
||||||
|
|
||||||
void SetIncludeArguments(bool b) { m_include_arguments = b; }
|
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; }
|
bool GetIncludeLocals() const { return m_include_locals; }
|
||||||
|
|
||||||
void SetIncludeLocals(bool b) { m_include_locals = b; }
|
void SetIncludeLocals(bool b) { m_include_locals = b; }
|
||||||
|
@ -57,6 +65,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_include_arguments : 1;
|
bool m_include_arguments : 1;
|
||||||
|
bool m_include_recognized_arguments : 1;
|
||||||
bool m_include_locals : 1;
|
bool m_include_locals : 1;
|
||||||
bool m_include_statics : 1;
|
bool m_include_statics : 1;
|
||||||
bool m_in_scope_only : 1;
|
bool m_in_scope_only : 1;
|
||||||
|
@ -90,6 +99,14 @@ void SBVariablesOptions::SetIncludeArguments(bool arguments) {
|
||||||
m_opaque_ap->SetIncludeArguments(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 {
|
bool SBVariablesOptions::GetIncludeLocals() const {
|
||||||
return m_opaque_ap->GetIncludeLocals();
|
return m_opaque_ap->GetIncludeLocals();
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,6 +235,13 @@ LLDBSWIGPythonCreateOSPlugin(const char *python_class_name,
|
||||||
const char *session_dictionary_name,
|
const char *session_dictionary_name,
|
||||||
const lldb::ProcessSP &process_sp);
|
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(
|
extern "C" bool LLDBSWIGPythonRunScriptKeywordProcess(
|
||||||
const char *python_function_name, const char *session_dictionary_name,
|
const char *python_function_name, const char *session_dictionary_name,
|
||||||
lldb::ProcessSP &process, std::string &output);
|
lldb::ProcessSP &process, std::string &output);
|
||||||
|
@ -423,7 +430,9 @@ void SystemInitializerFull::InitializeSWIG() {
|
||||||
LLDBSwigPython_MightHaveChildrenSynthProviderInstance,
|
LLDBSwigPython_MightHaveChildrenSynthProviderInstance,
|
||||||
LLDBSwigPython_GetValueSynthProviderInstance, LLDBSwigPythonCallCommand,
|
LLDBSwigPython_GetValueSynthProviderInstance, LLDBSwigPythonCallCommand,
|
||||||
LLDBSwigPythonCallCommandObject, LLDBSwigPythonCallModuleInit,
|
LLDBSwigPythonCallCommandObject, LLDBSwigPythonCallModuleInit,
|
||||||
LLDBSWIGPythonCreateOSPlugin, LLDBSWIGPythonRunScriptKeywordProcess,
|
LLDBSWIGPythonCreateOSPlugin, LLDBSWIGPython_CreateFrameRecognizer,
|
||||||
|
LLDBSwigPython_GetRecognizedArguments,
|
||||||
|
LLDBSWIGPythonRunScriptKeywordProcess,
|
||||||
LLDBSWIGPythonRunScriptKeywordThread,
|
LLDBSWIGPythonRunScriptKeywordThread,
|
||||||
LLDBSWIGPythonRunScriptKeywordTarget, LLDBSWIGPythonRunScriptKeywordFrame,
|
LLDBSWIGPythonRunScriptKeywordTarget, LLDBSWIGPythonRunScriptKeywordFrame,
|
||||||
LLDBSWIGPythonRunScriptKeywordValue, LLDBSWIGPython_GetDynamicSetting,
|
LLDBSWIGPythonRunScriptKeywordValue, LLDBSWIGPython_GetDynamicSetting,
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "lldb/DataFormatters/ValueObjectPrinter.h"
|
#include "lldb/DataFormatters/ValueObjectPrinter.h"
|
||||||
#include "lldb/Host/Host.h"
|
#include "lldb/Host/Host.h"
|
||||||
#include "lldb/Host/OptionParser.h"
|
#include "lldb/Host/OptionParser.h"
|
||||||
|
#include "lldb/Host/StringConvert.h"
|
||||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||||
#include "lldb/Interpreter/CommandReturnObject.h"
|
#include "lldb/Interpreter/CommandReturnObject.h"
|
||||||
#include "lldb/Interpreter/OptionGroupFormat.h"
|
#include "lldb/Interpreter/OptionGroupFormat.h"
|
||||||
|
@ -40,6 +41,7 @@
|
||||||
#include "lldb/Symbol/VariableList.h"
|
#include "lldb/Symbol/VariableList.h"
|
||||||
#include "lldb/Target/Process.h"
|
#include "lldb/Target/Process.h"
|
||||||
#include "lldb/Target/StackFrame.h"
|
#include "lldb/Target/StackFrame.h"
|
||||||
|
#include "lldb/Target/StackFrameRecognizer.h"
|
||||||
#include "lldb/Target/StopInfo.h"
|
#include "lldb/Target/StopInfo.h"
|
||||||
#include "lldb/Target/Target.h"
|
#include "lldb/Target/Target.h"
|
||||||
#include "lldb/Target/Thread.h"
|
#include "lldb/Target/Thread.h"
|
||||||
|
@ -715,6 +717,23 @@ protected:
|
||||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
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()) {
|
if (m_interpreter.TruncationWarningNecessary()) {
|
||||||
result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
|
result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
|
||||||
m_cmd_name.c_str());
|
m_cmd_name.c_str());
|
||||||
|
@ -738,6 +757,368 @@ protected:
|
||||||
OptionGroupValueObjectDisplay m_varobj_options;
|
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
|
#pragma mark CommandObjectMultiwordFrame
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
@ -758,6 +1139,11 @@ CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
|
||||||
CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
|
CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
|
||||||
LoadSubCommand("variable",
|
LoadSubCommand("variable",
|
||||||
CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
|
CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
|
||||||
|
#ifndef LLDB_DISABLE_PYTHON
|
||||||
|
LoadSubCommand(
|
||||||
|
"recognizer",
|
||||||
|
CommandObjectSP(new CommandObjectFrameRecognizer(interpreter)));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
|
CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
|
||||||
|
|
|
@ -28,6 +28,9 @@ static constexpr OptionDefinition g_variable_options[] = {
|
||||||
{LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-args", 'a',
|
{LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-args", 'a',
|
||||||
OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
|
OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
|
||||||
"Omit function arguments."},
|
"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',
|
{LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-locals", 'l',
|
||||||
OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
|
OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
|
||||||
"Omit local variables."},
|
"Omit local variables."},
|
||||||
|
@ -101,6 +104,9 @@ OptionGroupVariable::SetOptionValue(uint32_t option_idx,
|
||||||
case 's':
|
case 's':
|
||||||
show_scope = true;
|
show_scope = true;
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
show_recognized_args = false;
|
||||||
|
break;
|
||||||
case 'y':
|
case 'y':
|
||||||
error = summary.SetCurrentValue(option_arg);
|
error = summary.SetCurrentValue(option_arg);
|
||||||
break;
|
break;
|
||||||
|
@ -119,6 +125,7 @@ OptionGroupVariable::SetOptionValue(uint32_t option_idx,
|
||||||
void OptionGroupVariable::OptionParsingStarting(
|
void OptionGroupVariable::OptionParsingStarting(
|
||||||
ExecutionContext *execution_context) {
|
ExecutionContext *execution_context) {
|
||||||
show_args = true; // Frame option only
|
show_args = true; // Frame option only
|
||||||
|
show_recognized_args = true; // Frame option only
|
||||||
show_locals = true; // Frame option only
|
show_locals = true; // Frame option only
|
||||||
show_globals = false; // Frame option only
|
show_globals = false; // Frame option only
|
||||||
show_decl = false;
|
show_decl = false;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "lldb/API/SBValue.h"
|
#include "lldb/API/SBValue.h"
|
||||||
|
#include "lldb/API/SBFrame.h"
|
||||||
#include "lldb/Breakpoint/BreakpointLocation.h"
|
#include "lldb/Breakpoint/BreakpointLocation.h"
|
||||||
#include "lldb/Breakpoint/StoppointCallbackContext.h"
|
#include "lldb/Breakpoint/StoppointCallbackContext.h"
|
||||||
#include "lldb/Breakpoint/WatchpointOptions.h"
|
#include "lldb/Breakpoint/WatchpointOptions.h"
|
||||||
|
@ -91,6 +92,10 @@ static ScriptInterpreterPython::SWIGPythonCallModuleInit
|
||||||
g_swig_call_module_init = nullptr;
|
g_swig_call_module_init = nullptr;
|
||||||
static ScriptInterpreterPython::SWIGPythonCreateOSPlugin
|
static ScriptInterpreterPython::SWIGPythonCreateOSPlugin
|
||||||
g_swig_create_os_plugin = nullptr;
|
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
|
static ScriptInterpreterPython::SWIGPythonScriptKeyword_Process
|
||||||
g_swig_run_script_keyword_process = nullptr;
|
g_swig_run_script_keyword_process = nullptr;
|
||||||
static ScriptInterpreterPython::SWIGPythonScriptKeyword_Thread
|
static ScriptInterpreterPython::SWIGPythonScriptKeyword_Thread
|
||||||
|
@ -1498,6 +1503,61 @@ bool ScriptInterpreterPython::GenerateTypeSynthClass(StringList &user_input,
|
||||||
return true;
|
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(
|
StructuredData::GenericSP ScriptInterpreterPython::OSPlugin_CreatePluginObject(
|
||||||
const char *class_name, lldb::ProcessSP process_sp) {
|
const char *class_name, lldb::ProcessSP process_sp) {
|
||||||
if (class_name == nullptr || class_name[0] == '\0')
|
if (class_name == nullptr || class_name[0] == '\0')
|
||||||
|
@ -3185,6 +3245,8 @@ void ScriptInterpreterPython::InitializeInterpreter(
|
||||||
SWIGPythonCallCommandObject swig_call_command_object,
|
SWIGPythonCallCommandObject swig_call_command_object,
|
||||||
SWIGPythonCallModuleInit swig_call_module_init,
|
SWIGPythonCallModuleInit swig_call_module_init,
|
||||||
SWIGPythonCreateOSPlugin swig_create_os_plugin,
|
SWIGPythonCreateOSPlugin swig_create_os_plugin,
|
||||||
|
SWIGPythonCreateFrameRecognizer swig_create_frame_recognizer,
|
||||||
|
SWIGPythonGetRecognizedArguments swig_get_recognized_arguments,
|
||||||
SWIGPythonScriptKeyword_Process swig_run_script_keyword_process,
|
SWIGPythonScriptKeyword_Process swig_run_script_keyword_process,
|
||||||
SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
|
SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
|
||||||
SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,
|
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_command_object = swig_call_command_object;
|
||||||
g_swig_call_module_init = swig_call_module_init;
|
g_swig_call_module_init = swig_call_module_init;
|
||||||
g_swig_create_os_plugin = swig_create_os_plugin;
|
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_process = swig_run_script_keyword_process;
|
||||||
g_swig_run_script_keyword_thread = swig_run_script_keyword_thread;
|
g_swig_run_script_keyword_thread = swig_run_script_keyword_thread;
|
||||||
g_swig_run_script_keyword_target = swig_run_script_keyword_target;
|
g_swig_run_script_keyword_target = swig_run_script_keyword_target;
|
||||||
|
|
|
@ -94,6 +94,12 @@ public:
|
||||||
const char *session_dictionary_name,
|
const char *session_dictionary_name,
|
||||||
const lldb::ProcessSP &process_sp);
|
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,
|
typedef size_t (*SWIGPythonCalculateNumChildren)(void *implementor,
|
||||||
uint32_t max);
|
uint32_t max);
|
||||||
|
|
||||||
|
@ -231,6 +237,13 @@ public:
|
||||||
ScriptedBreakpointResolverSearchDepth(StructuredData::GenericSP
|
ScriptedBreakpointResolverSearchDepth(StructuredData::GenericSP
|
||||||
implementor_sp) override;
|
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
|
StructuredData::GenericSP
|
||||||
OSPlugin_CreatePluginObject(const char *class_name,
|
OSPlugin_CreatePluginObject(const char *class_name,
|
||||||
lldb::ProcessSP process_sp) override;
|
lldb::ProcessSP process_sp) override;
|
||||||
|
@ -426,6 +439,8 @@ public:
|
||||||
SWIGPythonCallCommandObject swig_call_command_object,
|
SWIGPythonCallCommandObject swig_call_command_object,
|
||||||
SWIGPythonCallModuleInit swig_call_module_init,
|
SWIGPythonCallModuleInit swig_call_module_init,
|
||||||
SWIGPythonCreateOSPlugin swig_create_os_plugin,
|
SWIGPythonCreateOSPlugin swig_create_os_plugin,
|
||||||
|
SWIGPythonCreateFrameRecognizer swig_create_frame_recognizer,
|
||||||
|
SWIGPythonGetRecognizedArguments swig_get_recognized_arguments,
|
||||||
SWIGPythonScriptKeyword_Process swig_run_script_keyword_process,
|
SWIGPythonScriptKeyword_Process swig_run_script_keyword_process,
|
||||||
SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
|
SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
|
||||||
SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,
|
SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,
|
||||||
|
|
|
@ -28,6 +28,7 @@ add_lldb_library(lldbTarget
|
||||||
SectionLoadList.cpp
|
SectionLoadList.cpp
|
||||||
StackFrame.cpp
|
StackFrame.cpp
|
||||||
StackFrameList.cpp
|
StackFrameList.cpp
|
||||||
|
StackFrameRecognizer.cpp
|
||||||
StackID.cpp
|
StackID.cpp
|
||||||
StopInfo.cpp
|
StopInfo.cpp
|
||||||
StructuredDataPlugin.cpp
|
StructuredDataPlugin.cpp
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "lldb/Target/ExecutionContext.h"
|
#include "lldb/Target/ExecutionContext.h"
|
||||||
#include "lldb/Target/Process.h"
|
#include "lldb/Target/Process.h"
|
||||||
#include "lldb/Target/RegisterContext.h"
|
#include "lldb/Target/RegisterContext.h"
|
||||||
|
#include "lldb/Target/StackFrameRecognizer.h"
|
||||||
#include "lldb/Target/Target.h"
|
#include "lldb/Target/Target.h"
|
||||||
#include "lldb/Target/Thread.h"
|
#include "lldb/Target/Thread.h"
|
||||||
#include "lldb/Utility/RegisterValue.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_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_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid),
|
||||||
m_stack_frame_kind(kind), m_variable_list_sp(),
|
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
|
// 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
|
// recursive functions properly aren't confused with one another on a history
|
||||||
// stack.
|
// 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_code_addr(pc), m_sc(), m_flags(), m_frame_base(),
|
||||||
m_frame_base_error(), m_cfa_is_valid(true),
|
m_frame_base_error(), m_cfa_is_valid(true),
|
||||||
m_stack_frame_kind(StackFrame::Kind::Regular), m_variable_list_sp(),
|
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) {
|
if (sc_ptr != nullptr) {
|
||||||
m_sc = *sc_ptr;
|
m_sc = *sc_ptr;
|
||||||
m_flags.Set(m_sc.GetResolvedMask());
|
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_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(),
|
||||||
m_frame_base_error(), m_cfa_is_valid(true),
|
m_frame_base_error(), m_cfa_is_valid(true),
|
||||||
m_stack_frame_kind(StackFrame::Kind::Regular), m_variable_list_sp(),
|
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) {
|
if (sc_ptr != nullptr) {
|
||||||
m_sc = *sc_ptr;
|
m_sc = *sc_ptr;
|
||||||
m_flags.Set(m_sc.GetResolvedMask());
|
m_flags.Set(m_sc.GetResolvedMask());
|
||||||
|
@ -1952,3 +1956,11 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source,
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RecognizedStackFrameSP StackFrame::GetRecognizedFrame() {
|
||||||
|
if (!m_recognized_frame_sp) {
|
||||||
|
m_recognized_frame_sp =
|
||||||
|
StackFrameRecognizerManager::RecognizeFrame(CalculateStackFrame());
|
||||||
|
}
|
||||||
|
return m_recognized_frame_sp;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -930,8 +930,61 @@ if target:
|
||||||
</tt></pre></code>
|
</tt></pre></code>
|
||||||
</div>
|
</div>
|
||||||
<div class="postfooter"></div>
|
<div class="postfooter"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="post">
|
||||||
|
<h1 class ="postheader">Writing LLDB frame recognizers in Python</h1>
|
||||||
|
<div class="postcontent">
|
||||||
|
|
||||||
|
<p>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.</p>
|
||||||
|
|
||||||
|
<p>Adding a custom frame recognizer is done by implementing a Python class
|
||||||
|
and using the '<b>frame recognizer add</b>' command. The Python class should have a
|
||||||
|
'<b>get_recognized_arguments</b>' method and it will receive an argument of type
|
||||||
|
<b>lldb.SBFrame</b> representing the current frame that we are trying to recognize.
|
||||||
|
The method should return a (possibly empty) list of <b>lldb.SBValue</b> objects that
|
||||||
|
represent the recognized arguments.</p>
|
||||||
|
|
||||||
|
<p>An example of a recognizer that retrieves the file descriptor values from libc
|
||||||
|
functions '<b>read</b>', '<b>write</b>' and '<b>close</b>' follows:</p>
|
||||||
|
|
||||||
|
<code><pre><tt> 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 []
|
||||||
|
</tt></pre></code>
|
||||||
|
|
||||||
|
<p>The file containing this implementation can be imported via '<b>command script
|
||||||
|
import</b>' and then we can register this recognizer with '<b>frame recognizer add</b>'.
|
||||||
|
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:</p>
|
||||||
|
|
||||||
|
<code><pre><tt>(lldb) <b>command script import .../fd_recognizer.py</b>
|
||||||
|
(lldb) <b>frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib</b>
|
||||||
|
</tt></pre></code>
|
||||||
|
|
||||||
|
<p>When the program is stopped at the beginning of the '<b>read</b>' function in libc, we
|
||||||
|
can view the recognizer arguments in '<b>frame variable</b>':</p>
|
||||||
|
|
||||||
|
<code><pre><tt>(lldb) <b>b read</b>
|
||||||
|
(lldb) <b>r</b>
|
||||||
|
Process 1234 stopped
|
||||||
|
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
|
||||||
|
frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
|
||||||
|
(lldb) <b>frame variable</b>
|
||||||
|
(int) fd = 3
|
||||||
|
</tt></pre></code>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="postfooter"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
Loading…
Reference in New Issue