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

Updated patch. I've added a static 
`AppleObjCRuntime::GetExceptionThrowLocation()`, which returns the location of 
the exception throw breakpoint for the Obj-C runtime. I tried adding it as 
virtual method on LanguageRuntime instead, but then it wasn't clear to me how 
to make it easily return either an optional (there's runtimes that don't have 
exceptions) or an array (as you said, C++ will need multiple locations) and how 
to make existing code CreateExceptionResolver work with that. Let me know if 
that's okay.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D43886/new/

https://reviews.llvm.org/D43886

Files:
  include/lldb/API/SBThread.h
  include/lldb/Target/StackFrameRecognizer.h
  include/lldb/Target/Thread.h
  packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
  source/API/SBThread.cpp
  source/Commands/CommandObjectThread.cpp
  source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
  source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
  source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
  source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
  source/Target/StackFrameRecognizer.cpp
  source/Target/Thread.cpp

Index: source/Target/Thread.cpp
===================================================================
--- source/Target/Thread.cpp
+++ source/Target/Thread.cpp
@@ -25,6 +25,7 @@
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrameRecognizer.h"
 #include "lldb/Target/StopInfo.h"
 #include "lldb/Target/SystemRuntime.h"
 #include "lldb/Target/Target.h"
@@ -2186,3 +2187,18 @@
   }
   return error;
 }
+
+ValueObjectSP Thread::GetCurrentException() {
+  StackFrameSP frame_sp(GetStackFrameAtIndex(0));
+  if (!frame_sp) return ValueObjectSP();
+
+  RecognizedStackFrameSP recognized_frame(frame_sp->GetRecognizedFrame());
+  if (!recognized_frame) return ValueObjectSP();
+
+  return recognized_frame->GetExceptionObject();
+}
+
+/* TODO(kubamracek)
+ThreadSP Thread::GetCurrentExceptionBacktrace() {
+  return ThreadSP();
+}*/
Index: source/Target/StackFrameRecognizer.cpp
===================================================================
--- source/Target/StackFrameRecognizer.cpp
+++ source/Target/StackFrameRecognizer.cpp
@@ -49,8 +49,9 @@
 
 class StackFrameRecognizerManagerImpl {
 public:
-  void AddRecognizer(StackFrameRecognizerSP recognizer, ConstString &module,
-                     ConstString &symbol, bool first_instruction_only) {
+  void AddRecognizer(StackFrameRecognizerSP recognizer,
+                     const ConstString &module, const ConstString &symbol,
+                     bool first_instruction_only) {
     m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, false, module, RegularExpressionSP(),
                               symbol, RegularExpressionSP(),
                               first_instruction_only});
@@ -152,8 +153,8 @@
 }
 
 void StackFrameRecognizerManager::AddRecognizer(
-    StackFrameRecognizerSP recognizer, ConstString &module, ConstString &symbol,
-    bool first_instruction_only) {
+    StackFrameRecognizerSP recognizer, const ConstString &module,
+    const ConstString &symbol, bool first_instruction_only) {
   GetStackFrameRecognizerManagerImpl().AddRecognizer(recognizer, module, symbol,
                                                      first_instruction_only);
 }
Index: source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
===================================================================
--- source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -25,6 +25,7 @@
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/Section.h"
+#include "lldb/Core/ValueObjectConstResult.h"
 #include "lldb/Core/ValueObjectVariable.h"
 #include "lldb/Expression/DiagnosticManager.h"
 #include "lldb/Expression/FunctionCaller.h"
@@ -39,10 +40,12 @@
 #include "lldb/Symbol/Symbol.h"
 #include "lldb/Symbol/TypeList.h"
 #include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ABI.h"
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Platform.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrameRecognizer.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
 #include "lldb/Utility/ConstString.h"
@@ -373,6 +376,8 @@
   }
 }
 
+static void RegisterObjCExceptionRecognizer();
+
 AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process,
                                        const ModuleSP &objc_module_sp)
     : AppleObjCRuntime(process), m_get_class_info_code(),
@@ -393,6 +398,7 @@
   static const ConstString g_gdb_object_getClass("gdb_object_getClass");
   m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(
                                g_gdb_object_getClass, eSymbolTypeCode) != NULL);
+  RegisterObjCExceptionRecognizer();
 }
 
 bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress(
@@ -799,8 +805,9 @@
 
   if (throw_bp)
     resolver_sp.reset(new BreakpointResolverName(
-        bkpt, "objc_exception_throw", eFunctionNameTypeBase,
-        eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo));
+        bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(),
+        eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0,
+        eLazyBoolNo));
   // FIXME: We don't do catch breakpoints for ObjC yet.
   // Should there be some way for the runtime to specify what it can do in this
   // regard?
