[Lldb-commits] [lldb] r345678 - [lldb] Introduce StackFrameRecognizer

Kuba Mracek via lldb-commits lldb-commits at lists.llvm.org
Tue Oct 30 17:21:03 PDT 2018


Author: kuba.brecka
Date: Tue Oct 30 17:21:03 2018
New Revision: 345678

URL: http://llvm.org/viewvc/llvm-project?rev=345678&view=rev
Log:
[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


Added:
    lldb/trunk/include/lldb/Target/StackFrameRecognizer.h
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/Makefile
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/TestFrameRecognizer.py
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/main.m
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/recognizer.py
    lldb/trunk/source/Target/StackFrameRecognizer.cpp
Modified:
    lldb/trunk/include/lldb/API/SBVariablesOptions.h
    lldb/trunk/include/lldb/Interpreter/OptionGroupVariable.h
    lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h
    lldb/trunk/include/lldb/Target/StackFrame.h
    lldb/trunk/include/lldb/lldb-forward.h
    lldb/trunk/lldb.xcodeproj/project.pbxproj
    lldb/trunk/scripts/Python/python-wrapper.swig
    lldb/trunk/scripts/interface/SBVariablesOptions.i
    lldb/trunk/source/API/SBFrame.cpp
    lldb/trunk/source/API/SBVariablesOptions.cpp
    lldb/trunk/source/API/SystemInitializerFull.cpp
    lldb/trunk/source/Commands/CommandObjectFrame.cpp
    lldb/trunk/source/Interpreter/OptionGroupVariable.cpp
    lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
    lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
    lldb/trunk/source/Target/CMakeLists.txt
    lldb/trunk/source/Target/StackFrame.cpp
    lldb/trunk/www/python-reference.html

Modified: lldb/trunk/include/lldb/API/SBVariablesOptions.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBVariablesOptions.h?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/include/lldb/API/SBVariablesOptions.h (original)
+++ lldb/trunk/include/lldb/API/SBVariablesOptions.h Tue Oct 30 17:21:03 2018
@@ -33,6 +33,10 @@ public:
 
   void SetIncludeArguments(bool);
 
+  bool GetIncludeRecognizedArguments() const;
+
+  void SetIncludeRecognizedArguments(bool);
+
   bool GetIncludeLocals() const;
 
   void SetIncludeLocals(bool);

Modified: lldb/trunk/include/lldb/Interpreter/OptionGroupVariable.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/OptionGroupVariable.h?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/OptionGroupVariable.h (original)
+++ lldb/trunk/include/lldb/Interpreter/OptionGroupVariable.h Tue Oct 30 17:21:03 2018
@@ -39,6 +39,8 @@ public:
 
   bool include_frame_options : 1,
       show_args : 1,    // Frame option only (include_frame_options == true)
+      show_recognized_args : 1,  // Frame option only (include_frame_options ==
+                                 // true)
       show_locals : 1,  // Frame option only (include_frame_options == true)
       show_globals : 1, // Frame option only (include_frame_options == true)
       use_regex : 1, show_scope : 1, show_decl : 1;

Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h (original)
+++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h Tue Oct 30 17:21:03 2018
@@ -174,6 +174,17 @@ public:
   }
 
   virtual StructuredData::GenericSP
