kubamracek updated this revision to Diff 152017.
kubamracek added a comment.

Fixing up test (it was using the "-t" flag).
Removing a leftover printf().


https://reviews.llvm.org/D44603

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

Index: www/python-reference.html
===================================================================
--- www/python-reference.html
+++ www/python-reference.html
@@ -738,11 +738,64 @@
                             <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 class="post">
+            <h1 class ="postheader">Writing LLDB frame recognizers in Python</h1>
+            <div class="postcontent">
+
+                <p>Frame recognizers allow retrieving information about special frames based on
+                ABI, arguments or other special properties of that frame, even without source
+                code or debug info. Currently, they can extract function arguments that would
+                otherwise be unaccesible.</p>
+
+                <p>Adding a custom frame recognizer is possible 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):</p>
+
+<code><pre><tt>(lldb) <b>command script import .../fd_recognizer.py</b>
+(lldb) <b>frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -m 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>
+            <div class="postfooter"></div>
+        </div>
+
+    </div>
 </div>
 </body>
 </html>
Index: source/Target/StackFrameRecognizer.cpp
===================================================================
--- source/Target/StackFrameRecognizer.cpp
+++ source/Target/StackFrameRecognizer.cpp
@@ -0,0 +1,182 @@
+//===-- 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({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({recognizer, true, ConstString(), module,
+                              ConstString(), symbol, first_instruction_only});
+  }
+
+  void ForEach(
+      std::function<void(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->GetName(), entry.module_regexp->GetText(),
+                 entry.symbol_regexp->GetText(), true);
+      } else {
+        callback(entry.recognizer->GetName(), entry.module.GetCString(),
+                 entry.symbol.GetCString(), false);
+      }
+    }
+  }
+
+  bool Delete(std::string recognizer_name) {
+    size_t previous_size = m_recognizers.size();
+    m_recognizers.erase(
+        std::remove_if(m_recognizers.begin(), m_recognizers.end(),
+                       [recognizer_name](RegisteredEntry entry) {
+                         return entry.recognizer->GetName() == recognizer_name;
+                       }),
+        m_recognizers.end());
+    return previous_size != m_recognizers.size();
+  }
+
+  void RemoveAllRecognizers() {
+    m_recognizers.clear();
+  }
+
+  RecognizedStackFrameSP RecognizeFrame(StackFrameSP frame) {
+    const SymbolContext &symctx =
+        frame->GetSymbolContext(eSymbolContextModule | eSymbolContextFunction);
+    ConstString function_name = symctx.GetFunctionName();
+    ConstString module_name = symctx.module_sp->GetFileSpec().GetFilename();
+    Address start_addr = symctx.symbol->GetAddress();
+    Address current_addr = frame->GetFrameCodeAddress();
+
+    for (auto entry : m_recognizers) {
+      if (entry.module)
+        if (entry.module != module_name)
+          continue;
+
+      if (entry.module_regexp)
+        if (!entry.module_regexp->Execute(module_name.GetStringRef()))
+          continue;
+
+      if (entry.symbol)
+        if (entry.symbol != function_name)
+          continue;
+
+      if (entry.symbol_regexp)
+        if (!entry.symbol_regexp->Execute(function_name.GetStringRef()))
+          continue;
+
+      if (entry.first_instruction_only)
+        if (start_addr != current_addr)
+          continue;
+
+      auto recognized_frame = entry.recognizer->RecognizeFrame(frame);
+      if (recognized_frame)
+        return recognized_frame;
+    }
+    return RecognizedStackFrameSP();
+  }
+
+private:
+  struct RegisteredEntry {
+    StackFrameRecognizerSP recognizer;
+    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(std::string recognizer_name, std::string module,
+                       std::string symbol, bool regexp)> const &callback) {
+  GetStackFrameRecognizerManagerImpl().ForEach(callback);
+}
+
+bool StackFrameRecognizerManager::Delete(std::string recognizer_name) {
+  return GetStackFrameRecognizerManagerImpl().Delete(recognizer_name);
+}
+
+void StackFrameRecognizerManager::RemoveAllRecognizers() {
+  GetStackFrameRecognizerManagerImpl().RemoveAllRecognizers();
+}
+
+RecognizedStackFrameSP
+StackFrameRecognizerManager::RecognizeFrame(StackFrameSP frame) {
+  return GetStackFrameRecognizerManagerImpl().RecognizeFrame(frame);
+}
Index: source/Target/StackFrame.cpp
===================================================================
--- source/Target/StackFrame.cpp
+++ source/Target/StackFrame.cpp
@@ -32,6 +32,7 @@
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrameRecognizer.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
 