@@ -2592,3 +2599,59 @@
   } else
     this->AppleObjCRuntime::GetValuesForGlobalCFBooleans(cf_true, cf_false);
 }
+
+#pragma mark Frame recognizers
+
+class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame {
+ public:
+  ObjCExceptionRecognizedStackFrame(StackFrameSP frame_sp) {
+    ThreadSP thread_sp = frame_sp->GetThread();
+    ProcessSP process_sp = thread_sp->GetProcess();
+
+    const lldb::ABISP &abi = process_sp->GetABI();
+    if (!abi) return;
+
+    CompilerType voidstar = process_sp->GetTarget()
+                                .GetScratchClangASTContext()
+                                ->GetBasicType(lldb::eBasicTypeVoid)
+                                .GetPointerType();
+
+    ValueList args;
+    Value input_value;
+    input_value.SetCompilerType(voidstar);
+    args.PushValue(input_value);
+
+    if (!abi->GetArgumentValues(*thread_sp, args)) return;
+
+    addr_t exception_addr = args.GetValueAtIndex(0)->GetScalar().ULongLong();
+
+    Value value(exception_addr);
+    value.SetCompilerType(voidstar);
+    exception = ValueObjectConstResult::Create(frame_sp.get(), value,
+                                               ConstString("exception"));
+    exception = exception->GetDynamicValue(eDynamicDontRunTarget);
+  }
+
+  ValueObjectSP exception;
+
+  lldb::ValueObjectSP GetExceptionObject() override { return exception; }
+};
+
+class ObjCExceptionThrowFrameRecognizer : public StackFrameRecognizer {
+  lldb::RecognizedStackFrameSP RecognizeFrame(lldb::StackFrameSP frame) {
+    return lldb::RecognizedStackFrameSP(
+        new ObjCExceptionRecognizedStackFrame(frame));
+  };
+};
+
+static void RegisterObjCExceptionRecognizer() {
+  static llvm::once_flag g_once_flag;
+  llvm::call_once(g_once_flag, []() {
+    FileSpec module;
+    ConstString function;
+    std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation();
+    StackFrameRecognizerManager::AddRecognizer(
+        StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()),
+        module.GetFilename(), function, /*first_instruction_only*/ true);
+  });
+}
Index: source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
===================================================================
--- source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
+++ source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
@@ -113,8 +113,9 @@
 
   if (throw_bp)
     resolver_sp.reset(new BreakpointResolverName(
-        bkpt, "objc_exception_throw", eFunctionNameTypeBase,
-        eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo));
+        bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(),
+        eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0,
+        eLazyBoolNo));
   // FIXME: don't do catch yet.
   return resolver_sp;
 }
Index: source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
===================================================================
--- source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
+++ source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
@@ -86,6 +86,8 @@
   bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override;
 
   lldb::SearchFilterSP CreateExceptionSearchFilter() override;
+  
+  static std::tuple<FileSpec, ConstString> GetExceptionThrowLocation();
 
   uint32_t GetFoundationVersion();
 
Index: source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
===================================================================
--- source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
+++ source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
@@ -455,13 +455,19 @@
 
   if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple) {
     FileSpecList filter_modules;
-    filter_modules.Append(FileSpec("libobjc.A.dylib"));
+    filter_modules.Append(std::get<0>(GetExceptionThrowLocation()));
     return target.GetSearchFilterForModuleList(&filter_modules);
   } else {
     return LanguageRuntime::CreateExceptionSearchFilter();
   }
 }
 
+std::tuple<FileSpec, ConstString>
+AppleObjCRuntime::GetExceptionThrowLocation() {
+  return std::make_tuple(
+      FileSpec("libobjc.A.dylib"), ConstString("objc_exception_throw"));
+}
+
 void AppleObjCRuntime::ReadObjCLibraryIfNeeded(const ModuleList &module_list) {
   if (!HasReadObjCLibrary()) {
     std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
Index: source/Commands/CommandObjectThread.cpp
===================================================================
--- source/Commands/CommandObjectThread.cpp
+++ source/Commands/CommandObjectThread.cpp
@@ -1511,6 +1511,52 @@
 };
 
 //-------------------------------------------------------------------------
+// CommandObjectThreadException
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadException : public CommandObjectIterateOverThreads {
+ public:
+  CommandObjectThreadException(CommandInterpreter &interpreter)
+      : CommandObjectIterateOverThreads(
+            interpreter, "thread exception",
+            "Display the current exception object for a thread. Defaults to "
+            "the current thread.",
+            "thread exception",
+            eCommandRequiresProcess | eCommandTryTargetAPILock |
+                eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
+
+  ~CommandObjectThreadException() override = default;
+
+  bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
+    ThreadSP thread_sp =
+        m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
+    if (!thread_sp) {
+      result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
+                                   tid);
+      result.SetStatus(eReturnStatusFailed);
+      return false;
+    }
+
+    Stream &strm = result.GetOutputStream();
+    ValueObjectSP exception_object_sp = thread_sp->GetCurrentException();
+    if (exception_object_sp) {
+      exception_object_sp->Dump(strm);
+    }
+
+    /* TODO(kubamracek)
+    ThreadSP exception_thread_sp = thread_sp->GetCurrentExceptionBacktrace();
+    if (exception_thread_sp && exception_thread_sp->IsValid()) {
+      const uint32_t num_frames_with_source = 0;
+      const bool stop_format = false;
+      exception_thread_sp->GetStatus(strm, m_options.m_start, m_options.m_count,
+                                     num_frames_with_source, stop_format);
+    }*/
+
+    return true;
+  }
+};
+
+//-------------------------------------------------------------------------
 // CommandObjectThreadReturn
 //-------------------------------------------------------------------------
 
