Author: kuba.brecka
Date: Wed Dec 19 18:01:59 2018
New Revision: 349718

URL: http://llvm.org/viewvc/llvm-project?rev=349718&view=rev
Log:
[lldb] Retrieve currently handled Obj-C exception via 
__cxa_current_exception_type and add GetCurrentExceptionBacktrace SB ABI

This builds on https://reviews.llvm.org/D43884 and 
https://reviews.llvm.org/D43886 and extends LLDB support of Obj-C exceptions to 
also look for a "current exception" for a thread in the C++ exception handling 
runtime metadata (via call to __cxa_current_exception_type). We also construct 
an actual historical SBThread/ThreadSP that contains frames from the backtrace 
in the Obj-C exception object.

The high level goal this achieves is that when we're already crashed (because 
an unhandled exception occurred), we can still access the exception object and 
retrieve the backtrace from the throw point. In Obj-C, this is particularly 
useful because a catch+rethrow is very common and in those cases you currently 
don't have any access to the throw point backtrace.

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


Added:
    lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.mm
      - copied, changed from r349717, 
lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m
Removed:
    lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m
Modified:
    lldb/trunk/include/lldb/API/SBThread.h
    lldb/trunk/include/lldb/Target/LanguageRuntime.h
    lldb/trunk/include/lldb/Target/Thread.h
    lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/Makefile
    
lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
    lldb/trunk/scripts/interface/SBThread.i
    lldb/trunk/source/API/SBThread.cpp
    lldb/trunk/source/Commands/CommandObjectThread.cpp
    
lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
    
lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
    
lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
    
lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
    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=349718&r1=349717&r2=349718&view=diff
==============================================================================
--- lldb/trunk/include/lldb/API/SBThread.h (original)
+++ lldb/trunk/include/lldb/API/SBThread.h Wed Dec 19 18:01:59 2018
@@ -200,8 +200,7 @@ public:
 
   SBValue GetCurrentException();
 
-  // TODO(kubamracek): Extract backtrace from SBValue into SBThread
-  // SBThread GetCurrentExceptionBacktrace();
+  SBThread GetCurrentExceptionBacktrace();
 
   bool SafeToCallFunctions();
 

Modified: lldb/trunk/include/lldb/Target/LanguageRuntime.h
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/LanguageRuntime.h?rev=349718&r1=349717&r2=349718&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/LanguageRuntime.h (original)
+++ lldb/trunk/include/lldb/Target/LanguageRuntime.h Wed Dec 19 18:01:59 2018
@@ -119,6 +119,17 @@ public:
   static Breakpoint::BreakpointPreconditionSP
   CreateExceptionPrecondition(lldb::LanguageType language, bool catch_bp,
                               bool throw_bp);
+
+  virtual lldb::ValueObjectSP GetExceptionObjectForThread(
+      lldb::ThreadSP thread_sp) {
+    return lldb::ValueObjectSP();
+  }
+
+  virtual lldb::ThreadSP GetBacktraceThreadFromException(
+      lldb::ValueObjectSP thread_sp) {
+    return lldb::ThreadSP();
+  }
+
   Process *GetProcess() { return m_process; }
 
   Target &GetTargetRef() { return m_process->GetTarget(); }

Modified: lldb/trunk/include/lldb/Target/Thread.h
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Thread.h?rev=349718&r1=349717&r2=349718&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Thread.h (original)
+++ lldb/trunk/include/lldb/Target/Thread.h Wed Dec 19 18:01:59 2018
@@ -1255,8 +1255,7 @@ public:
 
   lldb::ValueObjectSP GetCurrentException();
 
-  // TODO(kubamracek): Extract backtrace from ValueObjectSP into ThreadSP
-  // lldb::ThreadSP GetCurrentExceptionBacktrace();
+  lldb::ThreadSP GetCurrentExceptionBacktrace();
 
 protected:
   friend class ThreadPlan;

Modified: 
lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/Makefile
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/Makefile?rev=349718&r1=349717&r2=349718&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/Makefile 
(original)
+++ lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/Makefile Wed 
Dec 19 18:01:59 2018
@@ -1,6 +1,6 @@
 LEVEL = ../../../make
 