@@ -58,7 +59,8 @@
       m_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid),
       m_stop_id(stop_id), m_stop_id_is_valid(stop_id_is_valid),
       m_is_history_frame(is_history_frame), m_variable_list_sp(),
-      m_variable_list_value_objects(), m_disassembly(), m_mutex() {
+      m_variable_list_value_objects(), m_recognized_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,8 +84,8 @@
       m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(),
       m_frame_base_error(), m_cfa_is_valid(true), m_stop_id(0),
       m_stop_id_is_valid(false), m_is_history_frame(false),
-      m_variable_list_sp(), m_variable_list_value_objects(), m_disassembly(),
-      m_mutex() {
+      m_variable_list_sp(), 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());
@@ -108,8 +110,8 @@
       m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(),
       m_frame_base_error(), m_cfa_is_valid(true), m_stop_id(0),
       m_stop_id_is_valid(false), m_is_history_frame(false),
-      m_variable_list_sp(), m_variable_list_value_objects(), m_disassembly(),
-      m_mutex() {
+      m_variable_list_sp(), 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());
@@ -1910,3 +1912,11 @@
   }
   return true;
 }
+
+RecognizedStackFrameSP StackFrame::GetRecognizedFrame() {
+  if (!m_recognized_frame_sp) {
+    m_recognized_frame_sp =
+        StackFrameRecognizerManager::RecognizeFrame(CalculateStackFrame());
+  }
+  return m_recognized_frame_sp;
+}
Index: source/Target/CMakeLists.txt
===================================================================
--- source/Target/CMakeLists.txt
+++ source/Target/CMakeLists.txt
@@ -28,6 +28,7 @@
   SectionLoadList.cpp
   StackFrame.cpp
   StackFrameList.cpp
+  StackFrameRecognizer.cpp
   StackID.cpp
   StopInfo.cpp
   StructuredDataPlugin.cpp
Index: source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
===================================================================
--- source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
+++ source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
@@ -85,6 +85,12 @@
                                             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);
 
@@ -210,6 +216,13 @@
                                 bool &script_error) override;
 
   StructuredData::GenericSP
+  CreateFrameRecognizer(const char *class_name) override;
+
+  lldb::ValueObjectListSP
+  GetRecognizedArguments(const StructuredData::ObjectSP &implementor,
+                         lldb::StackFrameSP frame_sp) override;
+
+  StructuredData::GenericSP
   OSPlugin_CreatePluginObject(const char *class_name,
                               lldb::ProcessSP process_sp) override;
 
@@ -405,6 +418,8 @@
       SWIGPythonCallCommandObject swig_call_command_object,
       SWIGPythonCallModuleInit swig_call_module_init,
       SWIGPythonCreateOSPlugin swig_create_os_plugin,
+      SWIGPythonCreateFrameRecognizer swig_create_frame_recognizer,
+      SWIGPythonGetRecognizedArguments swig_get_recognized_arguments,
       SWIGPythonScriptKeyword_Process swig_run_script_keyword_process,
       SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
       SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,
Index: source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
===================================================================
--- source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -27,6 +27,7 @@
 #include <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 @@
     g_swig_call_module_init = nullptr;
 static ScriptInterpreterPython::SWIGPythonCreateOSPlugin
     g_swig_create_os_plugin = nullptr;
+static ScriptInterpreterPython::SWIGPythonCreateFrameRecognizer
+    g_swig_create_frame_recognizer = nullptr;
+static ScriptInterpreterPython::SWIGPythonGetRecognizedArguments
+    g_swig_get_recognized_arguments = nullptr;
 static ScriptInterpreterPython::SWIGPythonScriptKeyword_Process
     g_swig_run_script_keyword_process = nullptr;
 static ScriptInterpreterPython::SWIGPythonScriptKeyword_Thread
@@ -1428,6 +1433,63 @@
   return true;
 }
 
