Add tests for the other variants of BreakpointCreateBySourceRegex.
authorJim Ingham <jingham@apple.com>
Sat, 16 Oct 2021 01:37:47 +0000 (18:37 -0700)
committerJim Ingham <jingham@apple.com>
Mon, 18 Oct 2021 17:59:04 +0000 (10:59 -0700)
I added some tests for the case where the breakpoints take immediately
to the extant test case, and made a new test case for when the source
regex breakpoint will be set in a dlopen-ed library.

I also noticed when doing this that "lldbutil.run_to_source_breakpoint
can't handle the case where the breakpoint will be in a dlopen-ed
library, since it requires the breakpoint to have at least 1 location
before run.  I fixed that by adding a parameter to say whether a
before run location is expected.

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

lldb/packages/Python/lldbsuite/test/lldbutil.py
lldb/test/API/functionalities/breakpoint/break_in_loaded_dylib/Makefile [new file with mode: 0644]
lldb/test/API/functionalities/breakpoint/break_in_loaded_dylib/TestBreakInLoadedDylib.py [new file with mode: 0644]
lldb/test/API/functionalities/breakpoint/break_in_loaded_dylib/b.cpp [new file with mode: 0644]
lldb/test/API/functionalities/breakpoint/break_in_loaded_dylib/main.cpp [new file with mode: 0644]
lldb/test/API/functionalities/breakpoint/breakpoint_command/TestBreakpointCommandsFromPython.py
lldb/test/API/functionalities/breakpoint/breakpoint_command/bktptcmd.py

