[Lldb-commits] [lldb] r347813 - [lldb] Add GetCurrentException APIs to SBThread, add frame recognizer for objc_exception_throw for Obj-C runtimes

Kuba Mracek via lldb-commits lldb-commits at lists.llvm.org
Wed Nov 28 14:01:52 PST 2018


Author: kuba.brecka
Date: Wed Nov 28 14:01:52 2018
New Revision: 347813

URL: http://llvm.org/viewvc/llvm-project?rev=347813&view=rev
Log:
[lldb] Add GetCurrentException APIs to SBThread, add frame recognizer for objc_exception_throw for Obj-C runtimes

This adds new APIs and a command to deal with exceptions (mostly Obj-C exceptions): SBThread and Thread get GetCurrentException API, which returns an SBValue/ValueObjectSP with the current exception for a thread. "Current" means an exception that is currently being thrown, caught or otherwise processed. In this patch, we only know about the exception when in objc_exception_throw, but subsequent patches will expand this (and add GetCurrentExceptionBacktrace, which will return an SBThread/ThreadSP containing a historical thread backtrace retrieved from the exception object. Currently unimplemented, subsequent patches will implement this).

Extracting the exception from objc_exception_throw is implemented by adding a frame recognizer.

This also add a new sub-command "thread exception", which prints the current exception.

Differential Revision: https://reviews.llvm.org/D43886


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

Modified: lldb/trunk/include/lldb/API/SBThread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBThread.h?rev=347813&r1=347812&r2=347813&view=diff
==============================================================================
--- lldb/trunk/include/lldb/API/SBThread.h (original)
+++ lldb/trunk/include/lldb/API/SBThread.h Wed Nov 28 14:01:52 2018
@@ -198,6 +198,11 @@ public:
 
   uint32_t GetExtendedBacktraceOriginatingIndexID();
 
+  SBValue GetCurrentException();
+
+  // TODO(kubamracek): Extract backtrace from SBValue into SBThread
+  // SBThread GetCurrentExceptionBacktrace();
+
   bool SafeToCallFunctions();
 
 #ifndef SWIG

Modified: lldb/trunk/include/lldb/Target/StackFrameRecognizer.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/StackFrameRecognizer.h?rev=347813&r1=347812&r2=347813&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/StackFrameRecognizer.h (original)
+++ lldb/trunk/include/lldb/Target/StackFrameRecognizer.h Wed Nov 28 14:01:52 2018
@@ -30,6 +30,9 @@ public:
   virtual lldb::ValueObjectListSP GetRecognizedArguments() {
     return m_arguments;
   }
+  virtual lldb::ValueObjectSP GetExceptionObject() {
+    return lldb::ValueObjectSP();
+  }
   virtual ~RecognizedStackFrame(){};
 
 protected:
@@ -97,7 +100,8 @@ private:
 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,

Modified: lldb/trunk/include/lldb/Target/Thread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Thread.h?rev=347813&r1=347812&r2=347813&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Thread.h (original)
+++ lldb/trunk/include/lldb/Target/Thread.h Wed Nov 28 14:01:52 2018
@@ -1253,6 +1253,11 @@ public:
   //----------------------------------------------------------------------
   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;

Modified: lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py?rev=347813&r1=347812&r2=347813&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py Wed Nov 28 14:01:52 2018
@@ -23,6 +23,16 @@ class ObjCExceptionsTestCase(TestBase):
         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,

Modified: lldb/trunk/source/API/SBThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBThread.cpp?rev=347813&r1=347812&r2=347813&view=diff
==============================================================================
--- lldb/trunk/source/API/SBThread.cpp (original)
+++ lldb/trunk/source/API/SBThread.cpp Wed Nov 28 14:01:52 2018
@@ -1484,6 +1484,21 @@ uint32_t SBThread::GetExtendedBacktraceO
   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)

Modified: lldb/trunk/source/Commands/CommandObjectThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectThread.cpp?rev=347813&r1=347812&r2=347813&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectThread.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectThread.cpp Wed Nov 28 14:01:52 2018
@@ -1520,6 +1520,52 @@ public:
 };
 
 //-------------------------------------------------------------------------
+// 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
 //-------------------------------------------------------------------------
 
@@ -2064,6 +2110,9 @@ CommandObjectMultiwordThread::CommandObj
                  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",

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp?rev=347813&r1=347812&r2=347813&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp Wed Nov 28 14:01:52 2018
@@ -455,13 +455,19 @@ lldb::SearchFilterSP AppleObjCRuntime::C
 
   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());

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h?rev=347813&r1=347812&r2=347813&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h Wed Nov 28 14:01:52 2018
@@ -86,6 +86,8 @@ public:
   bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override;
 
   lldb::SearchFilterSP CreateExceptionSearchFilter() override;
+  
+  static std::tuple<FileSpec, ConstString> GetExceptionThrowLocation();
 
   uint32_t GetFoundationVersion();
 

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp?rev=347813&r1=347812&r2=347813&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp Wed Nov 28 14:01:52 2018
@@ -113,8 +113,9 @@ AppleObjCRuntimeV1::CreateExceptionResol
 
   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;
 }

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp?rev=347813&r1=347812&r2=347813&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp Wed Nov 28 14:01:52 2018
@@ -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 @@ ExtractRuntimeGlobalSymbol(Process *proc
   }
 }
 
+static void RegisterObjCExceptionRecognizer();
+
 AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process,
                                        const ModuleSP &objc_module_sp)
     : AppleObjCRuntime(process), m_get_class_info_code(),
@@ -393,6 +398,7 @@ AppleObjCRuntimeV2::AppleObjCRuntimeV2(P
   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 @@ AppleObjCRuntimeV2::CreateExceptionResol
 
   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 @@ void AppleObjCRuntimeV2::GetValuesForGlo
   } 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);
+  });
+}

Modified: lldb/trunk/source/Target/StackFrameRecognizer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StackFrameRecognizer.cpp?rev=347813&r1=347812&r2=347813&view=diff
==============================================================================
--- lldb/trunk/source/Target/StackFrameRecognizer.cpp (original)
+++ lldb/trunk/source/Target/StackFrameRecognizer.cpp Wed Nov 28 14:01:52 2018
@@ -49,8 +49,9 @@ ScriptedStackFrameRecognizer::RecognizeF
 
 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 @@ StackFrameRecognizerManagerImpl &GetStac
 }
 
 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);
 }

Modified: lldb/trunk/source/Target/Thread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Thread.cpp?rev=347813&r1=347812&r2=347813&view=diff
==============================================================================
--- lldb/trunk/source/Target/Thread.cpp (original)
+++ lldb/trunk/source/Target/Thread.cpp Wed Nov 28 14:01:52 2018
@@ -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"
@@ -2199,3 +2200,18 @@ Status Thread::StepOut() {
   }
   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();
+}*/




More information about the lldb-commits mailing list