199451b44SJordan Rupprecht"""Test breaking inside functions defined within a BSD archive file libfoo.a.""" 299451b44SJordan Rupprecht 399451b44SJordan Rupprecht 499451b44SJordan Rupprechtimport lldb 599451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 699451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 799451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil 84763200eSGreg Claytonimport os 94763200eSGreg Claytonimport time 1099451b44SJordan Rupprecht 1199451b44SJordan Rupprecht 122238dcc3SJonas Devlieghereclass BSDArchivesTestCase(TestBase): 134763200eSGreg Clayton # If your test case doesn't stress debug info, then 144763200eSGreg Clayton # set this to true. That way it won't be run once for 154763200eSGreg Clayton # each debug info format. 164763200eSGreg Clayton NO_DEBUG_INFO_TESTCASE = True 174763200eSGreg Clayton 1899451b44SJordan Rupprecht def setUp(self): 1999451b44SJordan Rupprecht # Call super's setUp(). 2099451b44SJordan Rupprecht TestBase.setUp(self) 2199451b44SJordan Rupprecht # Find the line number in a(int) to break at. 222238dcc3SJonas Devlieghere self.line = line_number("a.c", "// Set file and line breakpoint inside a().") 2399451b44SJordan Rupprecht 2499451b44SJordan Rupprecht def test(self): 2599451b44SJordan Rupprecht """Break inside a() and b() defined within libfoo.a.""" 2699451b44SJordan Rupprecht self.build() 2799451b44SJordan Rupprecht 2899451b44SJordan Rupprecht exe = self.getBuildArtifact("a.out") 2999451b44SJordan Rupprecht self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 3099451b44SJordan Rupprecht 3199451b44SJordan Rupprecht # Break inside a() by file and line first. 3299451b44SJordan Rupprecht lldbutil.run_break_set_by_file_and_line( 332238dcc3SJonas Devlieghere self, "a.c", self.line, num_expected_locations=1, loc_exact=True 342238dcc3SJonas Devlieghere ) 3599451b44SJordan Rupprecht 3699451b44SJordan Rupprecht self.runCmd("run", RUN_SUCCEEDED) 3799451b44SJordan Rupprecht 3899451b44SJordan Rupprecht # The stop reason of the thread should be breakpoint. 392238dcc3SJonas Devlieghere self.expect( 402238dcc3SJonas Devlieghere "thread list", 412238dcc3SJonas Devlieghere STOPPED_DUE_TO_BREAKPOINT, 422238dcc3SJonas Devlieghere substrs=["stopped", "stop reason = breakpoint"], 432238dcc3SJonas Devlieghere ) 4499451b44SJordan Rupprecht 4599451b44SJordan Rupprecht # Break at a(int) first. 462238dcc3SJonas Devlieghere self.expect( 472238dcc3SJonas Devlieghere "frame variable", VARIABLES_DISPLAYED_CORRECTLY, substrs=["(int) arg = 1"] 482238dcc3SJonas Devlieghere ) 49d85cc03cSRaphael Isemann self.expect_var_path("__a_global", type="int", value="1") 5099451b44SJordan Rupprecht 5199451b44SJordan Rupprecht # Set breakpoint for b() next. 5299451b44SJordan Rupprecht lldbutil.run_break_set_by_symbol( 532238dcc3SJonas Devlieghere self, "b", num_expected_locations=1, sym_exact=True 542238dcc3SJonas Devlieghere ) 5599451b44SJordan Rupprecht 5699451b44SJordan Rupprecht # Continue the program, we should break at b(int) next. 5799451b44SJordan Rupprecht self.runCmd("continue") 582238dcc3SJonas Devlieghere self.expect( 592238dcc3SJonas Devlieghere "thread list", 602238dcc3SJonas Devlieghere STOPPED_DUE_TO_BREAKPOINT, 612238dcc3SJonas Devlieghere substrs=["stopped", "stop reason = breakpoint"], 622238dcc3SJonas Devlieghere ) 632238dcc3SJonas Devlieghere self.expect( 642238dcc3SJonas Devlieghere "frame variable", VARIABLES_DISPLAYED_CORRECTLY, substrs=["(int) arg = 2"] 652238dcc3SJonas Devlieghere ) 66d85cc03cSRaphael Isemann self.expect_var_path("__b_global", type="int", value="2") 67dc46ae6dSKaining Zhong 684763200eSGreg Clayton def check_frame_variable_errors(self, thread, error_strings): 694763200eSGreg Clayton command_result = lldb.SBCommandReturnObject() 704763200eSGreg Clayton interp = self.dbg.GetCommandInterpreter() 714763200eSGreg Clayton result = interp.HandleCommand("frame variable", command_result) 722238dcc3SJonas Devlieghere self.assertEqual( 732238dcc3SJonas Devlieghere result, lldb.eReturnStatusFailed, "frame var succeeded unexpectedly" 742238dcc3SJonas Devlieghere ) 754763200eSGreg Clayton command_error = command_result.GetError() 764763200eSGreg Clayton 774763200eSGreg Clayton frame = thread.GetFrameAtIndex(0) 784763200eSGreg Clayton var_list = frame.GetVariables(True, True, False, True) 794763200eSGreg Clayton self.assertEqual(var_list.GetSize(), 0) 804763200eSGreg Clayton api_error = var_list.GetError().GetCString() 814763200eSGreg Clayton 824763200eSGreg Clayton for s in error_strings: 83*9c246882SJordan Rupprecht self.assertIn( 84*9c246882SJordan Rupprecht s, 85*9c246882SJordan Rupprecht command_error, 862238dcc3SJonas Devlieghere 'Make sure "%s" exists in the command error "%s"' % (s, command_error), 872238dcc3SJonas Devlieghere ) 884763200eSGreg Clayton for s in error_strings: 89*9c246882SJordan Rupprecht self.assertIn( 90*9c246882SJordan Rupprecht s, 91*9c246882SJordan Rupprecht api_error, 922238dcc3SJonas Devlieghere 'Make sure "%s" exists in the API error "%s"' % (s, api_error), 932238dcc3SJonas Devlieghere ) 944763200eSGreg Clayton 954763200eSGreg Clayton @skipIfRemote 964763200eSGreg Clayton @skipUnlessDarwin 974763200eSGreg Clayton def test_frame_var_errors_when_archive_missing(self): 984763200eSGreg Clayton """ 994763200eSGreg Clayton Break inside a() and remove libfoo.a to make sure we can't load 1004763200eSGreg Clayton the debug information and report an appropriate error when doing 1014763200eSGreg Clayton 'frame variable'. 1024763200eSGreg Clayton """ 1034763200eSGreg Clayton self.build() 1044763200eSGreg Clayton exe = self.getBuildArtifact("a.out") 1054763200eSGreg Clayton libfoo_path = self.getBuildArtifact("libfoo.a") 1064763200eSGreg Clayton # Delete the main.o file that contains the debug info so we force an 1074763200eSGreg Clayton # error when we run to main and try to get variables for the a() 1084763200eSGreg Clayton # function. Since the libfoo.a is missing, the debug info won't be 1094763200eSGreg Clayton # loaded and we should see an error when trying to read varibles. 1104763200eSGreg Clayton os.unlink(libfoo_path) 1114763200eSGreg Clayton 1124763200eSGreg Clayton (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint( 1132238dcc3SJonas Devlieghere self, "a", bkpt_module=exe 1142238dcc3SJonas Devlieghere ) 1154763200eSGreg Clayton 1164763200eSGreg Clayton error_strings = [ 1174763200eSGreg Clayton 'debug map object file "', 1182238dcc3SJonas Devlieghere 'libfoo.a(a.o)" containing debug info does not exist, debug info will not be loaded', 1194763200eSGreg Clayton ] 1204763200eSGreg Clayton self.check_frame_variable_errors(thread, error_strings) 1214763200eSGreg Clayton 1224763200eSGreg Clayton @skipIfRemote 12315c8a762SAdrian Prantl @skipIf(compiler="clang", compiler_version=["<", "12.0"]) 124d4a141efSGreg Clayton def test_archive_specifications(self): 125d4a141efSGreg Clayton """ 126d4a141efSGreg Clayton Create archives and make sure the information we get when retrieving 127d4a141efSGreg Clayton the modules specifications is correct. 128d4a141efSGreg Clayton """ 129d4a141efSGreg Clayton self.build() 130d4a141efSGreg Clayton libbar_path = self.getBuildArtifact("libbar.a") 131d4a141efSGreg Clayton libfoo_path = self.getBuildArtifact("libfoo.a") 132d4a141efSGreg Clayton libfoothin_path = self.getBuildArtifact("libfoo-thin.a") 133d4a141efSGreg Clayton objfile_a = self.getBuildArtifact("a.o") 134d4a141efSGreg Clayton objfile_b = self.getBuildArtifact("b.o") 135d4a141efSGreg Clayton objfile_c = self.getBuildArtifact("c.o") 136d4a141efSGreg Clayton size_a = os.path.getsize(objfile_a) 137d4a141efSGreg Clayton size_b = os.path.getsize(objfile_b) 138d4a141efSGreg Clayton size_c = os.path.getsize(objfile_c) 139d4a141efSGreg Clayton 140d4a141efSGreg Clayton # Test loading normal archives 141d4a141efSGreg Clayton module_specs = lldb.SBModuleSpecList.GetModuleSpecifications(libfoo_path) 142d4a141efSGreg Clayton num_specs = module_specs.GetSize() 143d4a141efSGreg Clayton self.assertEqual(num_specs, 2) 144d4a141efSGreg Clayton spec = module_specs.GetSpecAtIndex(0) 145d4a141efSGreg Clayton self.assertEqual(spec.GetObjectName(), "a.o") 146d4a141efSGreg Clayton self.assertEqual(spec.GetObjectSize(), size_a) 147d4a141efSGreg Clayton spec = module_specs.GetSpecAtIndex(1) 148d4a141efSGreg Clayton self.assertEqual(spec.GetObjectName(), "b.o") 149d4a141efSGreg Clayton self.assertEqual(spec.GetObjectSize(), size_b) 150d4a141efSGreg Clayton 151d4a141efSGreg Clayton # Test loading thin archives 152d4a141efSGreg Clayton module_specs = lldb.SBModuleSpecList.GetModuleSpecifications(libbar_path) 153d4a141efSGreg Clayton num_specs = module_specs.GetSize() 154d4a141efSGreg Clayton self.assertEqual(num_specs, 1) 155d4a141efSGreg Clayton spec = module_specs.GetSpecAtIndex(0) 156d4a141efSGreg Clayton self.assertEqual(spec.GetObjectName(), "c.o") 157d4a141efSGreg Clayton self.assertEqual(spec.GetObjectSize(), size_c) 158d4a141efSGreg Clayton 159d4a141efSGreg Clayton module_specs = lldb.SBModuleSpecList.GetModuleSpecifications(libfoothin_path) 160d4a141efSGreg Clayton num_specs = module_specs.GetSize() 161d4a141efSGreg Clayton self.assertEqual(num_specs, 2) 162d4a141efSGreg Clayton spec = module_specs.GetSpecAtIndex(0) 163d4a141efSGreg Clayton self.assertEqual(spec.GetObjectName(), "a.o") 164d4a141efSGreg Clayton self.assertEqual(spec.GetObjectSize(), size_a) 165d4a141efSGreg Clayton spec = module_specs.GetSpecAtIndex(1) 166d4a141efSGreg Clayton self.assertEqual(spec.GetObjectName(), "b.o") 167d4a141efSGreg Clayton self.assertEqual(spec.GetObjectSize(), size_b, libfoothin_path) 168d4a141efSGreg Clayton 169d4a141efSGreg Clayton @skipIfRemote 1704763200eSGreg Clayton @skipUnlessDarwin 1714b9eed9cSWanyi Ye def test_frame_var_errors_when_thin_archive_malformed(self): 1724b9eed9cSWanyi Ye """ 1734b9eed9cSWanyi Ye Create thin archive libfoo.a and make it malformed to make sure 1744b9eed9cSWanyi Ye we don't crash and report an appropriate error when resolving 1754b9eed9cSWanyi Ye breakpoint using debug map. 1764b9eed9cSWanyi Ye """ 1774b9eed9cSWanyi Ye self.build() 1784b9eed9cSWanyi Ye exe = self.getBuildArtifact("a.out") 1794b9eed9cSWanyi Ye libfoo_path = self.getBuildArtifact("libfoo.a") 1804b9eed9cSWanyi Ye libthin_path = self.getBuildArtifact("libfoo-thin.a") 1814b9eed9cSWanyi Ye objfile_a = self.getBuildArtifact("a.o") 182d4a141efSGreg Clayton objfile_b = self.getBuildArtifact("b.o") 183d4a141efSGreg Clayton objfile_c = self.getBuildArtifact("c.o") 1844b9eed9cSWanyi Ye # Replace the libfoo.a file with a thin archive containing the same 1854b9eed9cSWanyi Ye # debug information (a.o, b.o). Then remove a.o from the file system 1864b9eed9cSWanyi Ye # so we force an error when we set a breakpoint on a() function. 1874b9eed9cSWanyi Ye # Since the a.o is missing, the debug info won't be loaded and we 1884b9eed9cSWanyi Ye # should see an error when trying to break into a(). 1894b9eed9cSWanyi Ye os.remove(libfoo_path) 1904b9eed9cSWanyi Ye shutil.copyfile(libthin_path, libfoo_path) 1914b9eed9cSWanyi Ye os.remove(objfile_a) 1924b9eed9cSWanyi Ye 1934b9eed9cSWanyi Ye self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 1944b9eed9cSWanyi Ye # We won't be able to see source file 1954b9eed9cSWanyi Ye self.expect( 1964b9eed9cSWanyi Ye "b a", 1974b9eed9cSWanyi Ye substrs=["Breakpoint 1: where = a.out`a, address ="], 1984b9eed9cSWanyi Ye ) 1994b9eed9cSWanyi Ye # Break at a() should fail 2004b9eed9cSWanyi Ye (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint( 2014b9eed9cSWanyi Ye self, "a", bkpt_module=exe 2024b9eed9cSWanyi Ye ) 2034b9eed9cSWanyi Ye error_strings = [ 2044b9eed9cSWanyi Ye '"a.o" object from the "', 2054b9eed9cSWanyi Ye "libfoo.a\" archive: either the .o file doesn't exist in the archive or the modification time (0x", 2064b9eed9cSWanyi Ye ") of the .o file doesn't match", 2074b9eed9cSWanyi Ye ] 2084b9eed9cSWanyi Ye self.check_frame_variable_errors(thread, error_strings) 209ca762819SWanyi Ye 210ca762819SWanyi Ye # Break at b() should succeed 211ca762819SWanyi Ye (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint( 212ca762819SWanyi Ye self, "b", bkpt_module=exe 213ca762819SWanyi Ye ) 214ca762819SWanyi Ye self.expect( 215ca762819SWanyi Ye "thread list", 216ca762819SWanyi Ye STOPPED_DUE_TO_BREAKPOINT, 217ca762819SWanyi Ye substrs=["stopped", "stop reason = breakpoint"], 218ca762819SWanyi Ye ) 219ca762819SWanyi Ye self.expect( 220ca762819SWanyi Ye "frame variable", VARIABLES_DISPLAYED_CORRECTLY, substrs=["(int) arg = 2"] 221ca762819SWanyi Ye ) 2224b9eed9cSWanyi Ye 2234b9eed9cSWanyi Ye @skipIfRemote 2244b9eed9cSWanyi Ye @skipUnlessDarwin 2254763200eSGreg Clayton def test_frame_var_errors_when_mtime_mistmatch_for_object_in_archive(self): 2264763200eSGreg Clayton """ 2274763200eSGreg Clayton Break inside a() and modify the modification time for "a.o" within 2284763200eSGreg Clayton libfoo.a to make sure we can't load the debug information and 2294763200eSGreg Clayton report an appropriate error when doing 'frame variable'. 2304763200eSGreg Clayton """ 2314763200eSGreg Clayton self.build() 2324763200eSGreg Clayton exe = self.getBuildArtifact("a.out") 2334763200eSGreg Clayton a_path = self.getBuildArtifact("a.o") 2344763200eSGreg Clayton 2354763200eSGreg Clayton # Change the modification time of the a.o object file after sleeping for 2364763200eSGreg Clayton # 2 seconds to ensure the modification time is different. The rebuild 2374763200eSGreg Clayton # only the "libfoo.a" target. This means the modification time of the 2384763200eSGreg Clayton # a.o within libfoo.a will not match the debug map's modification time 2394763200eSGreg Clayton # in a.out and will cause the debug information to not be loaded and we 2404763200eSGreg Clayton # should get an appropriate error when reading variables. 2414763200eSGreg Clayton time.sleep(2) 2424763200eSGreg Clayton os.utime(a_path, None) 2434763200eSGreg Clayton self.build(make_targets=["libfoo.a"]) 2444763200eSGreg Clayton 2454763200eSGreg Clayton (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint( 2462238dcc3SJonas Devlieghere self, "a", bkpt_module=exe 2472238dcc3SJonas Devlieghere ) 2484763200eSGreg Clayton 2494763200eSGreg Clayton error_strings = [ 2504763200eSGreg Clayton '"a.o" object from the "', 2512238dcc3SJonas Devlieghere "libfoo.a\" archive: either the .o file doesn't exist in the archive or the modification time (0x", 2522238dcc3SJonas Devlieghere ") of the .o file doesn't match", 2534763200eSGreg Clayton ] 2544763200eSGreg Clayton self.check_frame_variable_errors(thread, error_strings) 255