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

Cleaned up patch, clang-formatted, respects 80-columns now. Expanded test case. 
Implemented all "frame recognizer" commands (add, delete, clear, list). Changed 
iteration order on the list of active recognizers (so that last added wins). 
Hopefully addressed all comments now.


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

Index: source/Target/StackFrameRecognizer.cpp
===================================================================
--- /dev/null
+++ source/Target/StackFrameRecognizer.cpp
@@ -0,0 +1,183 @@
+//===-- 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) {
+                         printf("%s\n", entry.recognizer->GetName().c_str());
+                         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());
@@ -1918,3 +1920,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
@@ -30,6 +30,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);
 
@@ -209,6 +215,13 @@
   ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp,
                                 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
@@ -1452,6 +1457,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')
@@ -3060,6 +3122,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,
@@ -3086,6 +3150,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, "recognized-args", 't',
+     OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone,
+     "Show 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 = true;
+    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 = false; // 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
@@ -41,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"
@@ -717,6 +718,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());
@@ -733,6 +752,281 @@
   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() {}
+ ~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
 
 //-------------------------------------------------------------------------
@@ -753,6 +1047,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
@@ -218,6 +218,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);
@@ -399,7 +406,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
@@ -689,6 +689,52 @@
     Py_RETURN_NONE;
 }
 
+SWIGEXPORT void*
+LLDBSWIGPython_CreateFrameRecognizer
+(
+    const char *python_class_name,
+    const char *session_dictionary_name
+)
+{
+    using namespace lldb_private;
+
+    if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name)
+        Py_RETURN_NONE;
+
+    PyErr_Cleaner py_err_cleaner(true);
+
+    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name);
+    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_class_name, dict);
+
+    if (!pfunc.IsAllocated())
+        Py_RETURN_NONE;
+
+    auto result = pfunc();
+
+    if (result.IsAllocated())
+        return result.release();
+
+    Py_RETURN_NONE;
+}
+
+SWIGEXPORT PyObject*
+LLDBSwigPython_GetRecognizedArguments
+(
+    PyObject *implementor,
+    const lldb::StackFrameSP& frame_sp
+)
+{
+    using namespace lldb_private;
+
+    static char callee_name[] = "get_recognized_arguments";
+
+    lldb::SBFrame frame_sb(frame_sp);
+    PyObject *arg = SBTypeToSWIGWrapper(frame_sb);
+
+    PyObject* result = PyObject_CallMethodObjArgs(implementor, PyString_FromString(callee_name), arg, NULL);
+    return result;
+}
+
 SWIGEXPORT void*
 LLDBSWIGPython_GetDynamicSetting (void* module, const char* setting, const lldb::TargetSP& target_sp)
 {
Index: packages/Python/lldbsuite/test/functionalities/frame-recognizer/recognizer.py
===================================================================
--- /dev/null
+++ 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
===================================================================
--- /dev/null
+++ 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
===================================================================
--- /dev/null
+++ 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 -t",
+                    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
===================================================================
--- /dev/null
+++ 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
@@ -782,6 +782,7 @@
 		8CF02AE919DCC01900B14BE0 /* InstrumentationRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CF02ADF19DCBF3B00B14BE0 /* InstrumentationRuntime.cpp */; };
 		8CF02AEA19DCC02100B14BE0 /* ASanRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CF02AE519DCBF8400B14BE0 /* ASanRuntime.cpp */; };
 		8CF02AEF19DD16B100B14BE0 /* InstrumentationRuntimeStopInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CF02AED19DD15CF00B14BE0 /* InstrumentationRuntimeStopInfo.cpp */; };
+		8CF46A6220522A9800423DDF /* StackFrameRecognizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CF46A6120522A9000423DDF /* StackFrameRecognizer.cpp */; };
 		9404957A1BEC497E00926025 /* NSError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 940495781BEC497E00926025 /* NSError.cpp */; };
 		9404957B1BEC497E00926025 /* NSException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 940495791BEC497E00926025 /* NSException.cpp */; };
 		94094C6B163B6F840083A547 /* ValueObjectCast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94094C69163B6CD90083A547 /* ValueObjectCast.cpp */; };
@@ -2695,6 +2696,8 @@
 		8CF02AE619DCBF8400B14BE0 /* ASanRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASanRuntime.h; sourceTree = "<group>"; };
 		8CF02AED19DD15CF00B14BE0 /* InstrumentationRuntimeStopInfo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InstrumentationRuntimeStopInfo.cpp; path = source/Target/InstrumentationRuntimeStopInfo.cpp; sourceTree = "<group>"; };
 		8CF02AEE19DD15CF00B14BE0 /* InstrumentationRuntimeStopInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = InstrumentationRuntimeStopInfo.h; path = include/lldb/Target/InstrumentationRuntimeStopInfo.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>"; };
 		94005E0313F438DF001EF42D /* python-wrapper.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-wrapper.swig"; sourceTree = "<group>"; };
 		94005E0513F45A1B001EF42D /* embedded_interpreter.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = embedded_interpreter.py; path = source/Interpreter/embedded_interpreter.py; sourceTree = "<group>"; };
 		940495781BEC497E00926025 /* NSError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NSError.cpp; path = Language/ObjC/NSError.cpp; sourceTree = "<group>"; };
@@ -5452,6 +5455,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 */,
@@ -7659,6 +7664,7 @@
 				2689009813353E4200698AC0 /* ELFHeader.cpp in Sources */,
 				2689009913353E4200698AC0 /* ObjectFileELF.cpp in Sources */,
 				2689009A13353E4200698AC0 /* ObjectFileMachO.cpp in Sources */,
+				8CF46A6220522A9800423DDF /* StackFrameRecognizer.cpp in Sources */,
 				2689009B13353E4200698AC0 /* PlatformMacOSX.cpp in Sources */,
 				2689009C13353E4200698AC0 /* PlatformRemoteiOS.cpp in Sources */,
 				2689009D13353E4200698AC0 /* GDBRemoteCommunication.cpp in Sources */,
Index: include/lldb/lldb-forward.h
===================================================================
--- include/lldb/lldb-forward.h
+++ include/lldb/lldb-forward.h
@@ -183,6 +183,7 @@
 class ProcessLaunchInfo;
 class Property;
 struct PropertyDefinition;
+class RecognizedStackFrame;
 class RegisterCheckpoint;
 class RegisterContext;
 class RegisterLocation;
@@ -206,6 +207,8 @@
 class StackFrame;
 class StackFrameImpl;
 class StackFrameList;
+class StackFrameRecognizer;
+class StackFrameRecognizerManager;
 class StackID;
 class StopInfo;
 class Stoppoint;
@@ -412,6 +415,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;
@@ -427,6 +432,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
===================================================================
--- /dev/null
+++ 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
@@ -172,6 +172,17 @@
     return StructuredData::GenericSP();
   }
 
+  virtual StructuredData::GenericSP
+  CreateFrameRecognizer(const char *class_name) {
+    return StructuredData::GenericSP();
+  }
+
+  virtual lldb::ValueObjectListSP GetRecognizedArguments(
+      const StructuredData::ObjectSP &implementor,
+      lldb::StackFrameSP frame_sp) {
+    return lldb::ValueObjectListSP();
+  }
+
   virtual StructuredData::GenericSP
   OSPlugin_CreatePluginObject(const char *class_name,
                               lldb::ProcessSP process_sp) {
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