Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[lldb] Introduce StackFrameRecognizer [take 2]
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: 345686
- Loading branch information
1 parent
3e27306
commit 8fddd98
Showing
24 changed files
with
1,162 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
: public 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 | ||
: public 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_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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']) | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
Oops, something went wrong.