+  CreateFrameRecognizer(const char *class_name) {
+    return StructuredData::GenericSP();
+  }
+
+  virtual lldb::ValueObjectListSP GetRecognizedArguments(
+      const StructuredData::ObjectSP &implementor,
+      lldb::StackFrameSP frame_sp) {
+    return lldb::ValueObjectListSP();
+  }
+
+  virtual StructuredData::GenericSP
   OSPlugin_CreatePluginObject(const char *class_name,
                               lldb::ProcessSP process_sp) {
     return StructuredData::GenericSP();

Modified: lldb/trunk/include/lldb/Target/StackFrame.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/StackFrame.h?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/StackFrame.h (original)
+++ lldb/trunk/include/lldb/Target/StackFrame.h Tue Oct 30 17:21:03 2018
@@ -544,6 +544,8 @@ public:
 
   void CalculateExecutionContext(ExecutionContext &exe_ctx) override;
 
+  lldb::RecognizedStackFrameSP GetRecognizedFrame();
+
 protected:
   friend class StackFrameList;
 
@@ -578,6 +580,7 @@ private:
   ValueObjectList m_variable_list_value_objects; // Value objects for each
                                                  // variable in
                                                  // m_variable_list_sp
+  lldb::RecognizedStackFrameSP m_recognized_frame_sp;
   StreamString m_disassembly;
   std::recursive_mutex m_mutex;
 

Added: lldb/trunk/include/lldb/Target/StackFrameRecognizer.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/StackFrameRecognizer.h?rev=345678&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Target/StackFrameRecognizer.h (added)
+++ lldb/trunk/include/lldb/Target/StackFrameRecognizer.h Tue Oct 30 17:21:03 2018
@@ -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_

Modified: lldb/trunk/include/lldb/lldb-forward.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward.h?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-forward.h (original)
+++ lldb/trunk/include/lldb/lldb-forward.h Tue Oct 30 17:21:03 2018
@@ -184,6 +184,7 @@ class ProcessInstanceInfoMatch;
 class ProcessLaunchInfo;
 class Property;
 struct PropertyDefinition;
+class RecognizedStackFrame;
 class RegisterCheckpoint;
 class RegisterContext;
 class RegisterLocation;
@@ -208,6 +209,8 @@ class SourceManagerImpl;
 class StackFrame;
 class StackFrameImpl;
 class StackFrameList;
+class StackFrameRecognizer;
+class StackFrameRecognizerManager;
 class StackID;
 class StopInfo;
 class Stoppoint;
@@ -414,6 +417,8 @@ typedef std::shared_ptr<lldb_private::Qu
 typedef std::weak_ptr<lldb_private::Queue> QueueWP;
 typedef std::shared_ptr<lldb_private::QueueItem> QueueItemSP;
 typedef std::shared_ptr<lldb_private::REPL> REPLSP;
+typedef std::shared_ptr<lldb_private::RecognizedStackFrame>
+    RecognizedStackFrameSP;
 typedef std::shared_ptr<lldb_private::ScriptSummaryFormat>
     ScriptSummaryFormatSP;
 typedef std::shared_ptr<lldb_private::ScriptInterpreter> ScriptInterpreterSP;
@@ -429,6 +434,8 @@ typedef std::shared_ptr<lldb_private::St
 typedef std::unique_ptr<lldb_private::StackFrame> StackFrameUP;
 typedef std::weak_ptr<lldb_private::StackFrame> StackFrameWP;
 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::StoppointLocation> StoppointLocationSP;
 typedef std::shared_ptr<lldb_private::Stream> StreamSP;

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Tue Oct 30 17:21:03 2018
@@ -875,6 +875,7 @@
 		2689004C13353E0400698AC0 /* SourceManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8F10F1B85900F91463 /* SourceManager.cpp */; };
 		268900F313353E6F00698AC0 /* StackFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3810F1B90C00F91463 /* StackFrame.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 */; };
 		2689004D13353E0400698AC0 /* State.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9010F1B85900F91463 /* State.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>"; };
 		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>"; };
+		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>"; };
 		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>"; };
@@ -5687,6 +5690,8 @@
 				26BC7F3810F1B90C00F91463 /* StackFrame.cpp */,
 				26BC7DF610F1B81A00F91463 /* StackFrameList.h */,
 				26BC7F3910F1B90C00F91463 /* StackFrameList.cpp */,
+				8CFDB67920467B390052B399 /* StackFrameRecognizer.h */,
+				8CF46A6120522A9000423DDF /* StackFrameRecognizer.cpp */,
 				26BC7DF710F1B81A00F91463 /* StackID.h */,
 				26BC7F3A10F1B90C00F91463 /* StackID.cpp */,
 				2615DB841208A9C90021781D /* StopInfo.h */,
@@ -8241,6 +8246,7 @@
 				268900F213353E6F00698AC0 /* SectionLoadList.cpp in Sources */,
 				268900F313353E6F00698AC0 /* StackFrame.cpp in Sources */,
 				268900F413353E6F00698AC0 /* StackFrameList.cpp in Sources */,