+StructuredData::GenericSP ScriptInterpreterPython::CreateFrameRecognizer(
+    const char *class_name) {
+  if (class_name == nullptr || class_name[0] == '\0')
+    return StructuredData::GenericSP();
+
+  void *ret_val;
+
+  {
+    Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN,
+                   Locker::FreeLock);
+    ret_val =
+        g_swig_create_frame_recognizer(class_name, m_dictionary_name.c_str());
+  }
+
+  return StructuredData::GenericSP(new StructuredPythonObject(ret_val));
+}
+
+lldb::ValueObjectListSP ScriptInterpreterPython::GetRecognizedArguments(
+    const StructuredData::ObjectSP &os_plugin_object_sp,
+    lldb::StackFrameSP frame_sp) {
+  Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
+
+  static char callee_name[] = "get_recognized_arguments";
+
+  if (!os_plugin_object_sp) return ValueObjectListSP();
+
+  StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric();
+  if (!generic) return nullptr;
+
+  PythonObject implementor(PyRefType::Borrowed,
+                           (PyObject *)generic->GetValue());
+
+  if (!implementor.IsAllocated()) return ValueObjectListSP();
+
+  PythonObject py_return(
+      PyRefType::Owned,
+      (PyObject *)g_swig_get_recognized_arguments(implementor.get(), frame_sp));
+
+  // if it fails, print the error but otherwise go on
+  if (PyErr_Occurred()) {
+    PyErr_Print();
+    PyErr_Clear();
+  }
+  if (py_return.get()) {
+    PythonList result_list(PyRefType::Borrowed, py_return.get());
+    ValueObjectListSP result = ValueObjectListSP(new ValueObjectList());
+    for (int i = 0; i < result_list.GetSize(); i++) {
+      PyObject *item = result_list.GetItemAtIndex(i).get();
+      lldb::SBValue *sb_value_ptr =
+          (lldb::SBValue *)g_swig_cast_to_sbvalue(item);
+      if (sb_value_ptr->IsValid()) result->Append(sb_value_ptr->GetSP());
+    }
+    return result;
+  }
+  return ValueObjectListSP();
+}
+
 StructuredData::GenericSP ScriptInterpreterPython::OSPlugin_CreatePluginObject(
     const char *class_name, lldb::ProcessSP process_sp) {
   if (class_name == nullptr || class_name[0] == '\0')
@@ -3034,6 +3096,8 @@
     SWIGPythonCallCommandObject swig_call_command_object,
     SWIGPythonCallModuleInit swig_call_module_init,
     SWIGPythonCreateOSPlugin swig_create_os_plugin,
+    SWIGPythonCreateFrameRecognizer swig_create_frame_recognizer,
+    SWIGPythonGetRecognizedArguments swig_get_recognized_arguments,
     SWIGPythonScriptKeyword_Process swig_run_script_keyword_process,
     SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread,
     SWIGPythonScriptKeyword_Target swig_run_script_keyword_target,
@@ -3060,6 +3124,8 @@
   g_swig_call_command_object = swig_call_command_object;
   g_swig_call_module_init = swig_call_module_init;
   g_swig_create_os_plugin = swig_create_os_plugin;
+  g_swig_create_frame_recognizer = swig_create_frame_recognizer;
+  g_swig_get_recognized_arguments = swig_get_recognized_arguments;
   g_swig_run_script_keyword_process = swig_run_script_keyword_process;
   g_swig_run_script_keyword_thread = swig_run_script_keyword_thread;
   g_swig_run_script_keyword_target = swig_run_script_keyword_target;
Index: source/Interpreter/OptionGroupVariable.cpp
===================================================================
--- source/Interpreter/OptionGroupVariable.cpp
+++ source/Interpreter/OptionGroupVariable.cpp
@@ -28,6 +28,9 @@
     {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-args", 'a',
      OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone,
      "Omit function arguments."},
+    {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-recognized-args", 't',
+     OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone,
+     "Omit recognized function arguments."},
     {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-locals", 'l',
      OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone,
      "Omit local variables."},
@@ -101,6 +104,9 @@
   case 's':
     show_scope = true;
     break;
+  case 't':
+    show_recognized_args = false;
+    break;
   case 'y':
     error = summary.SetCurrentValue(option_arg);
     break;
@@ -119,6 +125,7 @@
 void OptionGroupVariable::OptionParsingStarting(
     ExecutionContext *execution_context) {
   show_args = true;     // Frame option only
+  show_recognized_args = true; // Frame option only
   show_locals = true;   // Frame option only
   show_globals = false; // Frame option only
   show_decl = false;
Index: source/Commands/CommandObjectFrame.cpp
===================================================================
--- source/Commands/CommandObjectFrame.cpp
+++ source/Commands/CommandObjectFrame.cpp
@@ -40,6 +40,7 @@
 #include "lldb/Symbol/VariableList.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/StackFrame.h"
+#include "lldb/Target/StackFrameRecognizer.h"
 #include "lldb/Target/StopInfo.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
@@ -712,6 +713,24 @@
       result.SetStatus(eReturnStatusSuccessFinishResult);
     }
 
+    if (m_option_variable.show_recognized_args) {
+      auto recognized_frame = frame->GetRecognizedFrame();
+      if (recognized_frame) {
+        ValueObjectListSP recognized_arg_list = recognized_frame->GetRecognizedArguments();
+        if (recognized_arg_list) {
+          for (size_t i = 0; i < recognized_arg_list->GetSize(); i++) {
+            valobj_sp = recognized_arg_list->GetValueObjectAtIndex(i);
+            
+            options.SetFormat(m_option_format.GetFormat());
+            options.SetVariableFormatDisplayLanguage(
+                valobj_sp->GetPreferredDisplayLanguage());
+            options.SetRootValueObjectName(valobj_sp->GetName().AsCString());
+            valobj_sp->Dump(result.GetOutputStream(), options);
+          }
+        }
+      }
+    }
+
     if (m_interpreter.TruncationWarningNecessary()) {
       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
                                       m_cmd_name.c_str());
@@ -735,6 +754,326 @@
   OptionGroupValueObjectDisplay m_varobj_options;
 };
 
