| from intelpt_testcase import * | |
| from lldbsuite.test.lldbtest import * | |
| from lldbsuite.test.decorators import * | |
| class TestTraceDumpInstructions(TraceIntelPTTestCaseBase): | |
| def testErrorMessages(self): | |
| # We first check the output when there are no targets | |
| self.expect( | |
| "thread trace dump instructions", | |
| substrs=[ | |
| "error: invalid target, create a target using the 'target create' command" | |
| ], | |
| error=True, | |
| ) | |
| # We now check the output when there's a non-running target | |
| self.expect( | |
| "target create " | |
| + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out") | |
| ) | |
| self.expect( | |
| "thread trace dump instructions", | |
| substrs=["error: Command requires a current process."], | |
| error=True, | |
| ) | |
| # Now we check the output when there's a running target without a trace | |
| self.expect("b main") | |
| self.expect("run") | |
| self.expect( | |
| "thread trace dump instructions", | |
| substrs=["error: process is not being traced"], | |
| error=True, | |
| ) | |
| def testRawDumpInstructionsInJSON(self): | |
| self.expect( | |
| "trace load -v " | |
| + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"), | |
| substrs=["intel-pt"], | |
| ) | |
| self.expect( | |
| "thread trace dump instructions --raw --count 5 --forwards --json", | |
| substrs=[ | |
| """[{"id":3,"loadAddress":"0x400511"}""", | |
| """{"id":7,"loadAddress":"0x400518"}""", | |
| """{"id":8,"loadAddress":"0x40051f"}""", | |
| """{"id":9,"loadAddress":"0x400529"}""", | |
| """{"id":10,"loadAddress":"0x40052d"}""", | |
| ], | |
| ) | |
| self.expect( | |
| "thread trace dump instructions --raw --count 5 --forwards --pretty-json", | |
| substrs=[ | |
| """[ | |
| { | |
| "id": 3, | |
| "loadAddress": "0x400511" | |
| }, | |
| { | |
| "id": 7, | |
| "loadAddress": "0x400518" | |
| }, | |
| { | |
| "id": 8, | |
| "loadAddress": "0x40051f" | |
| }, | |
| { | |
| "id": 9, | |
| "loadAddress": "0x400529" | |
| }, | |
| { | |
| "id": 10, | |
| "loadAddress": "0x40052d" | |
| } | |
| ]""" | |
| ], | |
| ) | |
| def testRawDumpInstructionsInJSONToFile(self): | |
| self.expect( | |
| "trace load -v " | |
| + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"), | |
| substrs=["intel-pt"], | |
| ) | |
| outfile = os.path.join(self.getBuildDir(), "output.json") | |
| self.expect( | |
| "thread trace dump instructions --raw --count 5 --forwards --pretty-json --file " | |
| + outfile | |
| ) | |
| with open(outfile, "r") as out: | |
| self.assertEqual( | |
| out.read(), | |
| """[ | |
| { | |
| "id": 3, | |
| "loadAddress": "0x400511" | |
| }, | |
| { | |
| "id": 7, | |
| "loadAddress": "0x400518" | |
| }, | |
| { | |
| "id": 8, | |
| "loadAddress": "0x40051f" | |
| }, | |
| { | |
| "id": 9, | |
| "loadAddress": "0x400529" | |
| }, | |
| { | |
| "id": 10, | |
| "loadAddress": "0x40052d" | |
| } | |
| ]""", | |
| ) | |
| def testRawDumpInstructions(self): | |
| self.expect( | |
| "trace load -v " | |
| + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"), | |
| substrs=["intel-pt"], | |
| ) | |
| self.expect( | |
| "thread trace dump instructions --raw --count 21 --forwards", | |
| substrs=[ | |
| """thread #1: tid = 3842849 | |
| 3: 0x0000000000400511 | |
| 7: 0x0000000000400518 | |
| 8: 0x000000000040051f | |
| 9: 0x0000000000400529 | |
| 10: 0x000000000040052d | |
| 11: 0x0000000000400521 | |
| 12: 0x0000000000400525 | |
| 13: 0x0000000000400529 | |
| 14: 0x000000000040052d | |
| 15: 0x0000000000400521 | |
| 16: 0x0000000000400525 | |
| 17: 0x0000000000400529 | |
| 18: 0x000000000040052d | |
| 19: 0x0000000000400521 | |
| 20: 0x0000000000400525 | |
| 21: 0x0000000000400529 | |
| 22: 0x000000000040052d | |
| 23: 0x0000000000400521 | |
| 24: 0x0000000000400525 | |
| 25: 0x0000000000400529 | |
| 26: 0x000000000040052""" | |
| ], | |
| ) | |
| # We check if we can pass count and skip | |
| self.expect( | |
| "thread trace dump instructions --count 5 --skip 6 --raw --forwards", | |
| substrs=[ | |
| """thread #1: tid = 3842849 | |
| 7: 0x0000000000400518 | |
| 8: 0x000000000040051f | |
| 9: 0x0000000000400529 | |
| 10: 0x000000000040052d | |
| 11: 0x0000000000400521""" | |
| ], | |
| ) | |
| self.expect( | |
| "thread trace dump instructions --count 5 --skip 6 --raw", | |
| substrs=[ | |
| """thread #1: tid = 3842849 | |
| 21: 0x0000000000400529 | |
| 20: 0x0000000000400525 | |
| 19: 0x0000000000400521 | |
| 18: 0x000000000040052d | |
| 17: 0x0000000000400529""" | |
| ], | |
| ) | |
| # We check if we can pass count and skip and instruction id in hex | |
| self.expect( | |
| "thread trace dump instructions --count 5 --skip 6 --raw --id 0xE", | |
| substrs=[ | |
| """thread #1: tid = 3842849 | |
| 8: 0x000000000040051f | |
| 7: 0x0000000000400518 | |
| 3: 0x0000000000400511 | |
| no more data""" | |
| ], | |
| ) | |
| # We check if we can pass count and skip and instruction id in decimal | |
| self.expect( | |
| "thread trace dump instructions --count 5 --skip 6 --raw --id 14", | |
| substrs=[ | |
| """thread #1: tid = 3842849 | |
| 8: 0x000000000040051f | |
| 7: 0x0000000000400518 | |
| 3: 0x0000000000400511 | |
| no more data""" | |
| ], | |
| ) | |
| # We check if we can access the thread by index id | |
| self.expect( | |
| "thread trace dump instructions 1 --raw", | |
| substrs=[ | |
| """thread #1: tid = 3842849 | |
| 26: 0x000000000040052d""" | |
| ], | |
| ) | |
| # We check that we get an error when using an invalid thread index id | |
| self.expect( | |
| "thread trace dump instructions 10", | |
| error=True, | |
| substrs=['error: no thread with index: "10"'], | |
| ) | |
| def testDumpFullInstructionsWithMultipleThreads(self): | |
| # We load a trace with two threads | |
| self.expect( | |
| "trace load -v " | |
| + os.path.join(self.getSourceDir(), "intelpt-trace", "trace_2threads.json") | |
| ) | |
| # We print the instructions of a specific thread | |
| self.expect( | |
| "thread trace dump instructions 2 --count 2", | |
| substrs=[ | |
| """thread #2: tid = 3842850 | |
| a.out`main + 32 at main.cpp:4 | |
| 26: 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5 | |
| 25: 0x0000000000400529 cmpl $0x3, -0x8(%rbp)""" | |
| ], | |
| ) | |
| # We use custom --count and --skip, saving the command to history for later | |
| self.expect( | |
| "thread trace dump instructions 2 --count 2 --skip 2", | |
| inHistory=True, | |
| substrs=[ | |
| """thread #2: tid = 3842850 | |
| a.out`main + 28 at main.cpp:4 | |
| 25: 0x0000000000400529 cmpl $0x3, -0x8(%rbp) | |
| 24: 0x0000000000400525 addl $0x1, -0x8(%rbp)""" | |
| ], | |
| ) | |
| # We use a repeat command twice and ensure the previous count is used and the | |
| # start position moves with each command. | |
| self.expect( | |
| "", | |
| inHistory=True, | |
| substrs=[ | |
| """thread #2: tid = 3842850 | |
| a.out`main + 20 at main.cpp:5 | |
| 23: 0x0000000000400521 xorl $0x1, -0x4(%rbp) | |
| a.out`main + 32 at main.cpp:4 | |
| 22: 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5""" | |
| ], | |
| ) | |
| self.expect( | |
| "", | |
| inHistory=True, | |
| substrs=[ | |
| """thread #2: tid = 3842850 | |
| a.out`main + 28 at main.cpp:4 | |
| 21: 0x0000000000400529 cmpl $0x3, -0x8(%rbp) | |
| 20: 0x0000000000400525 addl $0x1, -0x8(%rbp""" | |
| ], | |
| ) | |
| def testInvalidBounds(self): | |
| self.expect( | |
| "trace load -v " | |
| + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json") | |
| ) | |
| # The output should be work when too many instructions are asked | |
| self.expect( | |
| "thread trace dump instructions --count 20 --forwards", | |
| substrs=[ | |
| """thread #1: tid = 3842849 | |
| a.out`main + 4 at main.cpp:2 | |
| 3: 0x0000000000400511 movl $0x0, -0x4(%rbp) | |
| a.out`main + 11 at main.cpp:4 | |
| 7: 0x0000000000400518 movl $0x0, -0x8(%rbp) | |
| 8: 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4""" | |
| ], | |
| ) | |
| # Should print no instructions if the position is out of bounds | |
| self.expect("thread trace dump instructions --skip 23", endstr="no more data\n") | |
| # Should fail with negative bounds | |
| self.expect("thread trace dump instructions --skip -1", error=True) | |
| self.expect("thread trace dump instructions --count -1", error=True) | |
| def testWrongImage(self): | |
| self.expect( | |
| "trace load " | |
| + os.path.join(self.getSourceDir(), "intelpt-trace", "trace_bad_image.json") | |
| ) | |
| self.expect( | |
| "thread trace dump instructions --forwards", | |
| substrs=[ | |
| """thread #1: tid = 3842849 | |
| ...missing instructions | |
| 3: (error) no memory mapped at this address: 0x0000000000400511""" | |
| ], | |
| ) | |
| def testWrongCPU(self): | |
| self.expect( | |
| "trace load " | |
| + os.path.join(self.getSourceDir(), "intelpt-trace", "trace_wrong_cpu.json") | |
| ) | |
| self.expect( | |
| "thread trace dump instructions --forwards", | |
| substrs=["error: unknown cpu"], | |
| error=True, | |
| ) | |
| def testMultiFileTraceWithMissingModuleInJSON(self): | |
| self.expect( | |
| "trace load " | |
| + os.path.join( | |
| self.getSourceDir(), "intelpt-trace-multi-file", "multi-file-no-ld.json" | |
| ) | |
| ) | |
| self.expect( | |
| "thread trace dump instructions --count 4 --id 9 --forwards --pretty-json", | |
| substrs=[ | |
| """[ | |
| { | |
| "id": 9, | |
| "loadAddress": "0x40054b", | |
| "module": "a.out", | |
| "symbol": "foo()", | |
| "mnemonic": "jmp" | |
| }, | |
| { | |
| "id": 10, | |
| "loadAddress": "0x400510", | |
| "module": "a.out", | |
| "symbol": null, | |
| "mnemonic": "pushq" | |
| }, | |
| { | |
| "id": 11, | |
| "loadAddress": "0x400516", | |
| "module": "a.out", | |
| "symbol": null, | |
| "mnemonic": "jmpq" | |
| }, | |
| { | |
| "id": 12, | |
| "error": "no memory mapped at this address: 0x00007ffff7df1950" | |
| }, | |
| { | |
| "id": 16, | |
| "loadAddress": "0x400674", | |
| "module": "a.out", | |
| "symbol": "main", | |
| "mnemonic": "movl", | |
| "source": "/home/wallace/llvm-sand/external/llvm-project/lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp", | |
| "line": 10, | |
| "column": 0 | |
| } | |
| ]""" | |
| ], | |
| ) | |
| self.expect( | |
| "thread trace dump instructions --count 4 --id 20 --forwards --pretty-json", | |
| substrs=[ | |
| """[ | |
| { | |
| "id": 20, | |
| "loadAddress": "0x400677", | |
| "module": "a.out", | |
| "symbol": "main", | |
| "mnemonic": "movl", | |
| "source": "/home/wallace/llvm-sand/external/llvm-project/lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp", | |
| "line": 12, | |
| "column": 0 | |
| }, | |
| { | |
| "id": 21, | |
| "loadAddress": "0x40067a", | |
| "module": "a.out", | |
| "symbol": "main", | |
| "mnemonic": "addl", | |
| "source": "/home/wallace/llvm-sand/external/llvm-project/lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp", | |
| "line": 12, | |
| "column": 0 | |
| }, | |
| { | |
| "id": 22, | |
| "loadAddress": "0x40067f", | |
| "module": "a.out", | |
| "symbol": "main", | |
| "mnemonic": "movl", | |
| "source": "/home/wallace/llvm-sand/external/llvm-project/lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp", | |
| "line": 12, | |
| "column": 0 | |
| }, | |
| { | |
| "id": 26, | |
| "loadAddress": "0x400682", | |
| "module": "a.out", | |
| "symbol": "inline_function()", | |
| "mnemonic": "movl", | |
| "source": "/home/wallace/llvm-sand/external/llvm-project/lldb/test/API/commands/trace/intelpt-trace-multi-file/main.cpp", | |
| "line": 4, | |
| "column": 0 | |
| } | |
| ]""" | |
| ], | |
| ) | |
| def testMultiFileTraceWithMissingModule(self): | |
| self.expect( | |
| "trace load " | |
| + os.path.join( | |
| self.getSourceDir(), "intelpt-trace-multi-file", "multi-file-no-ld.json" | |
| ) | |
| ) | |
| # This instructions in this test covers the following flow: | |
| # | |
| # - The trace starts with a call to libfoo, which triggers the dynamic | |
| # linker, but the dynamic linker is not included in the JSON file, | |
| # thus the trace reports a set of missing instructions after | |
| # instruction [6]. | |
| # - Then, the dump continues in the next synchronization point showing | |
| # a call to an inlined function, which is displayed as [inlined]. | |
| # - Finally, a call to libfoo is performed, which invokes libbar inside. | |
| # | |
| # Whenever there's a line or symbol change, including the inline case, a | |
| # line is printed showing the symbol context change. | |
| # | |
| # Finally, the instruction disassembly is included in the dump. | |
| self.expect( | |
| "thread trace dump instructions --count 50 --forwards", | |
| substrs=[ | |
| """thread #1: tid = 815455 | |
| a.out`main + 15 at main.cpp:10 | |
| 3: 0x000000000040066f callq 0x400540 ; symbol stub for: foo() | |
| a.out`symbol stub for: foo() | |
| 7: 0x0000000000400540 jmpq *0x200ae2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 40 | |
| 8: 0x0000000000400546 pushq $0x2 | |
| 9: 0x000000000040054b jmp 0x400510 | |
| a.out`(none) | |
| 10: 0x0000000000400510 pushq 0x200af2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 8 | |
| 11: 0x0000000000400516 jmpq *0x200af4(%rip) ; _GLOBAL_OFFSET_TABLE_ + 16 | |
| ...missing instructions | |
| 12: (error) no memory mapped at this address: 0x00007ffff7df1950 | |
| a.out`main + 20 at main.cpp:10 | |
| 16: 0x0000000000400674 movl %eax, -0xc(%rbp) | |
| a.out`main + 23 at main.cpp:12 | |
| 20: 0x0000000000400677 movl -0xc(%rbp), %eax | |
| 21: 0x000000000040067a addl $0x1, %eax | |
| 22: 0x000000000040067f movl %eax, -0xc(%rbp) | |
| a.out`main + 34 [inlined] inline_function() at main.cpp:4 | |
| 26: 0x0000000000400682 movl $0x0, -0x4(%rbp) | |
| a.out`main + 41 [inlined] inline_function() + 7 at main.cpp:5 | |
| 27: 0x0000000000400689 movl -0x4(%rbp), %eax | |
| 28: 0x000000000040068c addl $0x1, %eax | |
| 29: 0x0000000000400691 movl %eax, -0x4(%rbp) | |
| a.out`main + 52 [inlined] inline_function() + 18 at main.cpp:6 | |
| 30: 0x0000000000400694 movl -0x4(%rbp), %eax | |
| a.out`main + 55 at main.cpp:14 | |
| 31: 0x0000000000400697 movl -0xc(%rbp), %ecx | |
| 32: 0x000000000040069a addl %eax, %ecx | |
| 33: 0x000000000040069c movl %ecx, -0xc(%rbp) | |
| a.out`main + 63 at main.cpp:16 | |
| 37: 0x000000000040069f callq 0x400540 ; symbol stub for: foo() | |
| a.out`symbol stub for: foo() | |
| 38: 0x0000000000400540 jmpq *0x200ae2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 40 | |
| libfoo.so`foo() at foo.cpp:3 | |
| 39: 0x00007ffff7bd96e0 pushq %rbp | |
| 40: 0x00007ffff7bd96e1 movq %rsp, %rbp | |
| libfoo.so`foo() + 4 at foo.cpp:4 | |
| 41: 0x00007ffff7bd96e4 subq $0x10, %rsp | |
| 42: 0x00007ffff7bd96e8 callq 0x7ffff7bd95d0 ; symbol stub for: bar() | |
| libfoo.so`symbol stub for: bar() | |
| 43: 0x00007ffff7bd95d0 jmpq *0x200a4a(%rip) ; _GLOBAL_OFFSET_TABLE_ + 32 | |
| libbar.so`bar() at bar.cpp:1 | |
| 44: 0x00007ffff79d7690 pushq %rbp | |
| 45: 0x00007ffff79d7691 movq %rsp, %rbp | |
| libbar.so`bar() + 4 at bar.cpp:2 | |
| 46: 0x00007ffff79d7694 movl $0x1, -0x4(%rbp) | |
| libbar.so`bar() + 11 at bar.cpp:3 | |
| 47: 0x00007ffff79d769b movl -0x4(%rbp), %eax | |
| 48: 0x00007ffff79d769e addl $0x1, %eax | |
| 49: 0x00007ffff79d76a3 movl %eax, -0x4(%rbp) | |
| libbar.so`bar() + 22 at bar.cpp:4 | |
| 50: 0x00007ffff79d76a6 movl -0x4(%rbp), %eax | |
| 51: 0x00007ffff79d76a9 popq %rbp | |
| 52: 0x00007ffff79d76aa retq""", | |
| """libfoo.so`foo() + 13 at foo.cpp:4 | |
| 53: 0x00007ffff7bd96ed movl %eax, -0x4(%rbp) | |
| libfoo.so`foo() + 16 at foo.cpp:5 | |
| 54: 0x00007ffff7bd96f0 movl -0x4(%rbp), %eax | |
| 55: 0x00007ffff7bd96f3 addl $0x1, %eax | |
| 56: 0x00007ffff7bd96f8 movl %eax, -0x4(%rbp) | |
| libfoo.so`foo() + 27 at foo.cpp:6 | |
| 57: 0x00007ffff7bd96fb movl -0x4(%rbp), %eax | |
| 58: 0x00007ffff7bd96fe addq $0x10, %rsp | |
| 59: 0x00007ffff7bd9702 popq %rbp | |
| 60: 0x00007ffff7bd9703 retq""", | |
| """a.out`main + 68 at main.cpp:16 | |
| 61: 0x00000000004006a4 movl -0xc(%rbp), %ecx | |
| 62: 0x00000000004006a7 addl %eax, %ecx | |
| 63: 0x00000000004006a9 movl %ecx, -0xc(%rbp) | |
| no more data""", | |
| ], | |
| ) | |
| self.expect( | |
| "thread trace dump instructions --count 50", | |
| substrs=[ | |
| """thread #1: tid = 815455 | |
| a.out`main + 73 at main.cpp:16 | |
| 63: 0x00000000004006a9 movl %ecx, -0xc(%rbp) | |
| 62: 0x00000000004006a7 addl %eax, %ecx | |
| 61: 0x00000000004006a4 movl -0xc(%rbp), %ecx | |
| libfoo.so`foo() + 35 at foo.cpp:6 | |
| 60: 0x00007ffff7bd9703 retq""", | |
| """59: 0x00007ffff7bd9702 popq %rbp | |
| 58: 0x00007ffff7bd96fe addq $0x10, %rsp | |
| 57: 0x00007ffff7bd96fb movl -0x4(%rbp), %eax | |
| libfoo.so`foo() + 24 at foo.cpp:5 | |
| 56: 0x00007ffff7bd96f8 movl %eax, -0x4(%rbp) | |
| 55: 0x00007ffff7bd96f3 addl $0x1, %eax | |
| 54: 0x00007ffff7bd96f0 movl -0x4(%rbp), %eax | |
| libfoo.so`foo() + 13 at foo.cpp:4 | |
| 53: 0x00007ffff7bd96ed movl %eax, -0x4(%rbp) | |
| libbar.so`bar() + 26 at bar.cpp:4 | |
| 52: 0x00007ffff79d76aa retq""", | |
| """51: 0x00007ffff79d76a9 popq %rbp | |
| 50: 0x00007ffff79d76a6 movl -0x4(%rbp), %eax | |
| libbar.so`bar() + 19 at bar.cpp:3 | |
| 49: 0x00007ffff79d76a3 movl %eax, -0x4(%rbp) | |
| 48: 0x00007ffff79d769e addl $0x1, %eax | |
| 47: 0x00007ffff79d769b movl -0x4(%rbp), %eax | |
| libbar.so`bar() + 4 at bar.cpp:2 | |
| 46: 0x00007ffff79d7694 movl $0x1, -0x4(%rbp) | |
| libbar.so`bar() + 1 at bar.cpp:1 | |
| 45: 0x00007ffff79d7691 movq %rsp, %rbp | |
| 44: 0x00007ffff79d7690 pushq %rbp | |
| libfoo.so`symbol stub for: bar() | |
| 43: 0x00007ffff7bd95d0 jmpq *0x200a4a(%rip) ; _GLOBAL_OFFSET_TABLE_ + 32 | |
| libfoo.so`foo() + 8 at foo.cpp:4 | |
| 42: 0x00007ffff7bd96e8 callq 0x7ffff7bd95d0 ; symbol stub for: bar() | |
| 41: 0x00007ffff7bd96e4 subq $0x10, %rsp | |
| libfoo.so`foo() + 1 at foo.cpp:3 | |
| 40: 0x00007ffff7bd96e1 movq %rsp, %rbp | |
| 39: 0x00007ffff7bd96e0 pushq %rbp | |
| a.out`symbol stub for: foo() | |
| 38: 0x0000000000400540 jmpq *0x200ae2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 40 | |
| a.out`main + 63 at main.cpp:16 | |
| 37: 0x000000000040069f callq 0x400540 ; symbol stub for: foo() | |
| a.out`main + 60 at main.cpp:14 | |
| 33: 0x000000000040069c movl %ecx, -0xc(%rbp) | |
| 32: 0x000000000040069a addl %eax, %ecx | |
| 31: 0x0000000000400697 movl -0xc(%rbp), %ecx | |
| a.out`main + 52 [inlined] inline_function() + 18 at main.cpp:6 | |
| 30: 0x0000000000400694 movl -0x4(%rbp), %eax | |
| a.out`main + 49 [inlined] inline_function() + 15 at main.cpp:5 | |
| 29: 0x0000000000400691 movl %eax, -0x4(%rbp) | |
| 28: 0x000000000040068c addl $0x1, %eax | |
| 27: 0x0000000000400689 movl -0x4(%rbp), %eax | |
| a.out`main + 34 [inlined] inline_function() at main.cpp:4 | |
| 26: 0x0000000000400682 movl $0x0, -0x4(%rbp) | |
| a.out`main + 31 at main.cpp:12 | |
| 22: 0x000000000040067f movl %eax, -0xc(%rbp) | |
| 21: 0x000000000040067a addl $0x1, %eax | |
| 20: 0x0000000000400677 movl -0xc(%rbp), %eax | |
| a.out`main + 20 at main.cpp:10 | |
| 16: 0x0000000000400674 movl %eax, -0xc(%rbp) | |
| ...missing instructions | |
| 12: (error) no memory mapped at this address: 0x00007ffff7df1950 | |
| a.out`(none) | |
| 11: 0x0000000000400516 jmpq *0x200af4(%rip) ; _GLOBAL_OFFSET_TABLE_ + 16 | |
| 10: 0x0000000000400510 pushq 0x200af2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 8 | |
| a.out`symbol stub for: foo() + 11 | |
| 9: 0x000000000040054b jmp 0x400510 | |
| 8: 0x0000000000400546 pushq $0x2 | |
| 7: 0x0000000000400540 jmpq *0x200ae2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 40 | |
| a.out`main + 15 at main.cpp:10 | |
| 3: 0x000000000040066f callq 0x400540 ; symbol stub for: foo() | |
| no more data""", | |
| ], | |
| ) | |
| self.expect( | |
| "thread trace dump instructions --skip 100 --forwards", | |
| inHistory=True, | |
| substrs=[ | |
| """thread #1: tid = 815455 | |
| no more data""" | |
| ], | |
| ) | |
| self.expect( | |
| "", | |
| substrs=[ | |
| """thread #1: tid = 815455 | |
| no more data""" | |
| ], | |
| ) | |
| self.expect( | |
| "thread trace dump instructions --raw --all --forwards", | |
| substrs=[ | |
| """thread #1: tid = 815455 | |
| 3: 0x000000000040066f | |
| 7: 0x0000000000400540""", | |
| """11: 0x0000000000400516 | |
| ...missing instructions | |
| 12: (error) no memory mapped at this address: 0x00007ffff7df1950 | |
| 16: 0x0000000000400674""", | |
| """61: 0x00000000004006a4 | |
| 62: 0x00000000004006a7 | |
| 63: 0x00000000004006a9 | |
| no more data""", | |
| ], | |
| ) |