640 lines · python
1from intelpt_testcase import *2from lldbsuite.test.lldbtest import *3from lldbsuite.test.decorators import *4 5 6class TestTraceDumpInstructions(TraceIntelPTTestCaseBase):7 def testErrorMessages(self):8 # We first check the output when there are no targets9 self.expect(10 "thread trace dump instructions",11 substrs=[12 "error: invalid target, create a target using the 'target create' command"13 ],14 error=True,15 )16 17 # We now check the output when there's a non-running target18 self.expect(19 "target create "20 + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")21 )22 23 self.expect(24 "thread trace dump instructions",25 substrs=["error: Command requires a current process."],26 error=True,27 )28 29 # Now we check the output when there's a running target without a trace30 self.expect("b main")31 self.expect("run")32 33 self.expect(34 "thread trace dump instructions",35 substrs=["error: Process is not being traced"],36 error=True,37 )38 39 def testRawDumpInstructionsInJSON(self):40 self.expect(41 "trace load -v "42 + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"),43 substrs=["intel-pt"],44 )45 46 self.expect(47 "thread trace dump instructions --raw --count 5 --forwards --json",48 substrs=[49 """[{"id":3,"loadAddress":"0x400511"}""",50 """{"id":7,"loadAddress":"0x400518"}""",51 """{"id":8,"loadAddress":"0x40051f"}""",52 """{"id":9,"loadAddress":"0x400529"}""",53 """{"id":10,"loadAddress":"0x40052d"}""",54 ],55 )56 57 self.expect(58 "thread trace dump instructions --raw --count 5 --forwards --pretty-json",59 substrs=[60 """[61 {62 "id": 3,63 "loadAddress": "0x400511"64 },65 {66 "id": 7,67 "loadAddress": "0x400518"68 },69 {70 "id": 8,71 "loadAddress": "0x40051f"72 },73 {74 "id": 9,75 "loadAddress": "0x400529"76 },77 {78 "id": 10,79 "loadAddress": "0x40052d"80 }81]"""82 ],83 )84 85 def testRawDumpInstructionsInJSONToFile(self):86 self.expect(87 "trace load -v "88 + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"),89 substrs=["intel-pt"],90 )91 92 outfile = os.path.join(self.getBuildDir(), "output.json")93 94 self.expect(95 "thread trace dump instructions --raw --count 5 --forwards --pretty-json --file "96 + outfile97 )98 99 with open(outfile, "r") as out:100 self.assertEqual(101 out.read(),102 """[103 {104 "id": 3,105 "loadAddress": "0x400511"106 },107 {108 "id": 7,109 "loadAddress": "0x400518"110 },111 {112 "id": 8,113 "loadAddress": "0x40051f"114 },115 {116 "id": 9,117 "loadAddress": "0x400529"118 },119 {120 "id": 10,121 "loadAddress": "0x40052d"122 }123]""",124 )125 126 def testRawDumpInstructions(self):127 self.expect(128 "trace load -v "129 + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"),130 substrs=["intel-pt"],131 )132 133 self.expect(134 "thread trace dump instructions --raw --count 21 --forwards",135 substrs=[136 """thread #1: tid = 3842849137 3: 0x0000000000400511138 7: 0x0000000000400518139 8: 0x000000000040051f140 9: 0x0000000000400529141 10: 0x000000000040052d142 11: 0x0000000000400521143 12: 0x0000000000400525144 13: 0x0000000000400529145 14: 0x000000000040052d146 15: 0x0000000000400521147 16: 0x0000000000400525148 17: 0x0000000000400529149 18: 0x000000000040052d150 19: 0x0000000000400521151 20: 0x0000000000400525152 21: 0x0000000000400529153 22: 0x000000000040052d154 23: 0x0000000000400521155 24: 0x0000000000400525156 25: 0x0000000000400529157 26: 0x000000000040052"""158 ],159 )160 161 # We check if we can pass count and skip162 self.expect(163 "thread trace dump instructions --count 5 --skip 6 --raw --forwards",164 substrs=[165 """thread #1: tid = 3842849166 7: 0x0000000000400518167 8: 0x000000000040051f168 9: 0x0000000000400529169 10: 0x000000000040052d170 11: 0x0000000000400521"""171 ],172 )173 174 self.expect(175 "thread trace dump instructions --count 5 --skip 6 --raw",176 substrs=[177 """thread #1: tid = 3842849178 21: 0x0000000000400529179 20: 0x0000000000400525180 19: 0x0000000000400521181 18: 0x000000000040052d182 17: 0x0000000000400529"""183 ],184 )185 186 # We check if we can pass count and skip and instruction id in hex187 self.expect(188 "thread trace dump instructions --count 5 --skip 6 --raw --id 0xE",189 substrs=[190 """thread #1: tid = 3842849191 8: 0x000000000040051f192 7: 0x0000000000400518193 3: 0x0000000000400511194 no more data"""195 ],196 )197 198 # We check if we can pass count and skip and instruction id in decimal199 self.expect(200 "thread trace dump instructions --count 5 --skip 6 --raw --id 14",201 substrs=[202 """thread #1: tid = 3842849203 8: 0x000000000040051f204 7: 0x0000000000400518205 3: 0x0000000000400511206 no more data"""207 ],208 )209 210 # We check if we can access the thread by index id211 self.expect(212 "thread trace dump instructions 1 --raw",213 substrs=[214 """thread #1: tid = 3842849215 26: 0x000000000040052d"""216 ],217 )218 219 # We check that we get an error when using an invalid thread index id220 self.expect(221 "thread trace dump instructions 10",222 error=True,223 substrs=['error: no thread with index: "10"'],224 )225 226 def testDumpFullInstructionsWithMultipleThreads(self):227 # We load a trace with two threads228 self.expect(229 "trace load -v "230 + os.path.join(self.getSourceDir(), "intelpt-trace", "trace_2threads.json")231 )232 233 # We print the instructions of a specific thread234 self.expect(235 "thread trace dump instructions 2 --count 2",236 substrs=[237 """thread #2: tid = 3842850238 a.out`main + 32 at main.cpp:4239 26: 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5240 25: 0x0000000000400529 cmpl $0x3, -0x8(%rbp)"""241 ],242 )243 244 # We use custom --count and --skip, saving the command to history for later245 self.expect(246 "thread trace dump instructions 2 --count 2 --skip 2",247 inHistory=True,248 substrs=[249 """thread #2: tid = 3842850250 a.out`main + 28 at main.cpp:4251 25: 0x0000000000400529 cmpl $0x3, -0x8(%rbp)252 24: 0x0000000000400525 addl $0x1, -0x8(%rbp)"""253 ],254 )255 256 # We use a repeat command twice and ensure the previous count is used and the257 # start position moves with each command.258 self.expect(259 "",260 inHistory=True,261 substrs=[262 """thread #2: tid = 3842850263 a.out`main + 20 at main.cpp:5264 23: 0x0000000000400521 xorl $0x1, -0x4(%rbp)265 a.out`main + 32 at main.cpp:4266 22: 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5"""267 ],268 )269 270 self.expect(271 "",272 inHistory=True,273 substrs=[274 """thread #2: tid = 3842850275 a.out`main + 28 at main.cpp:4276 21: 0x0000000000400529 cmpl $0x3, -0x8(%rbp)277 20: 0x0000000000400525 addl $0x1, -0x8(%rbp"""278 ],279 )280 281 def testInvalidBounds(self):282 self.expect(283 "trace load -v "284 + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json")285 )286 287 # The output should be work when too many instructions are asked288 self.expect(289 "thread trace dump instructions --count 20 --forwards",290 substrs=[291 """thread #1: tid = 3842849292 a.out`main + 4 at main.cpp:2293 3: 0x0000000000400511 movl $0x0, -0x4(%rbp)294 a.out`main + 11 at main.cpp:4295 7: 0x0000000000400518 movl $0x0, -0x8(%rbp)296 8: 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4"""297 ],298 )299 300 # Should print no instructions if the position is out of bounds301 self.expect("thread trace dump instructions --skip 23", endstr="no more data\n")302 303 # Should fail with negative bounds304 self.expect("thread trace dump instructions --skip -1", error=True)305 self.expect("thread trace dump instructions --count -1", error=True)306 307 def testWrongImage(self):308 self.expect(309 "trace load "310 + os.path.join(self.getSourceDir(), "intelpt-trace", "trace_bad_image.json")311 )312 self.expect(313 "thread trace dump instructions --forwards",314 substrs=[315 """thread #1: tid = 3842849316 ...missing instructions317 3: (error) no memory mapped at this address: 0x0000000000400511"""318 ],319 )320 321 def testWrongCPU(self):322 self.expect(323 "trace load "324 + os.path.join(self.getSourceDir(), "intelpt-trace", "trace_wrong_cpu.json")325 )326 self.expect(327 "thread trace dump instructions --forwards",328 substrs=["error: unknown cpu"],329 error=True,330 )331 332 def testMultiFileTraceWithMissingModuleInJSON(self):333 self.expect(334 "trace load "335 + os.path.join(336 self.getSourceDir(), "intelpt-trace-multi-file", "multi-file-no-ld.json"337 )338 )339 340 self.expect(341 "thread trace dump instructions --count 4 --id 9 --forwards --pretty-json",342 substrs=[343 """[344 {345 "id": 9,346 "loadAddress": "0x40054b",347 "module": "a.out",348 "symbol": "foo()",349 "mnemonic": "jmp"350 },351 {352 "id": 10,353 "loadAddress": "0x400510",354 "module": "a.out",355 "symbol": null,356 "mnemonic": "pushq"357 },358 {359 "id": 11,360 "loadAddress": "0x400516",361 "module": "a.out",362 "symbol": null,363 "mnemonic": "jmpq"364 },365 {366 "id": 12,367 "error": "no memory mapped at this address: 0x00007ffff7df1950"368 },369 {370 "id": 16,371 "loadAddress": "0x400674",372 "module": "a.out",373 "symbol": "main",374 "mnemonic": "movl",375 "source": "/home/wallace/llvm-sand/external/llvm-project/lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp",376 "line": 10,377 "column": 0378 }379]"""380 ],381 )382 383 self.expect(384 "thread trace dump instructions --count 4 --id 20 --forwards --pretty-json",385 substrs=[386 """[387 {388 "id": 20,389 "loadAddress": "0x400677",390 "module": "a.out",391 "symbol": "main",392 "mnemonic": "movl",393 "source": "/home/wallace/llvm-sand/external/llvm-project/lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp",394 "line": 12,395 "column": 0396 },397 {398 "id": 21,399 "loadAddress": "0x40067a",400 "module": "a.out",401 "symbol": "main",402 "mnemonic": "addl",403 "source": "/home/wallace/llvm-sand/external/llvm-project/lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp",404 "line": 12,405 "column": 0406 },407 {408 "id": 22,409 "loadAddress": "0x40067f",410 "module": "a.out",411 "symbol": "main",412 "mnemonic": "movl",413 "source": "/home/wallace/llvm-sand/external/llvm-project/lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp",414 "line": 12,415 "column": 0416 },417 {418 "id": 26,419 "loadAddress": "0x400682",420 "module": "a.out",421 "symbol": "inline_function()",422 "mnemonic": "movl",423 "source": "/home/wallace/llvm-sand/external/llvm-project/lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp",424 "line": 4,425 "column": 0426 }427]"""428 ],429 )430 431 def testMultiFileTraceWithMissingModule(self):432 self.expect(433 "trace load "434 + os.path.join(435 self.getSourceDir(), "intelpt-trace-multi-file", "multi-file-no-ld.json"436 )437 )438 439 # This instructions in this test covers the following flow:440 #441 # - The trace starts with a call to libfoo, which triggers the dynamic442 # linker, but the dynamic linker is not included in the JSON file,443 # thus the trace reports a set of missing instructions after444 # instruction [6].445 # - Then, the dump continues in the next synchronization point showing446 # a call to an inlined function, which is displayed as [inlined].447 # - Finally, a call to libfoo is performed, which invokes libbar inside.448 #449 # Whenever there's a line or symbol change, including the inline case, a450 # line is printed showing the symbol context change.451 #452 # Finally, the instruction disassembly is included in the dump.453 self.expect(454 "thread trace dump instructions --count 50 --forwards",455 substrs=[456 """thread #1: tid = 815455457 a.out`main + 15 at main.cpp:10458 3: 0x000000000040066f callq 0x400540 ; symbol stub for: foo()459 a.out`symbol stub for: foo()460 7: 0x0000000000400540 jmpq *0x200ae2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 40461 8: 0x0000000000400546 pushq $0x2462 9: 0x000000000040054b jmp 0x400510463 a.out`(none)464 10: 0x0000000000400510 pushq 0x200af2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 8465 11: 0x0000000000400516 jmpq *0x200af4(%rip) ; _GLOBAL_OFFSET_TABLE_ + 16466 ...missing instructions467 12: (error) no memory mapped at this address: 0x00007ffff7df1950468 a.out`main + 20 at main.cpp:10469 16: 0x0000000000400674 movl %eax, -0xc(%rbp)470 a.out`main + 23 at main.cpp:12471 20: 0x0000000000400677 movl -0xc(%rbp), %eax472 21: 0x000000000040067a addl $0x1, %eax473 22: 0x000000000040067f movl %eax, -0xc(%rbp)474 a.out`main + 34 [inlined] inline_function() at main.cpp:4475 26: 0x0000000000400682 movl $0x0, -0x4(%rbp)476 a.out`main + 41 [inlined] inline_function() + 7 at main.cpp:5477 27: 0x0000000000400689 movl -0x4(%rbp), %eax478 28: 0x000000000040068c addl $0x1, %eax479 29: 0x0000000000400691 movl %eax, -0x4(%rbp)480 a.out`main + 52 [inlined] inline_function() + 18 at main.cpp:6481 30: 0x0000000000400694 movl -0x4(%rbp), %eax482 a.out`main + 55 at main.cpp:14483 31: 0x0000000000400697 movl -0xc(%rbp), %ecx484 32: 0x000000000040069a addl %eax, %ecx485 33: 0x000000000040069c movl %ecx, -0xc(%rbp)486 a.out`main + 63 at main.cpp:16487 37: 0x000000000040069f callq 0x400540 ; symbol stub for: foo()488 a.out`symbol stub for: foo()489 38: 0x0000000000400540 jmpq *0x200ae2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 40490 libfoo.so`foo() at foo.cpp:3491 39: 0x00007ffff7bd96e0 pushq %rbp492 40: 0x00007ffff7bd96e1 movq %rsp, %rbp493 libfoo.so`foo() + 4 at foo.cpp:4494 41: 0x00007ffff7bd96e4 subq $0x10, %rsp495 42: 0x00007ffff7bd96e8 callq 0x7ffff7bd95d0 ; symbol stub for: bar()496 libfoo.so`symbol stub for: bar()497 43: 0x00007ffff7bd95d0 jmpq *0x200a4a(%rip) ; _GLOBAL_OFFSET_TABLE_ + 32498 libbar.so`bar() at bar.cpp:1499 44: 0x00007ffff79d7690 pushq %rbp500 45: 0x00007ffff79d7691 movq %rsp, %rbp501 libbar.so`bar() + 4 at bar.cpp:2502 46: 0x00007ffff79d7694 movl $0x1, -0x4(%rbp)503 libbar.so`bar() + 11 at bar.cpp:3504 47: 0x00007ffff79d769b movl -0x4(%rbp), %eax505 48: 0x00007ffff79d769e addl $0x1, %eax506 49: 0x00007ffff79d76a3 movl %eax, -0x4(%rbp)507 libbar.so`bar() + 22 at bar.cpp:4508 50: 0x00007ffff79d76a6 movl -0x4(%rbp), %eax509 51: 0x00007ffff79d76a9 popq %rbp510 52: 0x00007ffff79d76aa retq""",511 """libfoo.so`foo() + 13 at foo.cpp:4512 53: 0x00007ffff7bd96ed movl %eax, -0x4(%rbp)513 libfoo.so`foo() + 16 at foo.cpp:5514 54: 0x00007ffff7bd96f0 movl -0x4(%rbp), %eax515 55: 0x00007ffff7bd96f3 addl $0x1, %eax516 56: 0x00007ffff7bd96f8 movl %eax, -0x4(%rbp)517 libfoo.so`foo() + 27 at foo.cpp:6518 57: 0x00007ffff7bd96fb movl -0x4(%rbp), %eax519 58: 0x00007ffff7bd96fe addq $0x10, %rsp520 59: 0x00007ffff7bd9702 popq %rbp521 60: 0x00007ffff7bd9703 retq""",522 """a.out`main + 68 at main.cpp:16523 61: 0x00000000004006a4 movl -0xc(%rbp), %ecx524 62: 0x00000000004006a7 addl %eax, %ecx525 63: 0x00000000004006a9 movl %ecx, -0xc(%rbp)526 no more data""",527 ],528 )529 530 self.expect(531 "thread trace dump instructions --count 50",532 substrs=[533 """thread #1: tid = 815455534 a.out`main + 73 at main.cpp:16535 63: 0x00000000004006a9 movl %ecx, -0xc(%rbp)536 62: 0x00000000004006a7 addl %eax, %ecx537 61: 0x00000000004006a4 movl -0xc(%rbp), %ecx538 libfoo.so`foo() + 35 at foo.cpp:6539 60: 0x00007ffff7bd9703 retq""",540 """59: 0x00007ffff7bd9702 popq %rbp541 58: 0x00007ffff7bd96fe addq $0x10, %rsp542 57: 0x00007ffff7bd96fb movl -0x4(%rbp), %eax543 libfoo.so`foo() + 24 at foo.cpp:5544 56: 0x00007ffff7bd96f8 movl %eax, -0x4(%rbp)545 55: 0x00007ffff7bd96f3 addl $0x1, %eax546 54: 0x00007ffff7bd96f0 movl -0x4(%rbp), %eax547 libfoo.so`foo() + 13 at foo.cpp:4548 53: 0x00007ffff7bd96ed movl %eax, -0x4(%rbp)549 libbar.so`bar() + 26 at bar.cpp:4550 52: 0x00007ffff79d76aa retq""",551 """51: 0x00007ffff79d76a9 popq %rbp552 50: 0x00007ffff79d76a6 movl -0x4(%rbp), %eax553 libbar.so`bar() + 19 at bar.cpp:3554 49: 0x00007ffff79d76a3 movl %eax, -0x4(%rbp)555 48: 0x00007ffff79d769e addl $0x1, %eax556 47: 0x00007ffff79d769b movl -0x4(%rbp), %eax557 libbar.so`bar() + 4 at bar.cpp:2558 46: 0x00007ffff79d7694 movl $0x1, -0x4(%rbp)559 libbar.so`bar() + 1 at bar.cpp:1560 45: 0x00007ffff79d7691 movq %rsp, %rbp561 44: 0x00007ffff79d7690 pushq %rbp562 libfoo.so`symbol stub for: bar()563 43: 0x00007ffff7bd95d0 jmpq *0x200a4a(%rip) ; _GLOBAL_OFFSET_TABLE_ + 32564 libfoo.so`foo() + 8 at foo.cpp:4565 42: 0x00007ffff7bd96e8 callq 0x7ffff7bd95d0 ; symbol stub for: bar()566 41: 0x00007ffff7bd96e4 subq $0x10, %rsp567 libfoo.so`foo() + 1 at foo.cpp:3568 40: 0x00007ffff7bd96e1 movq %rsp, %rbp569 39: 0x00007ffff7bd96e0 pushq %rbp570 a.out`symbol stub for: foo()571 38: 0x0000000000400540 jmpq *0x200ae2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 40572 a.out`main + 63 at main.cpp:16573 37: 0x000000000040069f callq 0x400540 ; symbol stub for: foo()574 a.out`main + 60 at main.cpp:14575 33: 0x000000000040069c movl %ecx, -0xc(%rbp)576 32: 0x000000000040069a addl %eax, %ecx577 31: 0x0000000000400697 movl -0xc(%rbp), %ecx578 a.out`main + 52 [inlined] inline_function() + 18 at main.cpp:6579 30: 0x0000000000400694 movl -0x4(%rbp), %eax580 a.out`main + 49 [inlined] inline_function() + 15 at main.cpp:5581 29: 0x0000000000400691 movl %eax, -0x4(%rbp)582 28: 0x000000000040068c addl $0x1, %eax583 27: 0x0000000000400689 movl -0x4(%rbp), %eax584 a.out`main + 34 [inlined] inline_function() at main.cpp:4585 26: 0x0000000000400682 movl $0x0, -0x4(%rbp)586 a.out`main + 31 at main.cpp:12587 22: 0x000000000040067f movl %eax, -0xc(%rbp)588 21: 0x000000000040067a addl $0x1, %eax589 20: 0x0000000000400677 movl -0xc(%rbp), %eax590 a.out`main + 20 at main.cpp:10591 16: 0x0000000000400674 movl %eax, -0xc(%rbp)592 ...missing instructions593 12: (error) no memory mapped at this address: 0x00007ffff7df1950594 a.out`(none)595 11: 0x0000000000400516 jmpq *0x200af4(%rip) ; _GLOBAL_OFFSET_TABLE_ + 16596 10: 0x0000000000400510 pushq 0x200af2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 8597 a.out`symbol stub for: foo() + 11598 9: 0x000000000040054b jmp 0x400510599 8: 0x0000000000400546 pushq $0x2600 7: 0x0000000000400540 jmpq *0x200ae2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 40601 a.out`main + 15 at main.cpp:10602 3: 0x000000000040066f callq 0x400540 ; symbol stub for: foo()603 no more data""",604 ],605 )606 607 self.expect(608 "thread trace dump instructions --skip 100 --forwards",609 inHistory=True,610 substrs=[611 """thread #1: tid = 815455612 no more data"""613 ],614 )615 616 self.expect(617 "",618 substrs=[619 """thread #1: tid = 815455620 no more data"""621 ],622 )623 624 self.expect(625 "thread trace dump instructions --raw --all --forwards",626 substrs=[627 """thread #1: tid = 815455628 3: 0x000000000040066f629 7: 0x0000000000400540""",630 """11: 0x0000000000400516631 ...missing instructions632 12: (error) no memory mapped at this address: 0x00007ffff7df1950633 16: 0x0000000000400674""",634 """61: 0x00000000004006a4635 62: 0x00000000004006a7636 63: 0x00000000004006a9637 no more data""",638 ],639 )640