+#pragma mark CommandObjectFrameRecognizer
+
+static OptionDefinition g_frame_recognizer_add_options[] = {
+    // clang-format off
+  { LLDB_OPT_SET_ALL, false, "module",        'm', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName,        "Name of the module that this recognizer applies to." },
+  { LLDB_OPT_SET_ALL, false, "function",      'n', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName,        "Name of the function that this recognizer applies to." },
+  { LLDB_OPT_SET_2,   false, "python-class",  'l', OptionParser::eRequiredArgument, nullptr, 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, 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 'm':
+        m_module = std::string(option_arg);
+        break;
+      case 'n':
+        m_function = std::string(option_arg);
+        break;
+      case 'x':
+        m_regex = true;
+        break;
+      default:
+        error.SetErrorStringWithFormat("unrecognized option '%c'",
+                                       short_option);
+        break;
+      }
+
+      return error;
+    }
+
+    void OptionParsingStarting(ExecutionContext *execution_context) override {
+      m_module = "";
+      m_function = "";
+      m_class_name = "";
+      m_regex = false;
+    }
+
+    llvm::ArrayRef<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 retrieving information about special frames based on
+ABI, arguments or other special properties of that frame, even without source
+code or debug info. Currently, they can extract function arguments that would
+otherwise be unaccesible.
+
+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):
+
+(lldb) command script import .../fd_recognizer.py
+(lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -m 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 (-m 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();
+  }
+};
+
+static OptionDefinition g_frame_recognizer_delete_options[] = {
+    // clang-format off
+  { LLDB_OPT_SET_2,   false, "python-class",  'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "Name of a Python class of a frame recognizer." },
+    // clang-format on
+};
+
+class CommandObjectFrameRecognizerDelete : 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;
+      default:
+        error.SetErrorStringWithFormat("unrecognized option '%c'",
+                                       short_option);
+        break;
+      }
+
+      return error;
+    }
+
+    void OptionParsingStarting(ExecutionContext *execution_context) override {
+      m_class_name = "";
+    }
+
+    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+      return llvm::makeArrayRef(g_frame_recognizer_delete_options);
+    }
+
+    // Instance variables to hold the values for command options.
+    std::string m_class_name;
+  };
+
+  CommandOptions m_options;
+
+  Options *GetOptions() override { return &m_options; }
+
+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 (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 (StackFrameRecognizerManager::Delete(m_options.m_class_name)) {
+      result.SetStatus(eReturnStatusSuccessFinishNoResult);
+      return result.Succeeded();
+    } else {
+      result.GetOutputStream().PutCString("no matching results found.\n");
+      result.SetStatus(eReturnStatusFailed);
+      return false;
+    }
+  }
+};
+
+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](std::string name, std::string function,
+                               std::string symbol, bool regexp) {
+         if (name == "") name = "(internal)";
+         result.GetOutputStream().Printf(
+             "%s: module %s, function %s%s\n", 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 CommandObjectFrameRecognizer : public CommandObjectMultiword {
+public:
+  CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
+      : CommandObjectMultiword(
+            interpreter, "frame recognizer",
+            "Commands for editing 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)));
+  }
+
+  ~CommandObjectFrameRecognizer() override = default;
+};
+
 #pragma mark CommandObjectMultiwordFrame
 
 //-------------------------------------------------------------------------
@@ -755,6 +1094,11 @@
                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
   LoadSubCommand("variable",
                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
+#ifndef LLDB_DISABLE_PYTHON
+  LoadSubCommand(
+      "recognizer",
+      CommandObjectSP(new CommandObjectFrameRecognizer(interpreter)));
+#endif
 }
 
 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
Index: source/API/SystemInitializerFull.cpp
===================================================================
--- source/API/SystemInitializerFull.cpp
+++ source/API/SystemInitializerFull.cpp
@@ -222,6 +222,13 @@
                              const char *session_dictionary_name,
                              const lldb::ProcessSP &process_sp);
 
+extern "C" void *LLDBSWIGPython_CreateFrameRecognizer(
+    const char *python_class_name,
+    const char *session_dictionary_name);
+
+extern "C" void *LLDBSwigPython_GetRecognizedArguments(void *implementor,
+    const lldb::StackFrameSP& frame_sp);
+
 extern "C" bool LLDBSWIGPythonRunScriptKeywordProcess(
     const char *python_function_name, const char *session_dictionary_name,
     lldb::ProcessSP &process, std::string &output);
@@ -409,7 +416,9 @@
       LLDBSwigPython_MightHaveChildrenSynthProviderInstance,
       LLDBSwigPython_GetValueSynthProviderInstance, LLDBSwigPythonCallCommand,
       LLDBSwigPythonCallCommandObject, LLDBSwigPythonCallModuleInit,
-      LLDBSWIGPythonCreateOSPlugin, LLDBSWIGPythonRunScriptKeywordProcess,
+      LLDBSWIGPythonCreateOSPlugin, LLDBSWIGPython_CreateFrameRecognizer,
+      LLDBSwigPython_GetRecognizedArguments,
+      LLDBSWIGPythonRunScriptKeywordProcess,
       LLDBSWIGPythonRunScriptKeywordThread,
       LLDBSWIGPythonRunScriptKeywordTarget, LLDBSWIGPythonRunScriptKeywordFrame,
       LLDBSWIGPythonRunScriptKeywordValue, LLDBSWIGPython_GetDynamicSetting,
Index: source/API/SBVariablesOptions.cpp
===================================================================
--- source/API/SBVariablesOptions.cpp
+++ source/API/SBVariablesOptions.cpp
@@ -16,9 +16,9 @@
 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 @@
 
   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 @@
 
 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 @@
   m_opaque_ap->SetIncludeArguments(arguments);
 }
 