index 20a6d28..2ab372d 100644 (file)
@@ -953,7 +953,8 @@ def run_to_source_breakpoint(test, bkpt_pattern, source_spec,
                              bkpt_module = None,
                              in_cwd = True,
                              only_one_thread = True,
-                             extra_images = None):
+                             extra_images = None,
+                             has_locations_before_run = True):
     """Start up a target, using exe_name as the executable, and run it to
        a breakpoint set by source regex bkpt_pattern.
 
@@ -964,9 +965,10 @@ def run_to_source_breakpoint(test, bkpt_pattern, source_spec,
     # Set the breakpoints
     breakpoint = target.BreakpointCreateBySourceRegex(
             bkpt_pattern, source_spec, bkpt_module)
-    test.assertTrue(breakpoint.GetNumLocations() > 0,
-        'No locations found for source breakpoint: "%s", file: "%s", dir: "%s"'
-        %(bkpt_pattern, source_spec.GetFilename(), source_spec.GetDirectory()))
+    if has_locations_before_run:
+        test.assertTrue(breakpoint.GetNumLocations() > 0,
+                        'No locations found for source breakpoint: "%s", file: "%s", dir: "%s"'
+                        %(bkpt_pattern, source_spec.GetFilename(), source_spec.GetDirectory()))
     return run_to_breakpoint_do_run(test, target, breakpoint, launch_info,
                                     only_one_thread, extra_images)
 
diff --git a/lldb/test/API/functionalities/breakpoint/break_in_loaded_dylib/Makefile b/lldb/test/API/functionalities/breakpoint/break_in_loaded_dylib/Makefile
new file mode 100644 (file)
index 0000000..0f3fb37
--- /dev/null
@@ -0,0 +1,9 @@
+CXX_SOURCES := main.cpp
+USE_LIBDL := 1
+
+lib_b:
+       $(MAKE) -f $(MAKEFILE_RULES) \
+               DYLIB_ONLY=YES DYLIB_CXX_SOURCES=b.cpp DYLIB_NAME=lib_b
+all: lib_b
+
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/breakpoint/break_in_loaded_dylib/TestBreakInLoadedDylib.py b/lldb/test/API/functionalities/breakpoint/break_in_loaded_dylib/TestBreakInLoadedDylib.py
new file mode 100644 (file)
index 0000000..88fcfc4
--- /dev/null
@@ -0,0 +1,62 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestBreakInLoadedDylib(TestBase):
+    """ Test that we can set a source regex breakpoint that will take in
+    a dlopened library that hasn't loaded when we set the breakpoint."""
+
+    mydir = TestBase.compute_mydir(__file__)
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipIfRemote
+    def common_setup(self):
+        self.build()
+        ctx = self.platformContext
+        self.main_spec = lldb.SBFileSpec("main.cpp")
+        self.b_spec = lldb.SBFileSpec("b.cpp")
+        self.lib_shortname = 'lib_b'
+        self.lib_fullname = ctx.shlib_prefix + self.lib_shortname + '.' + ctx.shlib_extension
+        self.lib_spec = lldb.SBFileSpec(self.lib_fullname)
+        
+    def test_break_in_dlopen_dylib_using_lldbutils(self):
+        self.common_setup()
+        lldbutil.run_to_source_breakpoint(self, "Break here in dylib", self.b_spec,
+                                          bkpt_module=self.lib_fullname,
+                                          extra_images = [self.lib_shortname],
+                                          has_locations_before_run = False)
+
+    @skipIfRemote
+    def test_break_in_dlopen_dylib_using_target(self):
+        self.common_setup()
+
+        target, process, _, _ = lldbutil.run_to_source_breakpoint(self, "Break here before we dlopen", self.main_spec,
+                                                            extra_images = [self.lib_shortname])
+        
+        # Now set some breakpoints that won't take till the library is loaded:
+        # This one is currently how lldbutils does it but test here in case that changes:
+        bkpt1 = target.BreakpointCreateBySourceRegex("Break here in dylib", self.b_spec, self.lib_fullname)
+        self.assertEqual(bkpt1.GetNumLocations(), 0, "Library isn't loaded yet.")
+        # Try the file list API as well.  Put in some bogus entries too, to make sure those
+        # don't trip us up:
+                                               
+        files_list = lldb.SBFileSpecList()
+        files_list.Append(self.b_spec)
+        files_list.Append(self.main_spec)
+        files_list.Append(lldb.SBFileSpec("I_bet_nobody_has_this_file.cpp"))
+
+        modules_list = lldb.SBFileSpecList()
+        modules_list.Append(self.lib_spec)
+        modules_list.Append(lldb.SBFileSpec("libI_bet_not_this_one_either.dylib"))
+
+        bkpt2 = target.BreakpointCreateBySourceRegex("Break here in dylib", modules_list, files_list)
+        self.assertEqual(bkpt2.GetNumLocations(), 0, "Library isn't loaded yet")
+
+        lldbutil.continue_to_breakpoint(process, bkpt1)
+        self.assertEqual(bkpt1.GetHitCount(), 1, "Hit breakpoint 1")
+        self.assertEqual(bkpt2.GetHitCount(), 1, "Hit breakpoint 2")
+
+        
+
+        
diff --git a/lldb/test/API/functionalities/breakpoint/break_in_loaded_dylib/b.cpp b/lldb/test/API/functionalities/breakpoint/break_in_loaded_dylib/b.cpp
new file mode 100644 (file)
index 0000000..5bfb310
--- /dev/null
@@ -0,0 +1,3 @@
+extern "C" int LLDB_DYLIB_EXPORT b_function() {
+  return 500; // Break here in dylib
+}
diff --git a/lldb/test/API/functionalities/breakpoint/break_in_loaded_dylib/main.cpp b/lldb/test/API/functionalities/breakpoint/break_in_loaded_dylib/main.cpp
new file mode 100644 (file)
index 0000000..3b00c6e
--- /dev/null
@@ -0,0 +1,15 @@
+#include "dylib.h"
+#include <cassert>
+#include <cstdio>
+#include <thread>
+#include <chrono>
+
+int main(int argc, char* argv[]) {
+  // Break here before we dlopen the 'liblib_b.so' shared library.
+  void* dylib_handle = dylib_open("lib_b"); 
+  assert(dylib_handle && "dlopen failed");
+  void (*func_handle)() = (void (*)()) dylib_get_symbol(dylib_handle, "b_function");
+  assert(func_handle && "dlsym failed");
+  func_handle();
+  return 0;
+}
index b5ff89a..35e19c8 100644 (file)
@@ -54,6 +54,17 @@ class PythonBreakpointCommandSettingTestCase(TestBase):
             "Set break point at this line.", self.main_source_spec)
         self.assertTrue(fancier_bkpt, VALID_BREAKPOINT)
 
