Author: Jim Ingham
Date: 2023-04-05T17:14:25-07:00
New Revision: f79c037b63278bc5b4481a1a55c68e42f0ea1461

URL: 
https://github.com/llvm/llvm-project/commit/f79c037b63278bc5b4481a1a55c68e42f0ea1461
DIFF: 
https://github.com/llvm/llvm-project/commit/f79c037b63278bc5b4481a1a55c68e42f0ea1461.diff

LOG: Fix the check in StopInfoBreakpoint for "are we currently running an 
expression"

We were checking "WasTheLastResumeForUserExpression" but that returns true even
if that expression was completed, provided we haven't run again.  This uses a
better check.

This is actually fairly hard to trigger.  It happens the first time you hit an
objc_exception_throw breakpoint and invoke that frame recognizer for that.  But
I couldn't trigger it using a Python based frame recognizer.  So I wrote a test
for the objc_exception_throw_breakpoint recognizer which should have been there
anyway...  It fails (the target auto-continues) w/o this patch and succeeds with
it.

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

Added: 
    lldb/test/API/macosx/objc_exception_recognizer/Makefile
    lldb/test/API/macosx/objc_exception_recognizer/TestObjCRecognizer.py
    lldb/test/API/macosx/objc_exception_recognizer/main.m

Modified: 
    lldb/include/lldb/Target/Process.h
    lldb/source/Target/StopInfo.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Target/Process.h 
b/lldb/include/lldb/Target/Process.h
index 3ffacb52299b9..1857dd0a7ada9 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -284,6 +284,13 @@ class ProcessModID {
     return m_resume_id == m_last_user_expression_resume;
   }
 