+bool SBVariablesOptions::GetIncludeRecognizedArguments() const {
+  return m_opaque_ap->GetIncludeRecognizedArguments();
+}
+
+void SBVariablesOptions::SetIncludeRecognizedArguments(bool arguments) {
+  m_opaque_ap->SetIncludeRecognizedArguments(arguments);
+}
+
 bool SBVariablesOptions::GetIncludeLocals() const {
   return m_opaque_ap->GetIncludeLocals();
 }
Index: source/API/SBFrame.cpp
===================================================================
--- source/API/SBFrame.cpp
+++ source/API/SBFrame.cpp
@@ -36,6 +36,7 @@
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Target/StackFrame.h"
+#include "lldb/Target/StackFrameRecognizer.h"
 #include "lldb/Target/StackID.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
@@ -978,17 +979,19 @@
 
   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 =
       options.GetIncludeRuntimeSupportValues();
   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();
@@ -1050,6 +1053,21 @@
             }
           }
         }
+        if (recognized_arguments) {
+          auto recognized_frame = frame->GetRecognizedFrame();
+          if (recognized_frame) {
+            ValueObjectListSP recognized_arg_list =
+                recognized_frame->GetRecognizedArguments();
+            if (recognized_arg_list) {
+              for (size_t i = 0; i < recognized_arg_list->GetSize(); i++) {
+                SBValue value_sb;
+                value_sb.SetSP(recognized_arg_list->GetValueObjectAtIndex(i),
+                               use_dynamic);
+                value_list.Append(value_sb);
+              }
+            }
+          }
+        }
       } else {
         if (log)
           log->Printf("SBFrame::GetVariables () => error: could not "
Index: scripts/interface/SBVariablesOptions.i
===================================================================
--- scripts/interface/SBVariablesOptions.i
+++ scripts/interface/SBVariablesOptions.i
@@ -26,7 +26,13 @@
     
     void
     SetIncludeArguments (bool);
-    
+
+    bool
+    GetIncludeRecognizedArguments ()  const;
+
+    void
+    SetIncludeRecognizedArguments (bool);
+
     bool
     GetIncludeLocals ()  const;
     
Index: scripts/Python/python-wrapper.swig
===================================================================
--- scripts/Python/python-wrapper.swig
+++ scripts/Python/python-wrapper.swig
@@ -690,6 +690,52 @@
 }
 
 SWIGEXPORT void*
+LLDBSWIGPython_CreateFrameRecognizer
+(
+    const char *python_class_name,
+    const char *session_dictionary_name
+)
+{
+    using namespace lldb_private;
+
+    if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name)
+        Py_RETURN_NONE;
+
+    PyErr_Cleaner py_err_cleaner(true);
+
+    auto dict = PythonModule::MainModule().ResolveName<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;
Index: packages/Python/lldbsuite/test/functionalities/frame-recognizer/recognizer.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/frame-recognizer/recognizer.py
+++ packages/Python/lldbsuite/test/functionalities/frame-recognizer/recognizer.py
@@ -0,0 +1,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 []
Index: packages/Python/lldbsuite/test/functionalities/frame-recognizer/main.m
===================================================================
--- packages/Python/lldbsuite/test/functionalities/frame-recognizer/main.m
+++ packages/Python/lldbsuite/test/functionalities/frame-recognizer/main.m
@@ -0,0 +1,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;
+}
Index: packages/Python/lldbsuite/test/functionalities/frame-recognizer/TestFrameRecognizer.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/frame-recognizer/TestFrameRecognizer.py
+++ packages/Python/lldbsuite/test/functionalities/frame-recognizer/TestFrameRecognizer.py
@@ -0,0 +1,93 @@
+# 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 -m a.out -n foo")
+
+        self.expect("frame recognizer list",
+                    substrs=['recognizer.MyFrameRecognizer: module a.out, function foo'])
+
+        self.runCmd("frame recognizer add -l recognizer.MyOtherFrameRecognizer -m a.out -n bar -x")
+
+        self.expect("frame recognizer list",
+                    substrs=['recognizer.MyFrameRecognizer: module a.out, function foo',
+                             'recognizer.MyOtherFrameRecognizer: module a.out, function bar (regexp)'
+                    ])
+
+        self.runCmd("frame recognizer delete -l recognizer.MyFrameRecognizer")
+
+        self.expect("frame recognizer list",
+                    substrs=['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 -m a.out -n foo")
+
+        self.runCmd("b foo")
+        self.runCmd("r")
+
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+                    substrs=['stopped', 'stop reason = breakpoint'])
+
+        process = target.GetProcess()
+        thread = process.GetSelectedThread()
+        frame = thread.GetSelectedFrame()
+
+        self.assertEqual(frame.GetSymbol().GetName(), "foo")
+        self.assertFalse(frame.GetLineEntry().IsValid())
+
+        self.expect("frame variable",
+                    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)
+
+        # FIXME: The following doesn't work yet, but should be fixed.
+        """
+        self.runCmd("b 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'])
+        """
Index: packages/Python/lldbsuite/test/functionalities/frame-recognizer/Makefile
===================================================================
--- packages/Python/lldbsuite/test/functionalities/frame-recognizer/Makefile
+++ packages/Python/lldbsuite/test/functionalities/frame-recognizer/Makefile
@@ -0,0 +1,10 @@
+LEVEL = ../../make
+
+OBJC_SOURCES := main.m
+
+CFLAGS_EXTRAS += -g0 # No debug info.
+MAKE_DSYM := NO
+
+include $(LEVEL)/Makefile.rules
+
+LDFLAGS += -framework Foundation
Index: lldb.xcodeproj/project.pbxproj
===================================================================
--- lldb.xcodeproj/project.pbxproj
+++ lldb.xcodeproj/project.pbxproj
@@ -848,6 +848,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 */; };
@@ -2847,6 +2848,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/Core/State.cpp; sourceTree = "<group>"; };
@@ -5535,6 +5538,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 */,
@@ -7931,6 +7936,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 */,
 				268900F613353E6F00698AC0 /* StopInfo.cpp in Sources */,
 				256CBDB41ADD0EFD00BC6CDC /* RegisterContextPOSIXCore_arm.cpp in Sources */,
