278 lines · python
1"""2Make sure the frame variable -g, -a, and -l flags work.3"""4 5import lldb6import lldbsuite.test.lldbutil as lldbutil7from lldbsuite.test.decorators import *8from lldbsuite.test.lldbtest import *9import os10import shutil11import time12 13 14class TestFrameVar(TestBase):15 # If your test case doesn't stress debug info, then16 # set this to true. That way it won't be run once for17 # each debug info format.18 NO_DEBUG_INFO_TESTCASE = True19 20 def test_frame_var(self):21 self.build()22 self.do_test()23 24 def do_test(self):25 target = self.createTestTarget()26 27 # Now create a breakpoint in main.c at the source matching28 # "Set a breakpoint here"29 breakpoint = target.BreakpointCreateBySourceRegex(30 "Set a breakpoint here", lldb.SBFileSpec("main.c")31 )32 self.assertTrue(33 breakpoint and breakpoint.GetNumLocations() >= 1, VALID_BREAKPOINT34 )35 36 error = lldb.SBError()37 # This is the launch info. If you want to launch with arguments or38 # environment variables, add them using SetArguments or39 # SetEnvironmentEntries40 41 launch_info = target.GetLaunchInfo()42 process = target.Launch(launch_info, error)43 self.assertTrue(process, PROCESS_IS_VALID)44 45 # Did we hit our breakpoint?46 from lldbsuite.test.lldbutil import get_threads_stopped_at_breakpoint47 48 threads = get_threads_stopped_at_breakpoint(process, breakpoint)49 self.assertEqual(50 len(threads), 1, "There should be a thread stopped at our breakpoint"51 )52 53 # The hit count for the breakpoint should be 1.54 self.assertEqual(breakpoint.GetHitCount(), 1)55 56 frame = threads[0].GetFrameAtIndex(0)57 command_result = lldb.SBCommandReturnObject()58 interp = self.dbg.GetCommandInterpreter()59 60 # Ensure --regex can find globals if it is the very first frame var command.61 self.expect("frame var --regex g_", substrs=["g_var"])62 63 # Ensure the requested scope is respected:64 self.expect(65 "frame var --regex argc --no-args",66 error=True,67 substrs=["no variables matched the regular expression 'argc'"],68 )69 70 # Just get args:71 result = interp.HandleCommand("frame var -l", command_result)72 self.assertEqual(73 result, lldb.eReturnStatusSuccessFinishResult, "frame var -a didn't succeed"74 )75 output = command_result.GetOutput()76 self.assertIn("argc", output, "Args didn't find argc")77 self.assertIn("argv", output, "Args didn't find argv")78 self.assertNotIn("test_var", output, "Args found a local")79 self.assertNotIn("g_var", output, "Args found a global")80 81 value_list = command_result.GetValues(lldb.eNoDynamicValues)82 self.assertGreaterEqual(value_list.GetSize(), 2)83 value_names = []84 for value in value_list:85 value_names.append(value.GetName())86 self.assertIn("argc", value_names)87 self.assertIn("argv", value_names)88 89 # Just get locals:90 result = interp.HandleCommand("frame var -a", command_result)91 self.assertEqual(92 result, lldb.eReturnStatusSuccessFinishResult, "frame var -a didn't succeed"93 )94 output = command_result.GetOutput()95 self.assertNotIn("argc", output, "Locals found argc")96 self.assertNotIn("argv", output, "Locals found argv")97 self.assertIn("test_var", output, "Locals didn't find test_var")98 self.assertNotIn("g_var", output, "Locals found a global")99 100 # Get the file statics:101 result = interp.HandleCommand("frame var -l -a -g", command_result)102 self.assertEqual(103 result, lldb.eReturnStatusSuccessFinishResult, "frame var -a didn't succeed"104 )105 output = command_result.GetOutput()106 self.assertNotIn("argc", output, "Globals found argc")107 self.assertNotIn("argv", output, "Globals found argv")108 self.assertNotIn("test_var", output, "Globals found test_var")109 self.assertIn("g_var", output, "Globals didn't find g_var")110 111 def check_frame_variable_errors(self, thread, error_strings):112 command_result = lldb.SBCommandReturnObject()113 interp = self.dbg.GetCommandInterpreter()114 result = interp.HandleCommand("frame variable", command_result)115 self.assertEqual(116 result, lldb.eReturnStatusFailed, "frame var succeeded unexpectedly"117 )118 command_error = command_result.GetError()119 120 frame = thread.GetFrameAtIndex(0)121 var_list = frame.GetVariables(True, True, False, True)122 self.assertEqual(var_list.GetSize(), 0)123 api_error = var_list.GetError()124 api_error_str = api_error.GetCString()125 126 for s in error_strings:127 self.assertIn(s, command_error)128 for s in error_strings:129 self.assertIn(s, api_error_str)130 131 # Check the structured error data.132 data = api_error.GetErrorData()133 version = data.GetValueForKey("version")134 self.assertEqual(version.GetIntegerValue(), 1)135 err_ty = data.GetValueForKey("type")136 self.assertEqual(err_ty.GetIntegerValue(), lldb.eErrorTypeGeneric)137 message = str(data.GetValueForKey("errors").GetItemAtIndex(0))138 for s in error_strings:139 self.assertIn(s, message)140 141 @skipIfRemote142 @skipUnlessDarwin143 def test_darwin_dwarf_missing_obj(self):144 """145 Test that if we build a binary with DWARF in .o files and we remove146 the .o file for main.cpp, that we get an appropriate error when we147 do 'frame variable' that explains why we aren't seeing variables.148 """149 self.build(debug_info="dwarf")150 exe = self.getBuildArtifact("a.out")151 main_obj = self.getBuildArtifact("main.o")152 # Delete the main.o file that contains the debug info so we force an153 # error when we run to main and try to get variables154 os.unlink(main_obj)155 156 # We have to set a named breakpoint because we don't have any debug info157 # because we deleted the main.o file.158 (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, "main")159 error_strings = [160 'debug map object file "',161 'main.o" containing debug info does not exist, debug info will not be loaded',162 ]163 self.check_frame_variable_errors(thread, error_strings)164 165 @skipIfRemote166 @skipUnlessDarwin167 def test_darwin_dwarf_obj_mod_time_mismatch(self):168 """169 Test that if we build a binary with DWARF in .o files and we update170 the mod time of the .o file for main.cpp, that we get an appropriate171 error when we do 'frame variable' that explains why we aren't seeing172 variables.173 """174 self.build(debug_info="dwarf")175 exe = self.getBuildArtifact("a.out")176 main_obj = self.getBuildArtifact("main.o")177 178 # Set the modification time for main.o file to the current time after179 # sleeping for 2 seconds. This ensures the modification time will have180 # changed and will not match the modification time in the debug map and181 # force an error when we run to main and try to get variables182 time.sleep(2)183 os.utime(main_obj, None)184 185 # We have to set a named breakpoint because we don't have any debug info186 # because we deleted the main.o file since the mod times don't match187 # and debug info won't be loaded188 (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, "main")189 190 error_strings = [191 'debug map object file "',192 'main.o" changed (actual: 0x',193 ", debug map: 0x",194 ") since this executable was linked, debug info will not be loaded",195 ]196 self.check_frame_variable_errors(thread, error_strings)197 198 @skipIfRemote199 @skipIfWindows # Windows can't set breakpoints by name 'main' in this case.200 def test_gline_tables_only(self):201 """202 Test that if we build a binary with "-gline-tables-only" that we can203 set a file and line breakpoint successfully, and get an error204 letting us know that this build option was enabled when trying to205 read variables.206 """207 self.build(dictionary={"CFLAGS_EXTRAS": "-gline-tables-only"})208 exe = self.getBuildArtifact("a.out")209 210 # We have to set a named breakpoint because we don't have any debug info211 # because we deleted the main.o file since the mod times don't match212 # and debug info won't be loaded213 (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, "main")214 error_strings = [215 "no variable information is available in debug info for this compile unit"216 ]217 self.check_frame_variable_errors(thread, error_strings)218 219 @skipUnlessPlatform(["linux", "freebsd"])220 @add_test_categories(["dwo"])221 def test_fission_missing_dwo(self):222 """223 Test that if we build a binary with "-gsplit-dwarf" that we can224 set a file and line breakpoint successfully, and get an error225 letting us know we were unable to load the .dwo file.226 """227 self.build(dictionary={"CFLAGS_EXTRAS": "-gsplit-dwarf"})228 exe = self.getBuildArtifact("a.out")229 main_dwo = self.getBuildArtifact("main.dwo")230 231 self.assertTrue(232 os.path.exists(main_dwo), 'Make sure "%s" file exists' % (main_dwo)233 )234 # Delete the main.dwo file that contains the debug info so we force an235 # error when we run to main and try to get variables.236 os.unlink(main_dwo)237 238 # We have to set a named breakpoint because we don't have any debug info239 # because we deleted the main.o file since the mod times don't match240 # and debug info won't be loaded241 (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, "main")242 error_strings = [243 'unable to locate .dwo debug file "',244 'main.dwo" for skeleton DIE 0x',245 ]246 self.check_frame_variable_errors(thread, error_strings)247 248 @skipUnlessPlatform(["linux", "freebsd"])249 @add_test_categories(["dwo"])250 def test_fission_invalid_dwo_objectfile(self):251 """252 Test that if we build a binary with "-gsplit-dwarf" that we can253 set a file and line breakpoint successfully, and get an error254 letting us know we were unable to load the .dwo file because it255 existed, but it wasn't a valid object file.256 """257 self.build(dictionary={"CFLAGS_EXTRAS": "-gsplit-dwarf"})258 exe = self.getBuildArtifact("a.out")259 main_dwo = self.getBuildArtifact("main.dwo")260 261 self.assertTrue(262 os.path.exists(main_dwo), 'Make sure "%s" file exists' % (main_dwo)263 )264 # Overwrite the main.dwo with the main.c source file so that the .dwo265 # file exists, but it isn't a valid object file as there is an error266 # for this case.267 shutil.copyfile(self.getSourcePath("main.c"), main_dwo)268 269 # We have to set a named breakpoint because we don't have any debug info270 # because we deleted the main.o file since the mod times don't match271 # and debug info won't be loaded272 (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, "main")273 error_strings = [274 'unable to load object file for .dwo debug file "'275 'main.dwo" for unit DIE 0x',276 ]277 self.check_frame_variable_errors(thread, error_strings)278