+				8CF46A6220522A9800423DDF /* StackFrameRecognizer.cpp in Sources */,
 				268900F513353E6F00698AC0 /* StackID.cpp in Sources */,
 				228B1B672113340200E61C70 /* ClangHighlighter.cpp in Sources */,
 				268900F613353E6F00698AC0 /* StopInfo.cpp in Sources */,

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/Makefile?rev=345678&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/Makefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/Makefile Tue Oct 30 17:21:03 2018
@@ -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

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/TestFrameRecognizer.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/TestFrameRecognizer.py?rev=345678&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/TestFrameRecognizer.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/TestFrameRecognizer.py Tue Oct 30 17:21:03 2018
@@ -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'])
+        """

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/main.m
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/main.m?rev=345678&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/main.m (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/main.m Tue Oct 30 17:21:03 2018
@@ -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;
+}

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/recognizer.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/recognizer.py?rev=345678&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/recognizer.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/frame-recognizer/recognizer.py Tue Oct 30 17:21:03 2018
@@ -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 []

Modified: lldb/trunk/scripts/Python/python-wrapper.swig
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/python-wrapper.swig?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/scripts/Python/python-wrapper.swig (original)
+++ lldb/trunk/scripts/Python/python-wrapper.swig Tue Oct 30 17:21:03 2018
@@ -785,6 +785,52 @@ LLDBSWIGPythonCreateOSPlugin
 }
 
 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*
 LLDBSWIGPython_GetDynamicSetting (void* module, const char* setting, const lldb::TargetSP& target_sp)
 {
     using namespace lldb_private;

Modified: lldb/trunk/scripts/interface/SBVariablesOptions.i
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/interface/SBVariablesOptions.i?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/scripts/interface/SBVariablesOptions.i (original)
+++ lldb/trunk/scripts/interface/SBVariablesOptions.i Tue Oct 30 17:21:03 2018
@@ -26,7 +26,13 @@ public:
     
     void
     SetIncludeArguments (bool);
-    
+
+    bool
+    GetIncludeRecognizedArguments ()  const;
+
+    void
+    SetIncludeRecognizedArguments (bool);
+
     bool
     GetIncludeLocals ()  const;
     

Modified: lldb/trunk/source/API/SBFrame.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBFrame.cpp?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/source/API/SBFrame.cpp (original)
+++ lldb/trunk/source/API/SBFrame.cpp Tue Oct 30 17:21:03 2018
@@ -36,6 +36,7 @@
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Target/StackFrame.h"
+#include "lldb/Target/StackFrameRecognizer.h"
 #include "lldb/Target/StackID.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
@@ -960,6 +961,7 @@ SBValueList SBFrame::GetVariables(const
 
   const bool statics = options.GetIncludeStatics();
   const bool arguments = options.GetIncludeArguments();
+  const bool recognized_arguments = options.GetIncludeRecognizedArguments();
   const bool locals = options.GetIncludeLocals();
   const bool in_scope_only = options.GetInScopeOnly();
   const bool include_runtime_support_values =
@@ -967,10 +969,11 @@ SBValueList SBFrame::GetVariables(const
   const lldb::DynamicValueType use_dynamic = options.GetUseDynamic();
 
   if (log)
-    log->Printf("SBFrame::GetVariables (arguments=%i, locals=%i, statics=%i, "
-                "in_scope_only=%i runtime=%i dynamic=%i)",
-                arguments, locals, statics, in_scope_only,
-                include_runtime_support_values, use_dynamic);
+    log->Printf(
+        "SBFrame::GetVariables (arguments=%i, recognized_arguments=%i, "
+        "locals=%i, statics=%i, in_scope_only=%i runtime=%i dynamic=%i)",
+        arguments, recognized_arguments, locals, statics, in_scope_only,
+        include_runtime_support_values, use_dynamic);
 
   std::set<VariableSP> variable_set;
   Process *process = exe_ctx.GetProcessPtr();
@@ -1031,6 +1034,20 @@ SBValueList SBFrame::GetVariables(const
               }
             }
           }
+        }
+        if (recognized_arguments) {
+          auto recognized_frame = frame->GetRecognizedFrame();
+          if (recognized_frame) {
+            ValueObjectListSP recognized_arg_list =
+                recognized_frame->GetRecognizedArguments();
+            if (recognized_arg_list) {
+              for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
+                SBValue value_sb;
+                value_sb.SetSP(rec_value_sp, use_dynamic);
+                value_list.Append(value_sb);
+              }
+            }
+          }
         }
       } else {
         if (log)

Modified: lldb/trunk/source/API/SBVariablesOptions.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBVariablesOptions.cpp?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/source/API/SBVariablesOptions.cpp (original)
+++ lldb/trunk/source/API/SBVariablesOptions.cpp Tue Oct 30 17:21:03 2018
@@ -16,9 +16,9 @@ using namespace lldb_private;
 class VariablesOptionsImpl {
 public:
   VariablesOptionsImpl()
-      : m_include_arguments(false), m_include_locals(false),
-        m_include_statics(false), m_in_scope_only(false),
-        m_include_runtime_support_values(false),
+      : m_include_arguments(false), m_include_recognized_arguments(false),
+        m_include_locals(false), m_include_statics(false),
+        m_in_scope_only(false), m_include_runtime_support_values(false),
         m_use_dynamic(lldb::eNoDynamicValues) {}
 
   VariablesOptionsImpl(const VariablesOptionsImpl &) = default;
@@ -31,6 +31,14 @@ public:
 
   void SetIncludeArguments(bool b) { m_include_arguments = b; }
 
+  bool GetIncludeRecognizedArguments() const {
+    return m_include_recognized_arguments;
+  }
+
+  void SetIncludeRecognizedArguments(bool b) {
+    m_include_recognized_arguments = b;
+  }
+
   bool GetIncludeLocals() const { return m_include_locals; }
 
   void SetIncludeLocals(bool b) { m_include_locals = b; }
@@ -57,6 +65,7 @@ public:
 
 private:
   bool m_include_arguments : 1;
+  bool m_include_recognized_arguments : 1;
   bool m_include_locals : 1;
   bool m_include_statics : 1;
   bool m_in_scope_only : 1;
@@ -90,6 +99,14 @@ void SBVariablesOptions::SetIncludeArgum
   m_opaque_ap->SetIncludeArguments(arguments);
 }
 
+bool SBVariablesOptions::GetIncludeRecognizedArguments() const {
+  return m_opaque_ap->GetIncludeRecognizedArguments();
+}
+
+void SBVariablesOptions::SetIncludeRecognizedArguments(bool arguments) {
+  m_opaque_ap->SetIncludeRecognizedArguments(arguments);
+}
+
 bool SBVariablesOptions::GetIncludeLocals() const {
   return m_opaque_ap->GetIncludeLocals();
 }

Modified: lldb/trunk/source/API/SystemInitializerFull.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SystemInitializerFull.cpp?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/source/API/SystemInitializerFull.cpp (original)
+++ lldb/trunk/source/API/SystemInitializerFull.cpp Tue Oct 30 17:21:03 2018
@@ -235,6 +235,13 @@ LLDBSWIGPythonCreateOSPlugin(const char
                              const char *session_dictionary_name,
                              const lldb::ProcessSP &process_sp);
 
+extern "C" void *LLDBSWIGPython_CreateFrameRecognizer(
+    const char *python_class_name,
+    const char *session_dictionary_name);
+
+extern "C" void *LLDBSwigPython_GetRecognizedArguments(void *implementor,
+    const lldb::StackFrameSP& frame_sp);
+
 extern "C" bool LLDBSWIGPythonRunScriptKeywordProcess(
     const char *python_function_name, const char *session_dictionary_name,
     lldb::ProcessSP &process, std::string &output);
@@ -423,7 +430,9 @@ void SystemInitializerFull::InitializeSW
       LLDBSwigPython_MightHaveChildrenSynthProviderInstance,
       LLDBSwigPython_GetValueSynthProviderInstance, LLDBSwigPythonCallCommand,
       LLDBSwigPythonCallCommandObject, LLDBSwigPythonCallModuleInit,
-      LLDBSWIGPythonCreateOSPlugin, LLDBSWIGPythonRunScriptKeywordProcess,
+      LLDBSWIGPythonCreateOSPlugin, LLDBSWIGPython_CreateFrameRecognizer,
+      LLDBSwigPython_GetRecognizedArguments,
+      LLDBSWIGPythonRunScriptKeywordProcess,
       LLDBSWIGPythonRunScriptKeywordThread,
       LLDBSWIGPythonRunScriptKeywordTarget, LLDBSWIGPythonRunScriptKeywordFrame,
       LLDBSWIGPythonRunScriptKeywordValue, LLDBSWIGPython_GetDynamicSetting,

Modified: lldb/trunk/source/Commands/CommandObjectFrame.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectFrame.cpp?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectFrame.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectFrame.cpp Tue Oct 30 17:21:03 2018
@@ -24,6 +24,7 @@
 #include "lldb/DataFormatters/ValueObjectPrinter.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Host/OptionParser.h"
+#include "lldb/Host/StringConvert.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Interpreter/OptionGroupFormat.h"
@@ -40,6 +41,7 @@
 #include "lldb/Symbol/VariableList.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/StackFrame.h"
+#include "lldb/Target/StackFrameRecognizer.h"
 #include "lldb/Target/StopInfo.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
@@ -715,6 +717,23 @@ protected:
       result.SetStatus(eReturnStatusSuccessFinishResult);
     }
 
+    if (m_option_variable.show_recognized_args) {
+      auto recognized_frame = frame->GetRecognizedFrame();
+      if (recognized_frame) {
+        ValueObjectListSP recognized_arg_list =
+            recognized_frame->GetRecognizedArguments();
+        if (recognized_arg_list) {
+          for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
+            options.SetFormat(m_option_format.GetFormat());
+            options.SetVariableFormatDisplayLanguage(
+                rec_value_sp->GetPreferredDisplayLanguage());
+            options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
+            rec_value_sp->Dump(result.GetOutputStream(), options);
+          }
+        }
+      }
+    }
+
     if (m_interpreter.TruncationWarningNecessary()) {
       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
                                       m_cmd_name.c_str());
@@ -738,6 +757,368 @@ protected:
   OptionGroupValueObjectDisplay m_varobj_options;
 };
 
+#pragma mark CommandObjectFrameRecognizer
+
+static OptionDefinition g_frame_recognizer_add_options[] = {
+    // clang-format off
+  { LLDB_OPT_SET_ALL, false, "shlib",         's', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eModuleCompletion, eArgTypeShlibName,   "Name of the module or shared library that this recognizer applies to." },
+  { LLDB_OPT_SET_ALL, false, "function",      'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeName,        "Name of the function that this recognizer applies to." },
+  { LLDB_OPT_SET_2,   false, "python-class",  'l', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypePythonClass, "Give the name of a Python class to use for this frame recognizer." },
+  { LLDB_OPT_SET_ALL, false, "regex",         'x', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,        "Function name and module name are actually regular expressions." }
+    // clang-format on
+};
+
+class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
+private:
+  class CommandOptions : public Options {
+  public:
+    CommandOptions() : Options() {}
+    ~CommandOptions() override = default;
+
+    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+                          ExecutionContext *execution_context) override {
+      Status error;
+      const int short_option = m_getopt_table[option_idx].val;
+
+      switch (short_option) {
+      case 'l':
+        m_class_name = std::string(option_arg);
+        break;
+      case 's':
+        m_module = std::string(option_arg);
+        break;
+      case 'n':
+        m_function = std::string(option_arg);
+        break;
+      case 'x':
+        m_regex = true;
+        break;
+      default:
+        error.SetErrorStringWithFormat("unrecognized option '%c'",
+                                       short_option);
+        break;
+      }
+
+      return error;
+    }
+
+    void OptionParsingStarting(ExecutionContext *execution_context) override {
+      m_module = "";
+      m_function = "";
+      m_class_name = "";
+      m_regex = false;
+    }
+
+    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+      return llvm::makeArrayRef(g_frame_recognizer_add_options);
+    }
+
+    // Instance variables to hold the values for command options.
+    std::string m_class_name;
+    std::string m_module;
+    std::string m_function;
+    bool m_regex;
+  };
+
+  CommandOptions m_options;
+
+  Options *GetOptions() override { return &m_options; }
+
+protected:
+  bool DoExecute(Args &command, CommandReturnObject &result) override;
+
+public:
+  CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "frame recognizer add",
+                            "Add a new frame recognizer.", nullptr),
+        m_options() {
+    SetHelpLong(R"(
+Frame recognizers allow for retrieving information about special frames based on
+ABI, arguments or other special properties of that frame, even without source
+code or debug info. Currently, one use case is to extract function arguments
+that would otherwise be unaccesible, or augment existing arguments.
+
+Adding a custom frame recognizer is possible by implementing a Python class
+and using the 'frame recognizer add' command. The Python class should have a
+'get_recognized_arguments' method and it will receive an argument of type
+lldb.SBFrame representing the current frame that we are trying to recognize.
+The method should return a (possibly empty) list of lldb.SBValue objects that
+represent the recognized arguments.
+
+An example of a recognizer that retrieves the file descriptor values from libc
+functions 'read', 'write' and 'close' follows:
+
+  class LibcFdRecognizer(object):
+    def get_recognized_arguments(self, frame):
+      if frame.name in ["read", "write", "close"]:
+        fd = frame.EvaluateExpression("$arg1").unsigned
+        value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
+        return [value]
+      return []
+
+The file containing this implementation can be imported via 'command script
+import' and then we can register this recognizer with 'frame recognizer add'.
+It's important to restrict the recognizer to the libc library (which is
+libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
+in other modules:
+
+(lldb) command script import .../fd_recognizer.py
+(lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
+
+When the program is stopped at the beginning of the 'read' function in libc, we
+can view the recognizer arguments in 'frame variable':
+
+(lldb) b read
+(lldb) r
+Process 1234 stopped
+* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
+    frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
+(lldb) frame variable
+(int) fd = 3
+
+    )");
+  }
+  ~CommandObjectFrameRecognizerAdd() override = default;
+};
+
+bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
+                                                CommandReturnObject &result) {
+  if (m_options.m_class_name.empty()) {
+    result.AppendErrorWithFormat(
+        "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
+    result.SetStatus(eReturnStatusFailed);
+    return false;
+  }
+
+  if (m_options.m_module.empty()) {
+    result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
+                                 m_cmd_name.c_str());
+    result.SetStatus(eReturnStatusFailed);
+    return false;
+  }
+
+  if (m_options.m_function.empty()) {
+    result.AppendErrorWithFormat("%s needs a function name (-n argument).\n",
+                                 m_cmd_name.c_str());
+    result.SetStatus(eReturnStatusFailed);
+    return false;
+  }
+
+  ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
+
+  if (interpreter &&
+      !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
+    result.AppendWarning(
+        "The provided class does not exist - please define it "
+        "before attempting to use this frame recognizer");
+  }
+
+  StackFrameRecognizerSP recognizer_sp =
+      StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
+          interpreter, m_options.m_class_name.c_str()));
+  if (m_options.m_regex) {
+    auto module =
+        RegularExpressionSP(new RegularExpression(m_options.m_module));
+    auto func =
+        RegularExpressionSP(new RegularExpression(m_options.m_function));
+    StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
+  } else {
+    auto module = ConstString(m_options.m_module);
+    auto func = ConstString(m_options.m_function);
+    StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
+  }
+
+  result.SetStatus(eReturnStatusSuccessFinishNoResult);
+  return result.Succeeded();
+}
+
+class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
+public:
+  CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "frame recognizer clear",
+                           "Delete all frame recognizers.", nullptr) {}
+
+  ~CommandObjectFrameRecognizerClear() override = default;
+
+protected:
+  bool DoExecute(Args &command, CommandReturnObject &result) override {
+    StackFrameRecognizerManager::RemoveAllRecognizers();
+    result.SetStatus(eReturnStatusSuccessFinishResult);
+    return result.Succeeded();
+  }
+};
+
+class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
+ public:
+  CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "frame recognizer delete",
+                            "Delete an existing frame recognizer.", nullptr) {}
+
+  ~CommandObjectFrameRecognizerDelete() override = default;
+
+ protected:
+  bool DoExecute(Args &command, CommandReturnObject &result) override {
+    if (command.GetArgumentCount() == 0) {
+      if (!m_interpreter.Confirm(
+              "About to delete all frame recognizers, do you want to do that?",
+              true)) {
+        result.AppendMessage("Operation cancelled...");
+        result.SetStatus(eReturnStatusFailed);
+        return false;
+      }
+
+      StackFrameRecognizerManager::RemoveAllRecognizers();
+      result.SetStatus(eReturnStatusSuccessFinishResult);
+      return result.Succeeded();
+    }
+
+    if (command.GetArgumentCount() != 1) {
+      result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
+                                   m_cmd_name.c_str());
+      result.SetStatus(eReturnStatusFailed);
+      return false;
+    }
+
+    uint32_t recognizer_id =
+        StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
+
+    StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
+    result.SetStatus(eReturnStatusSuccessFinishResult);
+    return result.Succeeded();
+  }
+};
+
+class CommandObjectFrameRecognizerList : public CommandObjectParsed {
+ public:
+  CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "frame recognizer list",
+                            "Show a list of active frame recognizers.",
+                            nullptr) {}
+
+  ~CommandObjectFrameRecognizerList() override = default;
+
+ protected:
+  bool DoExecute(Args &command, CommandReturnObject &result) override {
+    bool any_printed = false;
+    StackFrameRecognizerManager::ForEach(
+        [&result, &any_printed](uint32_t recognizer_id, std::string name,
+                                std::string function, std::string symbol,
+                                bool regexp) {
+          if (name == "") name = "(internal)";
+          result.GetOutputStream().Printf(
+              "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(),
+              function.c_str(), symbol.c_str(), regexp ? " (regexp)" : "");
+          any_printed = true;
+        });
+
+    if (any_printed)
+      result.SetStatus(eReturnStatusSuccessFinishResult);
+    else {
+      result.GetOutputStream().PutCString("no matching results found.\n");
+      result.SetStatus(eReturnStatusSuccessFinishNoResult);
+    }
+    return result.Succeeded();
+  }
+};
+
+class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
+ public:
+  CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
+      : CommandObjectParsed(
+            interpreter, "frame recognizer info",
+            "Show which frame recognizer is applied a stack frame (if any).",
+            nullptr) {
+    CommandArgumentEntry arg;
+    CommandArgumentData index_arg;
+
+    // Define the first (and only) variant of this arg.
+    index_arg.arg_type = eArgTypeFrameIndex;
+    index_arg.arg_repetition = eArgRepeatPlain;
+
+    // There is only one variant this argument could be; put it into the
+    // argument entry.
+    arg.push_back(index_arg);
+
+    // Push the data for the first argument into the m_arguments vector.
+    m_arguments.push_back(arg);
+  }
+
+  ~CommandObjectFrameRecognizerInfo() override = default;
+
+ protected:
+  bool DoExecute(Args &command, CommandReturnObject &result) override {
+    Process *process = m_exe_ctx.GetProcessPtr();
+    if (process == nullptr) {
+      result.AppendError("no process");
+      result.SetStatus(eReturnStatusFailed);
+      return false;
+    }
+    Thread *thread = m_exe_ctx.GetThreadPtr();
+    if (thread == nullptr) {
+      result.AppendError("no thread");
+      result.SetStatus(eReturnStatusFailed);
+      return false;
+    }
+    if (command.GetArgumentCount() != 1) {
+      result.AppendErrorWithFormat(
+          "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
+      result.SetStatus(eReturnStatusFailed);
+      return false;
+    }
+
+    uint32_t frame_index =
+        StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
+    StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
+    if (!frame_sp) {
+      result.AppendErrorWithFormat("no frame with index %u", frame_index);
+      result.SetStatus(eReturnStatusFailed);
+      return false;
+    }
+
+    auto recognizer =
+        StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
+
+    Stream &output_stream = result.GetOutputStream();
+    output_stream.Printf("frame %d ", frame_index);
+    if (recognizer) {
+      output_stream << "is recognized by ";
+      output_stream << recognizer->GetName();
+    } else {
+      output_stream << "not recognized by any recognizer";
+    }
+    output_stream.EOL();
+    result.SetStatus(eReturnStatusSuccessFinishResult);
+    return result.Succeeded();
+  }
+};
+
+class CommandObjectFrameRecognizer : public CommandObjectMultiword {
+ public:
+  CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
+      : CommandObjectMultiword(
+            interpreter, "frame recognizer",
+            "Commands for editing and viewing frame recognizers.",
+            "frame recognizer [<sub-command-options>] ") {
+    LoadSubCommand(
+        "add",
+        CommandObjectSP(new CommandObjectFrameRecognizerAdd(interpreter)));
+    LoadSubCommand(
+        "clear",
+        CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
+    LoadSubCommand(
+        "delete",
+        CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
+    LoadSubCommand(
+        "list",
+        CommandObjectSP(new CommandObjectFrameRecognizerList(interpreter)));
+    LoadSubCommand(
+        "info",
+        CommandObjectSP(new CommandObjectFrameRecognizerInfo(interpreter)));
+  }
+
+  ~CommandObjectFrameRecognizer() override = default;
+};
+
 #pragma mark CommandObjectMultiwordFrame
 
 //-------------------------------------------------------------------------
@@ -758,6 +1139,11 @@ CommandObjectMultiwordFrame::CommandObje
                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
   LoadSubCommand("variable",
                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
+#ifndef LLDB_DISABLE_PYTHON
+  LoadSubCommand(
+      "recognizer",
+      CommandObjectSP(new CommandObjectFrameRecognizer(interpreter)));
+#endif
 }
 
 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;

Modified: lldb/trunk/source/Interpreter/OptionGroupVariable.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/OptionGroupVariable.cpp?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/OptionGroupVariable.cpp (original)
+++ lldb/trunk/source/Interpreter/OptionGroupVariable.cpp Tue Oct 30 17:21:03 2018
@@ -28,6 +28,9 @@ static constexpr OptionDefinition g_vari
     {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-args", 'a',
      OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
      "Omit function arguments."},
+    {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-recognized-args", 't',
+     OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
+     "Omit recognized function arguments."},
     {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-locals", 'l',
      OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
      "Omit local variables."},
@@ -101,6 +104,9 @@ OptionGroupVariable::SetOptionValue(uint
   case 's':
     show_scope = true;
     break;
+  case 't':
+    show_recognized_args = false;
+    break;
   case 'y':
     error = summary.SetCurrentValue(option_arg);
     break;
@@ -119,6 +125,7 @@ OptionGroupVariable::SetOptionValue(uint
 void OptionGroupVariable::OptionParsingStarting(
     ExecutionContext *execution_context) {
   show_args = true;     // Frame option only
+  show_recognized_args = true; // Frame option only
   show_locals = true;   // Frame option only
   show_globals = false; // Frame option only
   show_decl = false;

Modified: lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp (original)
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp Tue Oct 30 17:21:03 2018
@@ -27,6 +27,7 @@
 #include <string>
 
 #include "lldb/API/SBValue.h"
+#include "lldb/API/SBFrame.h"
 #include "lldb/Breakpoint/BreakpointLocation.h"
 #include "lldb/Breakpoint/StoppointCallbackContext.h"
 #include "lldb/Breakpoint/WatchpointOptions.h"
@@ -91,6 +92,10 @@ static ScriptInterpreterPython::SWIGPyth
     g_swig_call_module_init = nullptr;
 static ScriptInterpreterPython::SWIGPythonCreateOSPlugin
     g_swig_create_os_plugin = nullptr;
+static ScriptInterpreterPython::SWIGPythonCreateFrameRecognizer
+    g_swig_create_frame_recognizer = nullptr;
+static ScriptInterpreterPython::SWIGPythonGetRecognizedArguments
+    g_swig_get_recognized_arguments = nullptr;
 static ScriptInterpreterPython::SWIGPythonScriptKeyword_Process
     g_swig_run_script_keyword_process = nullptr;
 static ScriptInterpreterPython::SWIGPythonScriptKeyword_Thread
@@ -1498,6 +1503,61 @@ bool ScriptInterpreterPython::GenerateTy
   return true;
 }
 
+StructuredData::GenericSP ScriptInterpreterPython::CreateFrameRecognizer(
+    const char *class_name) {
+  if (class_name == nullptr || class_name[0] == '\0')
+    return StructuredData::GenericSP();
+
+  void *ret_val;
+
+  {
+    Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN,
+                   Locker::FreeLock);
+    ret_val =
+        g_swig_create_frame_recognizer(class_name, m_dictionary_name.c_str());
+  }
+
+  return StructuredData::GenericSP(new StructuredPythonObject(ret_val));
+}
+
+lldb::ValueObjectListSP ScriptInterpreterPython::GetRecognizedArguments(
+    const StructuredData::ObjectSP &os_plugin_object_sp,
+    lldb::StackFrameSP frame_sp) {
+  Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
+
+  if (!os_plugin_object_sp) return ValueObjectListSP();
+
+  StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric();
+  if (!generic) return nullptr;
+
+  PythonObject implementor(PyRefType::Borrowed,
+                           (PyObject *)generic->GetValue());
+
+  if (!implementor.IsAllocated()) return ValueObjectListSP();
+
+  PythonObject py_return(
+      PyRefType::Owned,
+      (PyObject *)g_swig_get_recognized_arguments(implementor.get(), frame_sp));
+
+  // if it fails, print the error but otherwise go on
+  if (PyErr_Occurred()) {
+    PyErr_Print();
+    PyErr_Clear();
+  }
+  if (py_return.get()) {
+    PythonList result_list(PyRefType::Borrowed, py_return.get());
+    ValueObjectListSP result = ValueObjectListSP(new ValueObjectList());
+    for (int i = 0; i < result_list.GetSize(); i++) {
+      PyObject *item = result_list.GetItemAtIndex(i).get();
+      lldb::SBValue *sb_value_ptr =
+          (lldb::SBValue *)g_swig_cast_to_sbvalue(item);
+      if (sb_value_ptr->IsValid()) result->Append(sb_value_ptr->GetSP());
+    }
+    return result;
+  }
+  return ValueObjectListSP();
+}
+
 StructuredData::GenericSP ScriptInterpreterPython::OSPlugin_CreatePluginObject(
     const char *class_name, lldb::ProcessSP process_sp) {
   if (class_name == nullptr || class_name[0] == '\0')
@@ -3185,6 +3245,8 @@ void ScriptInterpreterPython::Initialize
     SWIGPythonCallCommandObject swig_call_command_object,
     SWIGPythonCallModuleInit swig_call_module_init,
     SWIGPythonCreateOSPlugin swig_create_os_plugin,
+    SWIGPythonCreateFrameRecognizer swig_create_frame_recognizer,
+    SWIGPythonGetRecognizedArguments swig_get_recognized_arguments,
     SWIGPythonScriptKeyword_Process swig_run_script_keyword_process,
     SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
     SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,
@@ -3213,6 +3275,8 @@ void ScriptInterpreterPython::Initialize
   g_swig_call_command_object = swig_call_command_object;
   g_swig_call_module_init = swig_call_module_init;
   g_swig_create_os_plugin = swig_create_os_plugin;
+  g_swig_create_frame_recognizer = swig_create_frame_recognizer;
+  g_swig_get_recognized_arguments = swig_get_recognized_arguments;
   g_swig_run_script_keyword_process = swig_run_script_keyword_process;
   g_swig_run_script_keyword_thread = swig_run_script_keyword_thread;
   g_swig_run_script_keyword_target = swig_run_script_keyword_target;

Modified: lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h (original)
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h Tue Oct 30 17:21:03 2018
@@ -94,6 +94,12 @@ public:
                                             const char *session_dictionary_name,
                                             const lldb::ProcessSP &process_sp);
 
+  typedef void *(*SWIGPythonCreateFrameRecognizer)(
+      const char *python_class_name, const char *session_dictionary_name);
+
+  typedef void *(*SWIGPythonGetRecognizedArguments)(
+      void *implementor, const lldb::StackFrameSP &frame_sp);
+
   typedef size_t (*SWIGPythonCalculateNumChildren)(void *implementor,
                                                    uint32_t max);
 
@@ -232,6 +238,13 @@ public:
                                             implementor_sp) override;
 
   StructuredData::GenericSP
+  CreateFrameRecognizer(const char *class_name) override;
+
+  lldb::ValueObjectListSP
+  GetRecognizedArguments(const StructuredData::ObjectSP &implementor,
+                         lldb::StackFrameSP frame_sp) override;
+
+  StructuredData::GenericSP
   OSPlugin_CreatePluginObject(const char *class_name,
                               lldb::ProcessSP process_sp) override;
 
@@ -426,6 +439,8 @@ public:
       SWIGPythonCallCommandObject swig_call_command_object,
       SWIGPythonCallModuleInit swig_call_module_init,
       SWIGPythonCreateOSPlugin swig_create_os_plugin,
+      SWIGPythonCreateFrameRecognizer swig_create_frame_recognizer,
+      SWIGPythonGetRecognizedArguments swig_get_recognized_arguments,
       SWIGPythonScriptKeyword_Process swig_run_script_keyword_process,
       SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
       SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,

Modified: lldb/trunk/source/Target/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/CMakeLists.txt?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/source/Target/CMakeLists.txt (original)
+++ lldb/trunk/source/Target/CMakeLists.txt Tue Oct 30 17:21:03 2018
@@ -28,6 +28,7 @@ add_lldb_library(lldbTarget
   SectionLoadList.cpp
   StackFrame.cpp
   StackFrameList.cpp
+  StackFrameRecognizer.cpp
   StackID.cpp
   StopInfo.cpp
   StructuredDataPlugin.cpp

Modified: lldb/trunk/source/Target/StackFrame.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StackFrame.cpp?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/source/Target/StackFrame.cpp (original)
+++ lldb/trunk/source/Target/StackFrame.cpp Tue Oct 30 17:21:03 2018
@@ -31,6 +31,7 @@
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrameRecognizer.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
 #include "lldb/Utility/RegisterValue.h"
@@ -58,7 +59,8 @@ StackFrame::StackFrame(const ThreadSP &t
       m_id(pc, cfa, nullptr), m_frame_code_addr(pc), m_sc(), m_flags(),
       m_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid),
       m_stack_frame_kind(kind), m_variable_list_sp(),
-      m_variable_list_value_objects(), m_disassembly(), m_mutex() {
+      m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(),
+      m_mutex() {
   // If we don't have a CFA value, use the frame index for our StackID so that
   // recursive functions properly aren't confused with one another on a history
   // stack.
@@ -82,7 +84,8 @@ StackFrame::StackFrame(const ThreadSP &t
       m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(),
       m_frame_base_error(), m_cfa_is_valid(true),
       m_stack_frame_kind(StackFrame::Kind::Regular), m_variable_list_sp(),
-      m_variable_list_value_objects(), m_disassembly(), m_mutex() {
+      m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(),
+      m_mutex() {
   if (sc_ptr != nullptr) {
     m_sc = *sc_ptr;
     m_flags.Set(m_sc.GetResolvedMask());
@@ -107,7 +110,8 @@ StackFrame::StackFrame(const ThreadSP &t
       m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(),
       m_frame_base_error(), m_cfa_is_valid(true),
       m_stack_frame_kind(StackFrame::Kind::Regular), m_variable_list_sp(),
-      m_variable_list_value_objects(), m_disassembly(), m_mutex() {
+      m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(),
+      m_mutex() {
   if (sc_ptr != nullptr) {
     m_sc = *sc_ptr;
     m_flags.Set(m_sc.GetResolvedMask());
@@ -1952,3 +1956,11 @@ bool StackFrame::GetStatus(Stream &strm,
   }
   return true;
 }
+
+RecognizedStackFrameSP StackFrame::GetRecognizedFrame() {
+  if (!m_recognized_frame_sp) {
+    m_recognized_frame_sp =
+        StackFrameRecognizerManager::RecognizeFrame(CalculateStackFrame());
+  }
+  return m_recognized_frame_sp;
+}

Added: lldb/trunk/source/Target/StackFrameRecognizer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StackFrameRecognizer.cpp?rev=345678&view=auto
==============================================================================
--- lldb/trunk/source/Target/StackFrameRecognizer.cpp (added)
+++ lldb/trunk/source/Target/StackFrameRecognizer.cpp Tue Oct 30 17:21:03 2018
@@ -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);
+}

Modified: lldb/trunk/www/python-reference.html
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/www/python-reference.html?rev=345678&r1=345677&r2=345678&view=diff
==============================================================================
--- lldb/trunk/www/python-reference.html (original)
+++ lldb/trunk/www/python-reference.html Tue Oct 30 17:21:03 2018
@@ -928,11 +928,64 @@ if target:
                             <font color=green># We do have a symbol, print some info for the symbol</font>
                             print symbol
 </tt></pre></code>
-        				</div>
-        				<div class="postfooter"></div>
+            </div>
+            <div class="postfooter"></div>
+        </div>
 
-              	</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 class="postfooter"></div>
+        </div>
+
+    </div>
 </div>
 </body>
 </html>




More information about the lldb-commits mailing list