Index: include/lldb/lldb-forward.h
===================================================================
--- include/lldb/lldb-forward.h
+++ include/lldb/lldb-forward.h
@@ -184,6 +184,7 @@
 class ProcessLaunchInfo;
 class Property;
 struct PropertyDefinition;
+class RecognizedStackFrame;
 class RegisterCheckpoint;
 class RegisterContext;
 class RegisterLocation;
@@ -207,6 +208,8 @@
 class StackFrame;
 class StackFrameImpl;
 class StackFrameList;
+class StackFrameRecognizer;
+class StackFrameRecognizerManager;
 class StackID;
 class StopInfo;
 class Stoppoint;
@@ -413,6 +416,8 @@
 typedef std::weak_ptr<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;
@@ -428,6 +433,8 @@
 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;
Index: include/lldb/Target/StackFrameRecognizer.h
===================================================================
--- include/lldb/Target/StackFrameRecognizer.h
+++ include/lldb/Target/StackFrameRecognizer.h
@@ -0,0 +1,102 @@
+//===-- 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
+    : std::enable_shared_from_this<RecognizedStackFrame> {
+public:
+  virtual lldb::ValueObjectListSP GetRecognizedArguments() {
+    return m_arguments;
+  }
+  virtual ~RecognizedStackFrame(){};
+
+protected:
+  lldb::ValueObjectListSP m_arguments;
+};
+
+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 : 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 {
+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(std::string recognizer_name, std::string module,
+                         std::string symbol, bool regexp)> const &callback);
+
+  static bool Delete(std::string recognizer_name);
+
+  static void RemoveAllRecognizers();
+
+  static lldb::RecognizedStackFrameSP RecognizeFrame(lldb::StackFrameSP frame);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StackFrameRecognizer_h_
Index: include/lldb/Target/StackFrame.h
===================================================================
--- include/lldb/Target/StackFrame.h
+++ include/lldb/Target/StackFrame.h
@@ -516,6 +516,8 @@
 
   void CalculateExecutionContext(ExecutionContext &exe_ctx) override;
 