-OBJC_SOURCES := main.m
+OBJCXX_SOURCES := main.mm
 
 CFLAGS_EXTRAS += -w
 

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=349718&r1=349717&r2=349718&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 Dec 19 18:01:59 2018
@@ -17,13 +17,14 @@ class ObjCExceptionsTestCase(TestBase):
     mydir = TestBase.compute_mydir(__file__)
 
     @skipUnlessDarwin
-    def test_objc_exceptions_1(self):
+    def test_objc_exceptions_at_throw(self):
         self.build()
 
         target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
         self.assertTrue(target, VALID_TARGET)
 
-        lldbutil.run_to_name_breakpoint(self, "objc_exception_throw")
+        launch_info = lldb.SBLaunchInfo(["a.out", "0"])
+        lldbutil.run_to_name_breakpoint(self, "objc_exception_throw", 
launch_info=launch_info)
 
         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
                     substrs=['stopped', 'stop reason = breakpoint'])
@@ -33,7 +34,7 @@ class ObjCExceptionsTestCase(TestBase):
                 'name: "ThrownException" - reason: "SomeReason"',
             ])
 
-        lldbutil.run_to_source_breakpoint(self, "// Set break point at this 
line.", lldb.SBFileSpec("main.m"))
+        lldbutil.run_to_source_breakpoint(self, "// Set break point at this 
line.", lldb.SBFileSpec("main.mm"), launch_info=launch_info)
 
         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
                     substrs=['stopped', 'stop reason = breakpoint'])
@@ -42,19 +43,23 @@ class ObjCExceptionsTestCase(TestBase):
         thread = target.GetProcess().GetSelectedThread()
         frame = thread.GetSelectedFrame()
 
+        # No exception being currently thrown/caught at this point
+        self.assertFalse(thread.GetCurrentException().IsValid())
+        self.assertFalse(thread.GetCurrentExceptionBacktrace().IsValid())
+
         self.expect(
             'frame variable e1',
             substrs=[
                 '(NSException *) e1 = ',
-                'name: @"ExceptionName" - reason: @"SomeReason"'
+                'name: "ExceptionName" - reason: "SomeReason"'
             ])
 
         self.expect(
             'frame variable --dynamic-type no-run-target *e1',
             substrs=[
                 '(NSException) *e1 = ',
-                'name = ', '@"ExceptionName"',
-                'reason = ', '@"SomeReason"',
+                'name = ', '"ExceptionName"',
+                'reason = ', '"SomeReason"',
                 'userInfo = ', '1 key/value pair',
                 'reserved = ', 'nil',
             ])
@@ -62,7 +67,7 @@ class ObjCExceptionsTestCase(TestBase):
         e1 = frame.FindVariable("e1")
         self.assertTrue(e1)
         self.assertEqual(e1.type.name, "NSException *")
-        self.assertEqual(e1.GetSummary(), 'name: @"ExceptionName" - reason: 
@"SomeReason"')
+        self.assertEqual(e1.GetSummary(), 'name: "ExceptionName" - reason: 
"SomeReason"')
         self.assertEqual(e1.GetChildMemberWithName("name").description, 
"ExceptionName")
         self.assertEqual(e1.GetChildMemberWithName("reason").description, 
"SomeReason")
         userInfo = e1.GetChildMemberWithName("userInfo").dynamic
@@ -75,15 +80,15 @@ class ObjCExceptionsTestCase(TestBase):
             'frame variable e2',
             substrs=[
                 '(NSException *) e2 = ',
-                'name: @"ThrownException" - reason: @"SomeReason"'
+                'name: "ThrownException" - reason: "SomeReason"'
             ])
 
         self.expect(
             'frame variable --dynamic-type no-run-target *e2',
             substrs=[
                 '(NSException) *e2 = ',
-                'name = ', '@"ThrownException"',
-                'reason = ', '@"SomeReason"',
+                'name = ', '"ThrownException"',
+                'reason = ', '"SomeReason"',
                 'userInfo = ', '1 key/value pair',
                 'reserved = ',
             ])
@@ -91,7 +96,7 @@ class ObjCExceptionsTestCase(TestBase):
         e2 = frame.FindVariable("e2")
         self.assertTrue(e2)
         self.assertEqual(e2.type.name, "NSException *")
-        self.assertEqual(e2.GetSummary(), 'name: @"ThrownException" - reason: 
@"SomeReason"')
+        self.assertEqual(e2.GetSummary(), 'name: "ThrownException" - reason: 
"SomeReason"')
         self.assertEqual(e2.GetChildMemberWithName("name").description, 
"ThrownException")
         self.assertEqual(e2.GetChildMemberWithName("reason").description, 
"SomeReason")
         userInfo = e2.GetChildMemberWithName("userInfo").dynamic
@@ -106,5 +111,84 @@ class ObjCExceptionsTestCase(TestBase):
 
         pcs = [i.unsigned for i in children]
         names = [target.ResolveSymbolContextForAddress(lldb.SBAddress(pc, 
target), lldb.eSymbolContextSymbol).GetSymbol().name for pc in pcs]
-        for n in ["objc_exception_throw", "foo", "main"]:
+        for n in ["objc_exception_throw", "foo(int)", "main"]:
             self.assertTrue(n in names, "%s is in the exception backtrace 
(%s)" % (n, names))
+
+    @skipUnlessDarwin
+    def test_objc_exceptions_at_abort(self):
+        self.build()
+
+        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+        self.assertTrue(target, VALID_TARGET)
+
+        self.runCmd("run 0")
+
+        # We should be stopped at pthread_kill because of an unhandled 
exception
+        self.expect("thread list",
+            substrs=['stopped', 'stop reason = signal SIGABRT'])
+
+        self.expect('thread exception', substrs=[
+                '(NSException *) exception = ',
+                'name: "ThrownException" - reason: "SomeReason"',
+                'libobjc.A.dylib`objc_exception_throw',
+                'a.out`foo', 'at main.mm:25',
+                'a.out`rethrow', 'at main.mm:36',
+                'a.out`main',
+            ])
+
+        process = self.dbg.GetSelectedTarget().process
+        thread = process.GetSelectedThread()
+
+        # There is an exception being currently processed at this point
+        self.assertTrue(thread.GetCurrentException().IsValid())
+        self.assertTrue(thread.GetCurrentExceptionBacktrace().IsValid())
+
+        history_thread = thread.GetCurrentExceptionBacktrace()
+        self.assertGreaterEqual(history_thread.num_frames, 4)
+        for n in ["objc_exception_throw", "foo(int)", "rethrow(int)", "main"]:
+            self.assertEqual(len([f for f in history_thread.frames if 
f.GetFunctionName() == n]), 1)
+
+        self.runCmd("kill")
+
+        self.runCmd("run 1")
+        # We should be stopped at pthread_kill because of an unhandled 
exception
+        self.expect("thread list",
+            substrs=['stopped', 'stop reason = signal SIGABRT'])
+
+        self.expect('thread exception', substrs=[
+                '(MyCustomException *) exception = ',
+                'libobjc.A.dylib`objc_exception_throw',
+                'a.out`foo', 'at main.mm:27',
+                'a.out`rethrow', 'at main.mm:36',
+                'a.out`main',
+            ])
+
+        process = self.dbg.GetSelectedTarget().process
+        thread = process.GetSelectedThread()
+
+        history_thread = thread.GetCurrentExceptionBacktrace()
+        self.assertGreaterEqual(history_thread.num_frames, 4)
+        for n in ["objc_exception_throw", "foo(int)", "rethrow(int)", "main"]:
+            self.assertEqual(len([f for f in history_thread.frames if 
f.GetFunctionName() == n]), 1)
+
+    @skipUnlessDarwin
+    def test_cxx_exceptions_at_abort(self):
+        self.build()
+
+        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+        self.assertTrue(target, VALID_TARGET)
+
+        self.runCmd("run 2")
+
+        # We should be stopped at pthread_kill because of an unhandled 
exception
+        self.expect("thread list",
+            substrs=['stopped', 'stop reason = signal SIGABRT'])
+
+        self.expect('thread exception', substrs=[])
+
+        process = self.dbg.GetSelectedTarget().process
+        thread = process.GetSelectedThread()
+
+        # C++ exceptions are not exposed in the API (yet).
+        self.assertFalse(thread.GetCurrentException().IsValid())
+        self.assertFalse(thread.GetCurrentExceptionBacktrace().IsValid())

Removed: lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m?rev=349717&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m 
(original)
+++ lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m 
(removed)
@@ -1,36 +0,0 @@
-//===-- 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()
-{
-    NSDictionary *info = [NSDictionary 
dictionaryWithObjectsAndKeys:@"some_value", @"some_key", nil];
-    @throw [[NSException alloc] initWithName:@"ThrownException" 
reason:@"SomeReason" userInfo:info];
-}
-
-int main (int argc, const char * argv[])
-{
-    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
-    NSDictionary *info = [NSDictionary 
dictionaryWithObjectsAndKeys:@"some_value", @"some_key", nil];
-    NSException *e1 = [[NSException alloc] initWithName:@"ExceptionName" 
reason:@"SomeReason" userInfo:info];
-    NSException *e2;
-
-    @try {
-        foo();
-    } @catch(NSException *e) {
-        e2 = e;
-    }
-
-    NSLog(@"1"); // Set break point at this line.
-    [pool drain];
-    return 0;
-}
-

Copied: lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.mm 
(from r349717, 
lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m)
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.mm?p2=lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.mm&p1=lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m&r1=349717&r2=349718&rev=349718&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m 
(original)
+++ lldb/trunk/packages/Python/lldbsuite/test/lang/objc/exceptions/main.mm Wed 
Dec 19 18:01:59 2018
@@ -9,13 +9,37 @@
 
 #import <Foundation/Foundation.h>
 
-void foo()
+#import <exception>
+#import <stdexcept>
+
+@interface MyCustomException: NSException
+@end
+@implementation MyCustomException
+@end
+
+void foo(int n)
 {
     NSDictionary *info = [NSDictionary 
dictionaryWithObjectsAndKeys:@"some_value", @"some_key", nil];
-    @throw [[NSException alloc] initWithName:@"ThrownException" 
reason:@"SomeReason" userInfo:info];
+    switch (n) {
+        case 0:
+            @throw [[NSException alloc] initWithName:@"ThrownException" 
reason:@"SomeReason" userInfo:info];
+        case 1:
+            @throw [[MyCustomException alloc] initWithName:@"ThrownException" 
reason:@"SomeReason" userInfo:info];
+        case 2:
+            throw std::runtime_error("C++ exception");
+    }
 }
 
-int main (int argc, const char * argv[])
+void rethrow(int n)
+{
+    @try {
+        foo(n);
+    } @catch(NSException *e) {
+        @throw;
+    }
+}
+
+int main(int argc, const char * argv[])
 {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
@@ -24,12 +48,15 @@ int main (int argc, const char * argv[])
     NSException *e2;
 
     @try {
-        foo();
+        foo(atoi(argv[1]));
     } @catch(NSException *e) {
         e2 = e;
     }
 
     NSLog(@"1"); // Set break point at this line.
+
+    rethrow(atoi(argv[1]));
+
     [pool drain];
     return 0;
 }

Modified: lldb/trunk/scripts/interface/SBThread.i
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/interface/SBThread.i?rev=349718&r1=349717&r2=349718&view=diff
==============================================================================
--- lldb/trunk/scripts/interface/SBThread.i (original)
+++ lldb/trunk/scripts/interface/SBThread.i Wed Dec 19 18:01:59 2018
@@ -397,6 +397,24 @@ public:
     ") GetExtendedBacktraceOriginatingIndexID;
     uint32_t
     GetExtendedBacktraceOriginatingIndexID();
+    
+    %feature("autodoc","
+    Returns an SBValue object represeting the current exception for the thread,
+    if there is any. Currently, this works for Obj-C code and returns an 
SBValue
+    representing the NSException object at the throw site or that's currently
+    being processes.
+    ") GetCurrentException;
+    lldb::SBValue
+    GetCurrentException();
+
+    %feature("autodoc","
+    Returns a historical (fake) SBThread representing the stack trace of an
+    exception, if there is one for the thread. Currently, this works for Obj-C
+    code, and can retrieve the throw-site backtrace of an NSException object
+    even when the program is no longer at the throw site.
+    ") GetCurrentExceptionBacktrace;
+    lldb::SBThread
+    GetCurrentExceptionBacktrace();
 
     %feature("autodoc","
     Takes no arguments, returns a bool.

Modified: lldb/trunk/source/API/SBThread.cpp
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBThread.cpp?rev=349718&r1=349717&r2=349718&view=diff
==============================================================================
--- lldb/trunk/source/API/SBThread.cpp (original)
+++ lldb/trunk/source/API/SBThread.cpp Wed Dec 19 18:01:59 2018
@@ -1491,13 +1491,12 @@ SBValue SBThread::GetCurrentException()
   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());

Modified: lldb/trunk/source/Commands/CommandObjectThread.cpp
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectThread.cpp?rev=349718&r1=349717&r2=349718&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectThread.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectThread.cpp Wed Dec 19 18:01:59 2018
@@ -1552,14 +1552,13 @@ class CommandObjectThreadException : pub
       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,
+      exception_thread_sp->GetStatus(strm, 0, UINT32_MAX,
                                      num_frames_with_source, stop_format);
-    }*/
+    }
 
     return true;
   }

Modified: 
lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp?rev=349718&r1=349717&r2=349718&view=diff
==============================================================================
--- 
lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
 (original)
+++ 
lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
 Wed Dec 19 18:01:59 2018
@@ -16,6 +16,9 @@
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/ValueObject.h"
 #include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Expression/DiagnosticManager.h"
+#include "lldb/Expression/FunctionCaller.h"
 #include "lldb/Interpreter/CommandObject.h"
 #include "lldb/Interpreter/CommandObjectMultiword.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
@@ -549,6 +552,61 @@ bool ItaniumABILanguageRuntime::Exceptio
       break_site_id, m_cxx_exception_bp_sp->GetID());
 }
 
+ValueObjectSP ItaniumABILanguageRuntime::GetExceptionObjectForThread(
+    ThreadSP thread_sp) {
+  ClangASTContext *clang_ast_context =
+      m_process->GetTarget().GetScratchClangASTContext();
+  CompilerType voidstar =
+      clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+
+  DiagnosticManager diagnostics;
+  ExecutionContext exe_ctx;
+  EvaluateExpressionOptions options;
+
+  options.SetUnwindOnError(true);
+  options.SetIgnoreBreakpoints(true);
+  options.SetStopOthers(true);
+  options.SetTimeout(std::chrono::milliseconds(500));
+  options.SetTryAllThreads(false);
+  thread_sp->CalculateExecutionContext(exe_ctx);
+
+  const ModuleList &modules = m_process->GetTarget().GetImages();
+  SymbolContextList contexts;
+  SymbolContext context;
+
+  modules.FindSymbolsWithNameAndType(
+      ConstString("__cxa_current_exception_type"), eSymbolTypeCode, contexts);
+  contexts.GetContextAtIndex(0, context);
+  Address addr = context.symbol->GetAddress();
+
+  Status error;
+  FunctionCaller *function_caller =
+      m_process->GetTarget().GetFunctionCallerForLanguage(
+          eLanguageTypeC, voidstar, addr, ValueList(), "caller", error);
+
+  ExpressionResults func_call_ret;
+  Value results;
+  func_call_ret = function_caller->ExecuteFunction(exe_ctx, nullptr, options,
+                                                   diagnostics, results);
+  if (func_call_ret != eExpressionCompleted || !error.Success()) {
+    return ValueObjectSP();
+  }
+
+  size_t ptr_size = m_process->GetAddressByteSize();
+  addr_t result_ptr = results.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+  addr_t exception_addr =
+      m_process->ReadPointerFromMemory(result_ptr - ptr_size, error);
+
+  lldb_private::formatters::InferiorSizedWord exception_isw(exception_addr,
+                                                            *m_process);
+  ValueObjectSP exception = ValueObject::CreateValueObjectFromData(
+      "exception", exception_isw.GetAsData(m_process->GetByteOrder()), exe_ctx,
+      voidstar);
+  exception = exception->GetDynamicValue(eDynamicDontRunTarget);
+
+  return exception;
+}
+
 TypeAndOrName ItaniumABILanguageRuntime::GetDynamicTypeInfo(
     const lldb_private::Address &vtable_addr) {
   std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex);

Modified: 
lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h?rev=349718&r1=349717&r2=349718&view=diff
==============================================================================
--- 
lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
 (original)
+++ 
lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
 Wed Dec 19 18:01:59 2018
@@ -65,6 +65,9 @@ public:
                                                      bool throw_bp) override;
 
   lldb::SearchFilterSP CreateExceptionSearchFilter() override;
+  
+  lldb::ValueObjectSP GetExceptionObjectForThread(
+      lldb::ThreadSP thread_sp) override;
 
   //------------------------------------------------------------------
   // PluginInterface protocol

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=349718&r1=349717&r2=349718&view=diff
==============================================================================
--- 
lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
 (original)
+++ 
lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
 Wed Dec 19 18:01:59 2018
@@ -19,10 +19,13 @@
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/Section.h"
 #include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
 #include "lldb/Expression/DiagnosticManager.h"
 #include "lldb/Expression/FunctionCaller.h"
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
@@ -35,6 +38,9 @@
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/StreamString.h"
 
+#include "Plugins/Process/Utility/HistoryThread.h"
+#include "Plugins/Language/ObjC/NSString.h"
+
 #include <vector>
 
 using namespace lldb;
@@ -459,6 +465,102 @@ lldb::SearchFilterSP AppleObjCRuntime::C
   }
 }
 
