Home | History | Annotate | Download | only in load_unload
      1 """
      2 Test that breakpoint by symbol name works correctly with dynamic libs.
      3 """
      4 
      5 import os, time
      6 import re
      7 import unittest2
      8 import lldb
      9 from lldbtest import *
     10 import lldbutil
     11 
     12 class LoadUnloadTestCase(TestBase):
     13 
     14     def getCategories (self):
     15         return ['basic_process']
     16 
     17     mydir = os.path.join("functionalities", "load_unload")
     18 
     19     def setUp(self):
     20         # Call super's setUp().
     21         TestBase.setUp(self)
     22         # Find the line number to break for main.cpp.
     23         self.line = line_number('main.c',
     24                                 '// Set break point at this line for test_lldb_process_load_and_unload_commands().')
     25         self.line_d_function = line_number('d.c',
     26                                            '// Find this line number within d_dunction().')
     27 
     28     @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
     29     @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
     30     def test_modules_search_paths(self):
     31         """Test target modules list after loading a different copy of the library libd.dylib, and verifies that it works with 'target modules search-paths add'."""
     32 
     33         # Invoke the default build rule.
     34         self.buildDefault()
     35 
     36         if sys.platform.startswith("darwin"):
     37             dylibName = 'libd.dylib'
     38 
     39         # The directory with the dynamic library we did not link to.
     40         new_dir = os.path.join(os.getcwd(), "hidden")
     41 
     42         old_dylib = os.path.join(os.getcwd(), dylibName)
     43         new_dylib = os.path.join(new_dir, dylibName)
     44 
     45         exe = os.path.join(os.getcwd(), "a.out")
     46         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
     47 
     48         self.expect("target modules list",
     49             substrs = [old_dylib])
     50         #self.expect("target modules list -t 3",
     51         #    patterns = ["%s-[^-]*-[^-]*" % self.getArchitecture()])
     52         # Add an image search path substitution pair.
     53         self.runCmd("target modules search-paths add %s %s" % (os.getcwd(), new_dir))
     54         # Add teardown hook to clear image-search-paths after the test.
     55         # rdar://problem/10501020
     56         # Uncomment the following to reproduce 10501020.
     57         self.addTearDownHook(lambda: self.runCmd("target modules search-paths clear"))
     58 
     59         self.expect("target modules search-paths list",
     60             substrs = [os.getcwd(), new_dir])
     61 
     62         self.expect("target modules search-paths query %s" % os.getcwd(), "Image search path successfully transformed",
     63             substrs = [new_dir])
     64 
     65         # Obliterate traces of libd from the old location.
     66         os.remove(old_dylib)
     67         # Inform dyld of the new path, too.
     68         env_cmd_string = "settings set target.env-vars " + self.dylibPath + "=" + new_dir
     69         if self.TraceOn():
     70             print "Set environment to: ", env_cmd_string
     71         self.runCmd(env_cmd_string)
     72         self.runCmd("settings show target.env-vars")
     73 
     74         remove_dyld_path_cmd = "settings remove target.env-vars " + self.dylibPath
     75         self.addTearDownHook(lambda: self.runCmd(remove_dyld_path_cmd))
     76 
     77         self.runCmd("run")
     78 
     79         self.expect("target modules list", "LLDB successfully locates the relocated dynamic library",
     80             substrs = [new_dylib])
     81 
     82     @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
     83     @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
     84     def test_dyld_library_path(self):
     85         """Test DYLD_LIBRARY_PATH after moving libd.dylib, which defines d_function, somewhere else."""
     86 
     87         # Invoke the default build rule.
     88         self.buildDefault()
     89 
     90         exe = os.path.join(os.getcwd(), "a.out")
     91         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
     92 
     93         if sys.platform.startswith("darwin"):
     94             dylibName = 'libd.dylib'
     95             dsymName = 'libd.dylib.dSYM'
     96 
     97         # The directory to relocate the dynamic library and its debugging info.
     98         special_dir = "hidden"
     99         new_dir = os.path.join(os.getcwd(), special_dir)
    100 
    101         old_dylib = os.path.join(os.getcwd(), dylibName)
    102         new_dylib = os.path.join(new_dir, dylibName)
    103         old_dSYM = os.path.join(os.getcwd(), dsymName)
    104         new_dSYM = os.path.join(new_dir, dsymName)
    105 
    106         #system(["ls", "-lR", "."])
    107 
    108         # Try running with the DYLD_LIBRARY_PATH environment variable set, make sure
    109         # we pick up the hidden dylib.
    110 
    111         env_cmd_string = "settings set target.env-vars " + self.dylibPath + "=" + new_dir
    112         if self.TraceOn():
    113             print "Set environment to: ", env_cmd_string
    114         self.runCmd(env_cmd_string)
    115         self.runCmd("settings show target.env-vars")
    116 
    117         remove_dyld_path_cmd = "settings remove target.env-vars " + self.dylibPath
    118         self.addTearDownHook(lambda: self.runCmd(remove_dyld_path_cmd))
    119 
    120         lldbutil.run_break_set_by_file_and_line (self, "d.c", self.line_d_function, num_expected_locations=1, loc_exact=True)
    121 
    122         # For now we don't track DYLD_LIBRARY_PATH, so the old library will be in
    123         # the modules list.
    124         self.expect("target modules list",
    125             substrs = [os.path.basename(old_dylib)],
    126             matching=True)
    127 
    128         self.runCmd("run")
    129         self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
    130             patterns = ["frame #0.*d_function.*at d.c:%d" % self.line_d_function])
    131 
    132         # After run, make sure the hidden library is present, and the one we didn't 
    133         # load is not.
    134         self.expect("target modules list",
    135             substrs = [special_dir, os.path.basename(new_dylib)])
    136 
    137     @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
    138     @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
    139     def test_lldb_process_load_and_unload_commands(self):
    140         """Test that lldb process load/unload command work correctly."""
    141 
    142         # Invoke the default build rule.
    143         self.buildDefault()
    144 
    145         exe = os.path.join(os.getcwd(), "a.out")
    146         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
    147 
    148         # Break at main.c before the call to dlopen().
    149         # Use lldb's process load command to load the dylib, instead.
    150 
    151         lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
    152 
    153         self.runCmd("run", RUN_SUCCEEDED)
    154 
    155         # Make sure that a_function does not exist at this point.
    156         self.expect("image lookup -n a_function", "a_function should not exist yet",
    157                     error=True, matching=False,
    158             patterns = ["1 match found .* %s" % self.mydir])
    159 
    160         # Use lldb 'process load' to load the dylib.
    161         self.expect("process load liba.dylib", "liba.dylib loaded correctly",
    162             patterns = ['Loading "liba.dylib".*ok',
    163                         'Image [0-9]+ loaded'])
    164 
    165         # Search for and match the "Image ([0-9]+) loaded" pattern.
    166         output = self.res.GetOutput()
    167         pattern = re.compile("Image ([0-9]+) loaded")
    168         for l in output.split(os.linesep):
    169             #print "l:", l
    170             match = pattern.search(l)
    171             if match:
    172                 break
    173         index = match.group(1)
    174 
    175         # Now we should have an entry for a_function.
    176         self.expect("image lookup -n a_function", "a_function should now exist",
    177             patterns = ["1 match found .*%s" % self.mydir])
    178 
    179         # Use lldb 'process unload' to unload the dylib.
    180         self.expect("process unload %s" % index, "liba.dylib unloaded correctly",
    181             patterns = ["Unloading .* with index %s.*ok" % index])
    182 
    183         self.runCmd("process continue")
    184 
    185     @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
    186     @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
    187     def test_load_unload(self):
    188         """Test breakpoint by name works correctly with dlopen'ing."""
    189 
    190         # Invoke the default build rule.
    191         self.buildDefault()
    192 
    193         exe = os.path.join(os.getcwd(), "a.out")
    194         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
    195 
    196         # Break by function name a_function (not yet loaded).
    197         lldbutil.run_break_set_by_symbol (self, "a_function", num_expected_locations=0)
    198 
    199         self.runCmd("run", RUN_SUCCEEDED)
    200 
    201         # The stop reason of the thread should be breakpoint and at a_function.
    202         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
    203             substrs = ['stopped',
    204                        'a_function',
    205                        'stop reason = breakpoint'])
    206 
    207         # The breakpoint should have a hit count of 1.
    208         self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
    209             substrs = [' resolved, hit count = 1'])
    210 
    211         # Issue the 'contnue' command.  We should stop agaian at a_function.
    212         # The stop reason of the thread should be breakpoint and at a_function.
    213         self.runCmd("continue")
    214 
    215         # rdar://problem/8508987
    216         # The a_function breakpoint should be encountered twice.
    217         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
    218             substrs = ['stopped',
    219                        'a_function',
    220                        'stop reason = breakpoint'])
    221 
    222         # The breakpoint should have a hit count of 2.
    223         self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
    224             substrs = [' resolved, hit count = 2'])
    225 
    226     @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
    227     @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
    228     def test_step_over_load (self):
    229         """Test stepping over code that loads a shared library works correctly."""
    230 
    231         # Invoke the default build rule.
    232         self.buildDefault()
    233 
    234         exe = os.path.join(os.getcwd(), "a.out")
    235         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
    236 
    237         # Break by function name a_function (not yet loaded).
    238         lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
    239 
    240         self.runCmd("run", RUN_SUCCEEDED)
    241 
    242         # The stop reason of the thread should be breakpoint and at a_function.
    243         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
    244             substrs = ['stopped',
    245                        'stop reason = breakpoint'])
    246 
    247         self.runCmd("thread step-over", "Stepping over function that loads library")
    248         
    249         # The stop reason should be step end.
    250         self.expect("thread list", "step over succeeded.", 
    251             substrs = ['stopped',
    252                       'stop reason = step over'])
    253 
    254 if __name__ == '__main__':
    255     import atexit
    256     lldb.SBDebugger.Initialize()
    257     atexit.register(lambda: lldb.SBDebugger.Terminate())
    258     unittest2.main()
    259