399 lines · python
1from intelpt_testcase import *2from lldbsuite.test.lldbtest import *3from lldbsuite.test.decorators import *4 5 6class TestTraceDumpInfo(TraceIntelPTTestCaseBase):7 def testDumpSimpleFunctionCalls(self):8 self.expect(9 "trace load -v "10 + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json")11 )12 13 self.expect(14 "thread trace dump function-calls 2",15 error=True,16 substrs=['error: no thread with index: "2"'],17 )18 19 self.expect(20 "thread trace dump function-calls 1 -j",21 substrs=[22 '[{"tracedSegments":[{"firstInstructionId":"3","lastInstructionId":"26"}]}]'23 ],24 )25 26 self.expect(27 "thread trace dump function-calls 1 -J",28 substrs=[29 """[30 {31 "tracedSegments": [32 {33 "firstInstructionId": "3",34 "lastInstructionId": "26"35 }36 ]37 }38]"""39 ],40 )41 42 # We test first some code without function call43 self.expect(44 "thread trace dump function-calls 1",45 substrs=[46 """thread #1: tid = 384284947 48[call tree #0]49a.out`main + 4 at main.cpp:2 to 4:0 [3, 26]"""50 ],51 )52 53 def testFunctionCallsWithErrors(self):54 self.expect(55 "trace load -v "56 + os.path.join(57 self.getSourceDir(), "intelpt-multi-core-trace", "trace.json"58 )59 )60 61 # We expect that tracing errors appear as a different tree62 self.expect(63 "thread trace dump function-calls 2",64 substrs=[65 """thread #2: tid = 349749666 67[call tree #0]68m.out`foo() + 65 at multi_thread.cpp:12:21 to 12:21 [4, 19524]69 70[call tree #1]71<tracing errors> [19526, 19526]"""72 ],73 )74 75 self.expect(76 "thread trace dump function-calls 2 -J",77 substrs=[78 """[79 {80 "tracedSegments": [81 {82 "firstInstructionId": "4",83 "lastInstructionId": "19524"84 }85 ]86 },87 {88 "tracedSegments": [89 {90 "firstInstructionId": "19526",91 "lastInstructionId": "19526"92 }93 ]94 }95]"""96 ],97 )98 99 self.expect(100 "thread trace dump function-calls 3",101 substrs=[102 """thread #3: tid = 3497497103 104[call tree #0]105m.out`bar() + 30 at multi_thread.cpp:19:3 to 20:6 [5, 61831]106 107[call tree #1]108<tracing errors> [61833, 61833]"""109 ],110 )111 112 self.expect(113 "thread trace dump function-calls 3 -J",114 substrs=[115 """[116 {117 "tracedSegments": [118 {119 "firstInstructionId": "5",120 "lastInstructionId": "61831"121 }122 ]123 },124 {125 "tracedSegments": [126 {127 "firstInstructionId": "61833",128 "lastInstructionId": "61833"129 }130 ]131 }132]"""133 ],134 )135 136 @skipIfNoIntelPT137 def testInlineFunctionCalls(self):138 self.expect(139 "file " + os.path.join(self.getSourceDir(), "inline-function", "a.out")140 )141 self.expect("b main") # we'll trace from the beginning of main142 self.expect("b 17")143 self.expect("r")144 self.expect("thread trace start")145 self.expect("c")146 self.expect(147 "thread trace dump function-calls",148 substrs=[149 """[call tree #0]150a.out`main + 8 at inline.cpp:15:7 to 16:14 [2, 6]151 a.out`foo(int) at inline.cpp:8:16 to 9:15 [7, 14]152 a.out`foo(int) + 22 [inlined] mult(int, int) at inline.cpp:2:7 to 5:10 [15, 22]153 a.out`foo(int) + 49 at inline.cpp:9:15 to 12:1 [23, 27]154a.out`main + 25 at inline.cpp:16:14 to 16:14 [28, 28]"""155 ],156 )157 158 self.expect(159 "thread trace dump function-calls -J",160 substrs=[161 """[162 {163 "tracedSegments": [164 {165 "firstInstructionId": "2",166 "lastInstructionId": "6",167 "nestedCall": {168 "tracedSegments": [169 {170 "firstInstructionId": "7",171 "lastInstructionId": "14",172 "nestedCall": {173 "tracedSegments": [174 {175 "firstInstructionId": "15",176 "lastInstructionId": "22"177 }178 ]179 }180 },181 {182 "firstInstructionId": "23",183 "lastInstructionId": "27"184 }185 ]186 }187 },188 {189 "firstInstructionId": "28",190 "lastInstructionId": "28"191 }192 ]193 }194]"""195 ],196 )197 198 @skipIfNoIntelPT199 def testIncompleteInlineFunctionCalls(self):200 self.expect(201 "file " + os.path.join(self.getSourceDir(), "inline-function", "a.out")202 )203 self.expect("b 4") # we'll trace from the middle of the inline method204 self.expect("b 17")205 self.expect("r")206 self.expect("thread trace start")207 self.expect("c")208 self.expect(209 "thread trace dump function-calls",210 substrs=[211 """[call tree #0]212a.out`main213 a.out`foo(int)214 a.out`foo(int) + 36 [inlined] mult(int, int) + 14 at inline.cpp:4:5 to 5:10 [2, 6]215 a.out`foo(int) + 49 at inline.cpp:9:15 to 12:1 [7, 11]216a.out`main + 25 at inline.cpp:16:14 to 16:14 [12, 12]"""217 ],218 )219 220 self.expect(221 "thread trace dump function-calls -J",222 substrs=[223 """[224 {225 "untracedPrefixSegment": {226 "nestedCall": {227 "untracedPrefixSegment": {228 "nestedCall": {229 "tracedSegments": [230 {231 "firstInstructionId": "2",232 "lastInstructionId": "6"233 }234 ]235 }236 },237 "tracedSegments": [238 {239 "firstInstructionId": "7",240 "lastInstructionId": "11"241 }242 ]243 }244 },245 "tracedSegments": [246 {247 "firstInstructionId": "12",248 "lastInstructionId": "12"249 }250 ]251 }252]"""253 ],254 )255 256 def testMultifileFunctionCalls(self):257 # This test is extremely important because it first calls the method foo() which requires going through the dynamic linking.258 # You'll see the entry "a.out`symbol stub for: foo()" which will invoke the ld linker, which will in turn find the actual foo259 # function and eventually invoke it. However, we don't have the image of the linker in the trace bundle, so we'll see errors260 # because the decoder couldn't find the linker binary! After those failures, the linker will resume right where we return to261 # main after foo() finished.262 # Then, we call foo() again, but because it has already been loaded by the linker, we don't invoke the linker anymore! And263 # we'll see a nice tree without errors in this second invocation. Something interesting happens here. We still have an264 # invocation to the symbol stub for foo(), but it modifies the stack so that when we return from foo() we don't stop again265 # at the symbol stub, but instead we return directly to main. This is an example of returning several levels up in the266 # call stack.267 # Not only that, we also have an inline method in between.268 self.expect(269 "trace load "270 + os.path.join(271 self.getSourceDir(), "intelpt-trace-multi-file", "multi-file-no-ld.json"272 )273 )274 self.expect(275 "thread trace dump function-calls",276 substrs=[277 """thread #1: tid = 815455278 279[call tree #0]280a.out`main + 15 at main.cpp:10 to 10:0 [3, 3]281 a.out`symbol stub for: foo() to <+11> [7, 9]282 a.out`a.out[0x0000000000400510] to a.out[0x0000000000400516] [10, 11]283 284[call tree #1]285<tracing errors> [12, 12]286 287[call tree #2]288a.out`main + 20 at main.cpp:10 to 12:0 [16, 22]289 a.out`main + 34 [inlined] inline_function() at main.cpp:4 to 6:0 [26, 30]290a.out`main + 55 at main.cpp:14 to 16:0 [31, 37]291 a.out`symbol stub for: foo() to <+0> [38, 38]292 libfoo.so`foo() at foo.cpp:3 to 4:0 [39, 42]293 libfoo.so`symbol stub for: bar() to <+0> [43, 43]294 libbar.so`bar() at bar.cpp:1 to 4:0 [44, 52]295 libfoo.so`foo() + 13 at foo.cpp:4 to 6:0 [53, 60]296a.out`main + 68 at main.cpp:16 to 16:0 [61, 63]"""297 ],298 )299 300 self.expect(301 "thread trace dump function-calls -J",302 substrs=[303 """[304 {305 "tracedSegments": [306 {307 "firstInstructionId": "3",308 "lastInstructionId": "3",309 "nestedCall": {310 "tracedSegments": [311 {312 "firstInstructionId": "7",313 "lastInstructionId": "9",314 "nestedCall": {315 "tracedSegments": [316 {317 "firstInstructionId": "10",318 "lastInstructionId": "11"319 }320 ]321 }322 }323 ]324 }325 }326 ]327 },328 {329 "tracedSegments": [330 {331 "firstInstructionId": "12",332 "lastInstructionId": "12"333 }334 ]335 },336 {337 "tracedSegments": [338 {339 "firstInstructionId": "16",340 "lastInstructionId": "22",341 "nestedCall": {342 "tracedSegments": [343 {344 "firstInstructionId": "26",345 "lastInstructionId": "30"346 }347 ]348 }349 },350 {351 "firstInstructionId": "31",352 "lastInstructionId": "37",353 "nestedCall": {354 "tracedSegments": [355 {356 "firstInstructionId": "38",357 "lastInstructionId": "38",358 "nestedCall": {359 "tracedSegments": [360 {361 "firstInstructionId": "39",362 "lastInstructionId": "42",363 "nestedCall": {364 "tracedSegments": [365 {366 "firstInstructionId": "43",367 "lastInstructionId": "43",368 "nestedCall": {369 "tracedSegments": [370 {371 "firstInstructionId": "44",372 "lastInstructionId": "52"373 }374 ]375 }376 }377 ]378 }379 },380 {381 "firstInstructionId": "53",382 "lastInstructionId": "60"383 }384 ]385 }386 }387 ]388 }389 },390 {391 "firstInstructionId": "61",392 "lastInstructionId": "63"393 }394 ]395 }396]"""397 ],398 )399