+        # Also test the list version of this:
+        file_list = lldb.SBFileSpecList()
+        file_list.Append(self.main_source_spec)
+        module_list = lldb.SBFileSpecList()
+        module_list.Append(self.target.GetExecutable())
+        
+        list_bkpt = self.target.BreakpointCreateBySourceRegex(
+            "Set break point at this line.", module_list, file_list)
+        self.assertTrue(list_bkpt, VALID_BREAKPOINT)
+
+        
         not_so_fancy_bkpt = self.target.BreakpointCreateBySourceRegex(
             "Set break point at this line.", self.main_source_spec)
         self.assertTrue(not_so_fancy_bkpt, VALID_BREAKPOINT)
@@ -114,13 +125,21 @@ class PythonBreakpointCommandSettingTestCase(TestBase):
         error = not_so_fancy_bkpt.SetScriptCallbackFunction("bktptcmd.empty_extra_args", empty_args)
         self.assertTrue(error.Success(), "Failed to add callback %s"%(error.GetCString()))
 
+        # Do list breakpoint like fancy:
+        stream.Clear()
+        stream.Print('{"side_effect" : "I come from list input"}')
+        extra_args.SetFromJSON(stream)
+        error = list_bkpt.SetScriptCallbackFunction("bktptcmd.a_list_function", extra_args)
+        self.assertTrue(error.Success(), "Failed to add callback %s"%(error.GetCString()))
+        
         # Clear out canary variables
         side_effect.bktptcmd = None
         side_effect.callback = None
         side_effect.fancy    = None
         side_effect.fancier  = None
         side_effect.not_so_fancy = None
-
+        side_effect.a_list_function = None
+        
         # Now launch the process, and do not stop at entry point.
         self.process = self.target.LaunchSimple(
             None, None, self.get_process_working_directory())
@@ -133,11 +152,13 @@ class PythonBreakpointCommandSettingTestCase(TestBase):
         self.assertEquals(len(threads), 1, "Stopped at inner breakpoint.")
         self.thread = threads[0]
 
+        print("* Num Locations: {0} ; Hit Count {1}".format(list_bkpt.GetNumLocations(), list_bkpt.GetHitCount()))
         self.assertEquals("callback was here", side_effect.callback)
         self.assertEquals("function was here", side_effect.bktptcmd)
         self.assertEquals("I am fancy", side_effect.fancy)
         self.assertEquals("I am fancier", side_effect.fancier)
         self.assertEquals("Not so fancy", side_effect.not_so_fancy)
+        self.assertEquals("I come from list input", side_effect.from_list)
 
     def do_bad_args_to_python_command(self):
         error = lldb.SBError()
index e839de5..d635ae4 100644 (file)
@@ -17,6 +17,12 @@ def a_third_function(frame, bp_loc, extra_args, dict):
     se_string = se_value.GetStringValue(100)
     side_effect.fancier = se_string
 
+def a_list_function(frame, bp_loc, extra_args, dict):
+    se_value = extra_args.GetValueForKey("side_effect")
+    se_string = se_value.GetStringValue(100)
+    side_effect.from_list = se_string
+
+    
 def empty_extra_args(frame, bp_loc, extra_args, dict):
     if extra_args.IsValid():
         side_effect.not_so_fancy = "Extra args should not be valid"