+ValueObjectSP AppleObjCRuntime::GetExceptionObjectForThread(
+    ThreadSP thread_sp) {
+  auto cpp_runtime = m_process->GetCPPLanguageRuntime();
+  if (!cpp_runtime) return ValueObjectSP();
+  auto cpp_exception = cpp_runtime->GetExceptionObjectForThread(thread_sp);
+  if (!cpp_exception) return ValueObjectSP();
+  
+  auto descriptor = GetClassDescriptor(*cpp_exception.get());
+  if (!descriptor || !descriptor->IsValid()) return ValueObjectSP();
+  
+  while (descriptor) {
+    ConstString class_name(descriptor->GetClassName());
+    if (class_name == ConstString("NSException")) return cpp_exception;
+    descriptor = descriptor->GetSuperclass();
+  }
+
+  return ValueObjectSP();
+}
+
+ThreadSP AppleObjCRuntime::GetBacktraceThreadFromException(
+    lldb::ValueObjectSP exception_sp) {
+  ValueObjectSP reserved_dict =
+      exception_sp->GetChildMemberWithName(ConstString("reserved"), true);
+  if (!reserved_dict) return ThreadSP();
+
+  reserved_dict = reserved_dict->GetSyntheticValue();
+  if (!reserved_dict) return ThreadSP();
+
+  CompilerType objc_id =
+      exception_sp->GetTargetSP()->GetScratchClangASTContext()->GetBasicType(
+          lldb::eBasicTypeObjCID);
+  ValueObjectSP return_addresses;
+
+  auto objc_object_from_address = [&exception_sp, &objc_id](uint64_t addr,
+                                                            const char *name) {
+    Value value(addr);
+    value.SetCompilerType(objc_id);
+    auto object = ValueObjectConstResult::Create(
+        exception_sp->GetTargetSP().get(), value, ConstString(name));
+    object = object->GetDynamicValue(eDynamicDontRunTarget);
+    return object;
+  };
+
+  for (size_t idx = 0; idx < reserved_dict->GetNumChildren(); idx++) {
+    ValueObjectSP dict_entry = reserved_dict->GetChildAtIndex(idx, true);
+
+    DataExtractor data;
+    data.SetAddressByteSize(dict_entry->GetProcessSP()->GetAddressByteSize());
+    Status error;
+    dict_entry->GetData(data, error);
+    if (error.Fail()) return ThreadSP();
+
+    lldb::offset_t data_offset = 0;
+    auto dict_entry_key = data.GetPointer(&data_offset);
+    auto dict_entry_value = data.GetPointer(&data_offset);
+
+    auto key_nsstring = objc_object_from_address(dict_entry_key, "key");
+    StreamString key_summary;
+    if (lldb_private::formatters::NSStringSummaryProvider(
+            *key_nsstring, key_summary, TypeSummaryOptions()) &&
+        !key_summary.Empty()) {
+      if (key_summary.GetString() == "\"callStackReturnAddresses\"") {
+        return_addresses = objc_object_from_address(dict_entry_value,
+                                                    
"callStackReturnAddresses");
+        break;
+      }
+    }
+  }
+
+  if (!return_addresses) return ThreadSP();
+  auto frames_value =
+      return_addresses->GetChildMemberWithName(ConstString("_frames"), true);
+  addr_t frames_addr = frames_value->GetValueAsUnsigned(0);
+  auto count_value =
+      return_addresses->GetChildMemberWithName(ConstString("_cnt"), true);
+  size_t count = count_value->GetValueAsUnsigned(0);
+  auto ignore_value =
+      return_addresses->GetChildMemberWithName(ConstString("_ignore"), true);
+  size_t ignore = ignore_value->GetValueAsUnsigned(0);
+
+  size_t ptr_size = m_process->GetAddressByteSize();
+  std::vector<lldb::addr_t> pcs;
+  for (size_t idx = 0; idx < count; idx++) {
+    Status error;
+    addr_t pc = m_process->ReadPointerFromMemory(
+        frames_addr + (ignore + idx) * ptr_size, error);
+    pcs.push_back(pc);
+  }
+
+  if (pcs.empty()) return ThreadSP();
+
+  ThreadSP new_thread_sp(new HistoryThread(*m_process, 0, pcs, 0, false));
+  m_process->GetExtendedThreadList().AddThread(new_thread_sp);
+  return new_thread_sp;
+}
+
 std::tuple<FileSpec, ConstString>
 AppleObjCRuntime::GetExceptionThrowLocation() {
   return std::make_tuple(

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=349718&r1=349717&r2=349718&view=diff
==============================================================================
--- 
lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
 (original)
+++ 
lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
 Wed Dec 19 18:01:59 2018
@@ -89,6 +89,12 @@ public:
   
   static std::tuple<FileSpec, ConstString> GetExceptionThrowLocation();
 
+  lldb::ValueObjectSP GetExceptionObjectForThread(
+      lldb::ThreadSP thread_sp) override;
+
+  lldb::ThreadSP GetBacktraceThreadFromException(
+      lldb::ValueObjectSP thread_sp) override;
+
   uint32_t GetFoundationVersion();
 
   virtual void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,

Modified: lldb/trunk/source/Target/Thread.cpp
URL: 
http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Thread.cpp?rev=349718&r1=349717&r2=349718&view=diff
==============================================================================
--- lldb/trunk/source/Target/Thread.cpp (original)
+++ lldb/trunk/source/Target/Thread.cpp Wed Dec 19 18:01:59 2018
@@ -23,6 +23,7 @@
 #include "lldb/Target/ABI.h"
 #include "lldb/Target/DynamicLoader.h"
 #include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Target/StackFrameRecognizer.h"
@@ -2202,16 +2203,30 @@ Status Thread::StepOut() {
 }
 
 ValueObjectSP Thread::GetCurrentException() {
-  StackFrameSP frame_sp(GetStackFrameAtIndex(0));
-  if (!frame_sp) return ValueObjectSP();
+  if (auto frame_sp = GetStackFrameAtIndex(0))
+    if (auto recognized_frame = frame_sp->GetRecognizedFrame())
+      if (auto e = recognized_frame->GetExceptionObject())
+        return e;
+
+  // FIXME: For now, only ObjC exceptions are supported. This should really
+  // iterate over all language runtimes and ask them all to give us the current
+  // exception.
+  if (auto runtime = GetProcess()->GetObjCLanguageRuntime())
+    if (auto e = runtime->GetExceptionObjectForThread(shared_from_this()))
+      return e;
 
-  RecognizedStackFrameSP recognized_frame(frame_sp->GetRecognizedFrame());
-  if (!recognized_frame) return ValueObjectSP();
-
-  return recognized_frame->GetExceptionObject();
+  return ValueObjectSP();
 }
 
-/* TODO(kubamracek)
 ThreadSP Thread::GetCurrentExceptionBacktrace() {
-  return ThreadSP();
-}*/
+  ValueObjectSP exception = GetCurrentException();
+  if (!exception) return ThreadSP();
+
+  // FIXME: For now, only ObjC exceptions are supported. This should really
+  // iterate over all language runtimes and ask them all to give us the current
+  // exception.
+  auto runtime = GetProcess()->GetObjCLanguageRuntime();
+  if (!runtime) return ThreadSP();
+
+  return runtime->GetBacktraceThreadFromException(exception);
+}


_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to