@@ -2055,6 +2101,9 @@
                  CommandObjectSP(new CommandObjectThreadUntil(interpreter)));
   LoadSubCommand("info",
                  CommandObjectSP(new CommandObjectThreadInfo(interpreter)));
+  LoadSubCommand(
+      "exception",
+      CommandObjectSP(new CommandObjectThreadException(interpreter)));
   LoadSubCommand("step-in",
                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
                      interpreter, "thread step-in",
Index: source/API/SBThread.cpp
===================================================================
--- source/API/SBThread.cpp
+++ source/API/SBThread.cpp
@@ -1466,6 +1466,21 @@
   return LLDB_INVALID_INDEX32;
 }
 
+SBValue SBThread::GetCurrentException() {
+  ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
+  if (!thread_sp) return SBValue();
+
+  return SBValue(thread_sp->GetCurrentException());
+}
+
+/* TODO(kubamracek)
+SBThread SBThread::GetCurrentExceptionBacktrace() {
+  ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
+  if (!thread_sp) return SBThread();
+
+  return SBThread(thread_sp->GetCurrentExceptionBacktrace());
+}*/
+
 bool SBThread::SafeToCallFunctions() {
   ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
   if (thread_sp)
Index: packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
===================================================================
--- packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
+++ packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
@@ -23,6 +23,16 @@
         target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
         self.assertTrue(target, VALID_TARGET)
 
+        lldbutil.run_to_name_breakpoint(self, "objc_exception_throw")
+
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+                    substrs=['stopped', 'stop reason = breakpoint'])
+
+        self.expect('thread exception', substrs=[
+                '(NSException *) exception = ',
+                'name: "ThrownException" - reason: "SomeReason"',
+            ])
+
         lldbutil.run_to_source_breakpoint(self, "// Set break point at this line.", lldb.SBFileSpec("main.m"))
 
         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
Index: include/lldb/Target/Thread.h
===================================================================
--- include/lldb/Target/Thread.h
+++ include/lldb/Target/Thread.h
@@ -1232,6 +1232,11 @@
   //----------------------------------------------------------------------
   virtual uint64_t GetExtendedBacktraceToken() { return LLDB_INVALID_ADDRESS; }
 
+  lldb::ValueObjectSP GetCurrentException();
+
+  // TODO(kubamracek): Extract backtrace from ValueObjectSP into ThreadSP
+  // lldb::ThreadSP GetCurrentExceptionBacktrace();
+
 protected:
   friend class ThreadPlan;
   friend class ThreadList;
Index: include/lldb/Target/StackFrameRecognizer.h
===================================================================
--- include/lldb/Target/StackFrameRecognizer.h
+++ include/lldb/Target/StackFrameRecognizer.h
@@ -30,6 +30,9 @@
   virtual lldb::ValueObjectListSP GetRecognizedArguments() {
     return m_arguments;
   }
+  virtual lldb::ValueObjectSP GetExceptionObject() {
+    return lldb::ValueObjectSP();
+  }
   virtual ~RecognizedStackFrame(){};
 
 protected:
@@ -97,7 +100,8 @@
 class StackFrameRecognizerManager {
 public:
   static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer,
-                            ConstString &module, ConstString &symbol,
+                            const ConstString &module,
+                            const ConstString &symbol,
                             bool first_instruction_only = true);
 
   static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer,
Index: include/lldb/API/SBThread.h
===================================================================
--- include/lldb/API/SBThread.h
+++ include/lldb/API/SBThread.h
@@ -198,6 +198,11 @@
 
   uint32_t GetExtendedBacktraceOriginatingIndexID();
 
+  SBValue GetCurrentException();
+
+  // TODO(kubamracek): Extract backtrace from SBValue into SBThread
+  // SBThread GetCurrentExceptionBacktrace();
+
   bool SafeToCallFunctions();
 
 #ifndef SWIG
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to