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 call 43 self.expect( 44 "thread trace dump function-calls 1", 45 substrs=[ 46 """thread #1: tid = 3842849 47 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 tree 62 self.expect( 63 "thread trace dump function-calls 2", 64 substrs=[ 65 """thread #2: tid = 3497496 66 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 = 3497497 103 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 def testInlineFunctionCalls(self): 137 self.expect( 138 "file " + os.path.join(self.getSourceDir(), "inline-function", "a.out") 139 ) 140 self.expect("b main") # we'll trace from the beginning of main 141 self.expect("b 17") 142 self.expect("r") 143 self.expect("thread trace start") 144 self.expect("c") 145 self.expect( 146 "thread trace dump function-calls", 147 substrs=[ 148 """[call tree #0] 149a.out`main + 8 at inline.cpp:15:7 to 16:14 [2, 6] 150 a.out`foo(int) at inline.cpp:8:16 to 9:15 [7, 14] 151 a.out`foo(int) + 22 [inlined] mult(int, int) at inline.cpp:2:7 to 5:10 [15, 22] 152 a.out`foo(int) + 49 at inline.cpp:9:15 to 12:1 [23, 27] 153a.out`main + 25 at inline.cpp:16:14 to 16:14 [28, 28]""" 154 ], 155 ) 156 157 self.expect( 158 "thread trace dump function-calls -J", 159 substrs=[ 160 """[ 161 { 162 "tracedSegments": [ 163 { 164 "firstInstructionId": "2", 165 "lastInstructionId": "6", 166 "nestedCall": { 167 "tracedSegments": [ 168 { 169 "firstInstructionId": "7", 170 "lastInstructionId": "14", 171 "nestedCall": { 172 "tracedSegments": [ 173 { 174 "firstInstructionId": "15", 175 "lastInstructionId": "22" 176 } 177 ] 178 } 179 }, 180 { 181 "firstInstructionId": "23", 182 "lastInstructionId": "27" 183 } 184 ] 185 } 186 }, 187 { 188 "firstInstructionId": "28", 189 "lastInstructionId": "28" 190 } 191 ] 192 } 193]""" 194 ], 195 ) 196 197 def testIncompleteInlineFunctionCalls(self): 198 self.expect( 199 "file " + os.path.join(self.getSourceDir(), "inline-function", "a.out") 200 ) 201 self.expect("b 4") # we'll trace from the middle of the inline method 202 self.expect("b 17") 203 self.expect("r") 204 self.expect("thread trace start") 205 self.expect("c") 206 self.expect( 207 "thread trace dump function-calls", 208 substrs=[ 209 """[call tree #0] 210a.out`main 211 a.out`foo(int) 212 a.out`foo(int) + 36 [inlined] mult(int, int) + 14 at inline.cpp:4:5 to 5:10 [2, 6] 213 a.out`foo(int) + 49 at inline.cpp:9:15 to 12:1 [7, 11] 214a.out`main + 25 at inline.cpp:16:14 to 16:14 [12, 12]""" 215 ], 216 ) 217 218 self.expect( 219 "thread trace dump function-calls -J", 220 substrs=[ 221 """[ 222 { 223 "untracedPrefixSegment": { 224 "nestedCall": { 225 "untracedPrefixSegment": { 226 "nestedCall": { 227 "tracedSegments": [ 228 { 229 "firstInstructionId": "2", 230 "lastInstructionId": "6" 231 } 232 ] 233 } 234 }, 235 "tracedSegments": [ 236 { 237 "firstInstructionId": "7", 238 "lastInstructionId": "11" 239 } 240 ] 241 } 242 }, 243 "tracedSegments": [ 244 { 245 "firstInstructionId": "12", 246 "lastInstructionId": "12" 247 } 248 ] 249 } 250]""" 251 ], 252 ) 253 254 def testMultifileFunctionCalls(self): 255 # This test is extremely important because it first calls the method foo() which requires going through the dynamic linking. 256 # You'll see the entry "a.out`symbol stub for: foo()" which will invoke the ld linker, which will in turn find the actual foo 257 # function and eventually invoke it. However, we don't have the image of the linker in the trace bundle, so we'll see errors 258 # because the decoder couldn't find the linker binary! After those failures, the linker will resume right where we return to 259 # main after foo() finished. 260 # Then, we call foo() again, but because it has already been loaded by the linker, we don't invoke the linker anymore! And 261 # we'll see a nice tree without errors in this second invocation. Something interesting happens here. We still have an 262 # invocation to the symbol stub for foo(), but it modifies the stack so that when we return from foo() we don't stop again 263 # at the symbol stub, but instead we return directly to main. This is an example of returning several levels up in the 264 # call stack. 265 # Not only that, we also have an inline method in between. 266 self.expect( 267 "trace load " 268 + os.path.join( 269 self.getSourceDir(), "intelpt-trace-multi-file", "multi-file-no-ld.json" 270 ) 271 ) 272 self.expect( 273 "thread trace dump function-calls", 274 substrs=[ 275 """thread #1: tid = 815455 276 277[call tree #0] 278a.out`main + 15 at main.cpp:10 to 10:0 [3, 3] 279 a.out`symbol stub for: foo() to <+11> [7, 9] 280 a.out`a.out[0x0000000000400510] to a.out[0x0000000000400516] [10, 11] 281 282[call tree #1] 283<tracing errors> [12, 12] 284 285[call tree #2] 286a.out`main + 20 at main.cpp:10 to 12:0 [16, 22] 287 a.out`main + 34 [inlined] inline_function() at main.cpp:4 to 6:0 [26, 30] 288a.out`main + 55 at main.cpp:14 to 16:0 [31, 37] 289 a.out`symbol stub for: foo() to <+0> [38, 38] 290 libfoo.so`foo() at foo.cpp:3 to 4:0 [39, 42] 291 libfoo.so`symbol stub for: bar() to <+0> [43, 43] 292 libbar.so`bar() at bar.cpp:1 to 4:0 [44, 52] 293 libfoo.so`foo() + 13 at foo.cpp:4 to 6:0 [53, 60] 294a.out`main + 68 at main.cpp:16 to 16:0 [61, 63]""" 295 ], 296 ) 297 298 self.expect( 299 "thread trace dump function-calls -J", 300 substrs=[ 301 """[ 302 { 303 "tracedSegments": [ 304 { 305 "firstInstructionId": "3", 306 "lastInstructionId": "3", 307 "nestedCall": { 308 "tracedSegments": [ 309 { 310 "firstInstructionId": "7", 311 "lastInstructionId": "9", 312 "nestedCall": { 313 "tracedSegments": [ 314 { 315 "firstInstructionId": "10", 316 "lastInstructionId": "11" 317 } 318 ] 319 } 320 } 321 ] 322 } 323 } 324 ] 325 }, 326 { 327 "tracedSegments": [ 328 { 329 "firstInstructionId": "12", 330 "lastInstructionId": "12" 331 } 332 ] 333 }, 334 { 335 "tracedSegments": [ 336 { 337 "firstInstructionId": "16", 338 "lastInstructionId": "22", 339 "nestedCall": { 340 "tracedSegments": [ 341 { 342 "firstInstructionId": "26", 343 "lastInstructionId": "30" 344 } 345 ] 346 } 347 }, 348 { 349 "firstInstructionId": "31", 350 "lastInstructionId": "37", 351 "nestedCall": { 352 "tracedSegments": [ 353 { 354 "firstInstructionId": "38", 355 "lastInstructionId": "38", 356 "nestedCall": { 357 "tracedSegments": [ 358 { 359 "firstInstructionId": "39", 360 "lastInstructionId": "42", 361 "nestedCall": { 362 "tracedSegments": [ 363 { 364 "firstInstructionId": "43", 365 "lastInstructionId": "43", 366 "nestedCall": { 367 "tracedSegments": [ 368 { 369 "firstInstructionId": "44", 370 "lastInstructionId": "52" 371 } 372 ] 373 } 374 } 375 ] 376 } 377 }, 378 { 379 "firstInstructionId": "53", 380 "lastInstructionId": "60" 381 } 382 ] 383 } 384 } 385 ] 386 } 387 }, 388 { 389 "firstInstructionId": "61", 390 "lastInstructionId": "63" 391 } 392 ] 393 } 394]""" 395 ], 396 ) 397