278 lines · python
1"""2Test lldb-dap stackTrace request3"""4 5import os6 7import lldbdap_testcase8from lldbsuite.test.decorators import *9from lldbsuite.test.lldbtest import *10 11 12class TestDAP_stackTrace(lldbdap_testcase.DAPTestCaseBase):13 name_key_path = ["name"]14 source_key_path = ["source", "path"]15 line_key_path = ["line"]16 17 # stackTrace additioanl frames for paginated traces18 page_size = 2019 20 def verify_stackFrames(self, start_idx, stackFrames):21 frame_idx = start_idx22 for stackFrame in stackFrames:23 # Don't care about frame above main24 if frame_idx > 40:25 return26 self.verify_stackFrame(frame_idx, stackFrame)27 frame_idx += 128 29 def verify_stackFrame(self, frame_idx, stackFrame):30 frame_name = self.get_dict_value(stackFrame, self.name_key_path)31 frame_source = self.get_dict_value(stackFrame, self.source_key_path)32 frame_line = self.get_dict_value(stackFrame, self.line_key_path)33 if frame_idx == 0:34 expected_line = self.recurse_end35 expected_name = "recurse"36 elif frame_idx < 40:37 expected_line = self.recurse_call38 expected_name = "recurse"39 else:40 expected_line = self.recurse_invocation41 expected_name = "main"42 self.assertEqual(43 frame_name,44 expected_name,45 'frame #%i name "%s" == "%s"' % (frame_idx, frame_name, expected_name),46 )47 self.assertEqual(48 frame_source,49 self.source_path,50 'frame #%i source "%s" == "%s"'51 % (frame_idx, frame_source, self.source_path),52 )53 self.assertEqual(54 frame_line,55 expected_line,56 "frame #%i line %i == %i" % (frame_idx, frame_line, expected_line),57 )58 59 def test_stackTrace(self):60 """61 Tests the 'stackTrace' packet and all its variants.62 """63 program = self.getBuildArtifact("a.out")64 self.build_and_launch(program)65 source = "main.c"66 self.source_path = os.path.join(os.getcwd(), source)67 self.recurse_end = line_number(source, "recurse end")68 self.recurse_call = line_number(source, "recurse call")69 self.recurse_invocation = line_number(source, "recurse invocation")70 71 lines = [self.recurse_end]72 73 # Set breakpoint at a point of deepest recuusion74 breakpoint_ids = self.set_source_breakpoints(source, lines)75 self.assertEqual(76 len(breakpoint_ids), len(lines), "expect correct number of breakpoints"77 )78 79 self.continue_to_breakpoints(breakpoint_ids)80 startFrame = 081 # Verify we get all stack frames with no arguments82 (stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount()83 frameCount = len(stackFrames)84 self.assertGreaterEqual(85 frameCount, 40, "verify we get at least 40 frames for all frames"86 )87 self.assertEqual(88 totalFrames,89 frameCount,90 "verify total frames returns a speculative page size",91 )92 self.verify_stackFrames(startFrame, stackFrames)93 94 # Verify totalFrames contains a speculative page size of additional frames with startFrame = 0 and levels = 095 (stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount(96 startFrame=0, levels=1097 )98 self.assertEqual(len(stackFrames), 10, "verify we get levels=10 frames")99 self.assertEqual(100 totalFrames,101 len(stackFrames) + self.page_size,102 "verify total frames returns a speculative page size",103 )104 self.verify_stackFrames(startFrame, stackFrames)105 106 # Verify all stack frames by specifying startFrame = 0 and levels not107 # specified108 stackFrames = self.get_stackFrames(startFrame=startFrame)109 self.assertEqual(110 frameCount,111 len(stackFrames),112 ("verify same number of frames with startFrame=%i") % (startFrame),113 )114 self.verify_stackFrames(startFrame, stackFrames)115 116 # Verify all stack frames by specifying startFrame = 0 and levels = 0117 levels = 0118 stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)119 self.assertEqual(120 frameCount,121 len(stackFrames),122 ("verify same number of frames with startFrame=%i and" " levels=%i")123 % (startFrame, levels),124 )125 self.verify_stackFrames(startFrame, stackFrames)126 127 # Get only the first stack frame by sepcifying startFrame = 0 and128 # levels = 1129 levels = 1130 stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)131 self.assertEqual(132 levels,133 len(stackFrames),134 ("verify one frame with startFrame=%i and" " levels=%i")135 % (startFrame, levels),136 )137 self.verify_stackFrames(startFrame, stackFrames)138 139 # Get only the first 3 stack frames by sepcifying startFrame = 0 and140 # levels = 3141 levels = 3142 stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)143 self.assertEqual(144 levels,145 len(stackFrames),146 ("verify %i frames with startFrame=%i and" " levels=%i")147 % (levels, startFrame, levels),148 )149 self.verify_stackFrames(startFrame, stackFrames)150 151 # Get only the first 15 stack frames by sepcifying startFrame = 5 and152 # levels = 16153 startFrame = 5154 levels = 16155 stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)156 self.assertEqual(157 levels,158 len(stackFrames),159 ("verify %i frames with startFrame=%i and" " levels=%i")160 % (levels, startFrame, levels),161 )162 self.verify_stackFrames(startFrame, stackFrames)163 164 # Verify we cap things correctly when we ask for too many frames165 startFrame = 5166 levels = 1000167 (stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount(168 startFrame=startFrame, levels=levels169 )170 self.assertEqual(171 len(stackFrames),172 frameCount - startFrame,173 ("verify less than 1000 frames with startFrame=%i and" " levels=%i")174 % (startFrame, levels),175 )176 self.assertEqual(177 totalFrames,178 frameCount,179 "verify we get correct value for totalFrames count "180 "when requested frames not from 0 index",181 )182 self.verify_stackFrames(startFrame, stackFrames)183 184 # Verify level=0 works with non-zerp start frame185 startFrame = 5186 levels = 0187 stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)188 self.assertEqual(189 len(stackFrames),190 frameCount - startFrame,191 ("verify less than 1000 frames with startFrame=%i and" " levels=%i")192 % (startFrame, levels),193 )194 self.verify_stackFrames(startFrame, stackFrames)195 196 # Verify we get not frames when startFrame is too high197 startFrame = 1000198 levels = 1199 stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)200 self.assertEqual(201 0, len(stackFrames), "verify zero frames with startFrame out of bounds"202 )203 204 @skipIfWindows205 def test_functionNameWithArgs(self):206 """207 Test that the stack frame without a function name is given its pc in the response.208 """209 program = self.getBuildArtifact("a.out")210 self.build_and_launch(program, customFrameFormat="${function.name-with-args}")211 source = "main.c"212 213 self.set_source_breakpoints(source, [line_number(source, "recurse end")])214 215 self.continue_to_next_stop()216 frame = self.get_stackFrames()[0]217 self.assertEqual(frame["name"], "recurse(x=1)")218 219 @skipIfWindows220 def test_StackFrameFormat(self):221 """222 Test the StackFrameFormat.223 """224 program = self.getBuildArtifact("a.out")225 self.build_and_launch(program)226 source = "main.c"227 228 self.set_source_breakpoints(source, [line_number(source, "recurse end")])229 230 self.continue_to_next_stop()231 frame = self.get_stackFrames(format={"parameters": True})[0]232 self.assertEqual(frame["name"], "recurse(x=1)")233 234 frame = self.get_stackFrames(format={"parameterNames": True})[0]235 self.assertEqual(frame["name"], "recurse(x=1)")236 237 frame = self.get_stackFrames(format={"parameterValues": True})[0]238 self.assertEqual(frame["name"], "recurse(x=1)")239 240 frame = self.get_stackFrames(format={"parameters": False, "line": True})[0]241 self.assertEqual(frame["name"], "main.c:5:5 recurse")242 243 frame = self.get_stackFrames(format={"parameters": False, "module": True})[0]244 self.assertEqual(frame["name"], "a.out recurse")245 246 @skipIfWindows247 def test_stack_frame_module_id(self):248 program = self.getBuildArtifact("a.out")249 self.build_and_launch(program)250 source = "main.c"251 lines = [line_number(source, "recurse end")]252 breakpoint_ids = self.set_source_breakpoints(source, lines)253 self.assertEqual(254 len(breakpoint_ids), len(lines), "expect correct number of breakpoints"255 )256 257 self.continue_to_breakpoints(breakpoint_ids)258 259 modules = self.dap_server.get_modules()260 name_to_id = {261 name: info["id"] for name, info in modules.items() if "id" in info262 }263 264 stack_frames = self.get_stackFrames()265 for frame in stack_frames:266 module_id = frame.get("moduleId")267 source_name = frame.get("source", {}).get("name")268 if module_id is None or source_name is None:269 continue270 271 if source_name in name_to_id:272 expected_id = name_to_id[source_name]273 self.assertEqual(274 module_id,275 expected_id,276 f"Expected moduleId '{expected_id}' for {source_name}, got: {module_id}",277 )278