+  bool IsRunningExpression() const {
+    // Don't return true if we are no longer running an expression:
+    if (m_running_user_expression || m_running_utility_function)
+      return true;
+    return false;
+  }
+
   void SetRunningUserExpression(bool on) {
     if (on)
       m_running_user_expression++;

diff  --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index a98fc28c7338d..9fd0e0a5674ec 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -332,7 +332,7 @@ class StopInfoBreakpoint : public StopInfo {
 
           ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
           Process *process = exe_ctx.GetProcessPtr();
-          if (process->GetModIDRef().IsLastResumeForUserExpression()) {
+          if (process->GetModIDRef().IsRunningExpression()) {
             // If we are in the middle of evaluating an expression, don't run
             // asynchronous breakpoint commands or expressions.  That could
             // lead to infinite recursion if the command or condition re-calls

diff  --git a/lldb/test/API/macosx/objc_exception_recognizer/Makefile 
b/lldb/test/API/macosx/objc_exception_recognizer/Makefile
new file mode 100644
index 0000000000000..66119b1b48248
--- /dev/null
+++ b/lldb/test/API/macosx/objc_exception_recognizer/Makefile
@@ -0,0 +1,4 @@
+OBJC_SOURCES := main.m
+LD_EXTRAS := -framework Foundation
+
+include Makefile.rules

diff  --git 
a/lldb/test/API/macosx/objc_exception_recognizer/TestObjCRecognizer.py 
b/lldb/test/API/macosx/objc_exception_recognizer/TestObjCRecognizer.py
new file mode 100644
index 0000000000000..d7e5eb310a191
--- /dev/null
+++ b/lldb/test/API/macosx/objc_exception_recognizer/TestObjCRecognizer.py
@@ -0,0 +1,69 @@
+"""
+Test that the built in ObjC exception throw recognizer works
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.lldbtest import *
+
+class TestObjCRecognizer(TestBase):
+
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipUnlessDarwin
+    def test_exception_recognizer_sub_class(self):
+        """There can be many tests in a test case - describe this test here."""
+        self.build()
+        self.main_source_file = lldb.SBFileSpec("main.m")
+        self.objc_recognizer_test(True)
+        
+    @skipUnlessDarwin
+    def test_exception_recognizer_plain(self):
+        """There can be many tests in a test case - describe this test here."""
+        self.build()
+        self.main_source_file = lldb.SBFileSpec("main.m")
+        self.objc_recognizer_test(False)
+        
+    def objc_recognizer_test(self, sub_class):
+        """Make sure we stop at the exception and get all the fields out of 
the recognizer.
+           If sub_class is True, we make a subclass of NSException and throw 
that."""
+        if sub_class:
+            bkpt_string = "Set a breakpoint here for MyException"
+        else:
+            bkpt_string = "Set a breakpoint here for plain exception"
+            
+        (target, process, thread, bkpt) = 
lldbutil.run_to_source_breakpoint(self,
+                                   bkpt_string, self.main_source_file)
+
+        # Now turn on the ObjC Exception breakpoint and continue to hit it:
+        exception_bkpt = 
target.BreakpointCreateForException(lldb.eLanguageTypeObjC, False, True)
+        self.assertTrue(exception_bkpt.GetNumLocations() > 0, "Got some 
exception locations")
+
+        threads = lldbutil.continue_to_breakpoint(process, exception_bkpt)
+        self.assertEqual(len(threads), 1, "One thread hit exception 
breakpoint")
+        frame = threads[0].frame[0]
+
+        var_opts = lldb.SBVariablesOptions()
+        var_opts.SetIncludeRecognizedArguments(True)
+        var_opts.SetUseDynamic(True)
+        vars = frame.GetVariables(var_opts)
+        self.assertEqual(len(vars), 1, "Got the synthetic argument")
+        self.assertTrue(vars[0].IsValid(), "Got a valid Exception variable")
+
+        # This will be a pointer
+
+        ns_exception_children = [ValueCheck(type="NSObject"),
+                                 ValueCheck(name="name", 
summary='"NSException"'),
+                                 ValueCheck(name="reason", summary='"Simple 
Reason"'),
+                                 ValueCheck(name="userInfo"),
+                                 ValueCheck(name="reserved")]
+        ns_exception = ValueCheck(type="NSException", 
children=ns_exception_children) 
+        if not sub_class:
+            simple_check = ValueCheck(name="exception", 
dereference=ns_exception)
+            simple_check.check_value(self, vars[0], "Simple exception is 
right")
+        else:
+            my_exception_children = [ns_exception, 
ValueCheck(name="extra_info", type="int", value="100")]
+            my_exception = ValueCheck(type="MyException", 
children=my_exception_children)
+            sub_check = ValueCheck(name="exception", type="MyException *", 
dereference=my_exception)
+            sub_check.check_value(self, vars[0], "Subclass exception is right")

diff  --git a/lldb/test/API/macosx/objc_exception_recognizer/main.m 
b/lldb/test/API/macosx/objc_exception_recognizer/main.m
new file mode 100644
index 0000000000000..db98f5cb98c05
--- /dev/null
+++ b/lldb/test/API/macosx/objc_exception_recognizer/main.m
@@ -0,0 +1,37 @@
+#import <Foundation/Foundation.h>
+
+@interface MyException : NSException
+{
+  int extra_info;
+}
+- (NSException *) initWithExtraInfo: (int) info;
+@end
+
+@implementation MyException
+- (NSException *) initWithExtraInfo: (int) info
+{
+  [super initWithName: @"NSException" reason: @"Simple Reason" userInfo: nil];
+  self->extra_info = info;
+  return self;
+}
+@end
+
+int
+main(int argc, char **argv)
+{
+  // Set a breakpoint here for plain exception:
+  @try {
+    NSException *plain_exc = [[NSException alloc] initWithName: @"NSException" 
reason: @"Simple Reason" userInfo: nil];
+    [plain_exc raise];
+  }
+  @catch (id anException) {}
+
+  // Set a breakpoint here for MyException:
+  @try {
+    MyException *my_exc = [[MyException alloc] initWithExtraInfo: 100];
+    [my_exc raise];
+  }
+  @catch (id anException) {}
+
+  return 0;
+}


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

Reply via email to