+  lldb::RecognizedStackFrameSP GetRecognizedFrame();
+
 protected:
   friend class StackFrameList;
 
@@ -553,6 +555,7 @@
   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;
 
Index: include/lldb/Interpreter/ScriptInterpreter.h
===================================================================
--- include/lldb/Interpreter/ScriptInterpreter.h
+++ include/lldb/Interpreter/ScriptInterpreter.h
@@ -173,6 +173,17 @@
   }
 
   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();
Index: include/lldb/Interpreter/OptionGroupVariable.h
===================================================================
--- include/lldb/Interpreter/OptionGroupVariable.h
+++ include/lldb/Interpreter/OptionGroupVariable.h
@@ -39,6 +39,8 @@
 
   bool include_frame_options : 1,
       show_args : 1,    // Frame option only (include_frame_options == true)
+      show_recognized_args : 1,  // Frame option only (include_frame_options ==
+                                 // true)
       show_locals : 1,  // Frame option only (include_frame_options == true)
       show_globals : 1, // Frame option only (include_frame_options == true)
       use_regex : 1, show_scope : 1, show_decl : 1;
Index: include/lldb/API/SBVariablesOptions.h
===================================================================
--- include/lldb/API/SBVariablesOptions.h
+++ include/lldb/API/SBVariablesOptions.h
@@ -33,6 +33,10 @@
 
   void SetIncludeArguments(bool);
 
+  bool GetIncludeRecognizedArguments() const;
+
+  void SetIncludeRecognizedArguments(bool);
+
   bool GetIncludeLocals() const;
 
   void SetIncludeLocals(bool);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to