1import lldb 2from intelpt_testcase import * 3from lldbsuite.test.lldbtest import * 4from lldbsuite.test import lldbutil 5from lldbsuite.test.decorators import * 6 7class TestTraceDumpInstructions(TraceIntelPTTestCaseBase): 8 9 mydir = TestBase.compute_mydir(__file__) 10 11 def testErrorMessages(self): 12 # We first check the output when there are no targets 13 self.expect("thread trace dump instructions", 14 substrs=["error: invalid target, create a target using the 'target create' command"], 15 error=True) 16 17 # We now check the output when there's a non-running target 18 self.expect("target create " + 19 os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")) 20 21 self.expect("thread trace dump instructions", 22 substrs=["error: invalid process"], 23 error=True) 24 25 # Now we check the output when there's a running target without a trace 26 self.expect("b main") 27 self.expect("run") 28 29 self.expect("thread trace dump instructions", 30 substrs=["error: Process is not being traced"], 31 error=True) 32 33 def testRawDumpInstructions(self): 34 self.expect("trace load -v " + 35 os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"), 36 substrs=["intel-pt"]) 37 38 self.expect("thread trace dump instructions --raw --count 21 --forwards", 39 substrs=['''thread #1: tid = 3842849 40 [ 0] 0x0000000000400511 41 [ 1] 0x0000000000400518 42 [ 2] 0x000000000040051f 43 [ 3] 0x0000000000400529 44 [ 4] 0x000000000040052d 45 [ 5] 0x0000000000400521 46 [ 6] 0x0000000000400525 47 [ 7] 0x0000000000400529 48 [ 8] 0x000000000040052d 49 [ 9] 0x0000000000400521 50 [10] 0x0000000000400525 51 [11] 0x0000000000400529 52 [12] 0x000000000040052d 53 [13] 0x0000000000400521 54 [14] 0x0000000000400525 55 [15] 0x0000000000400529 56 [16] 0x000000000040052d 57 [17] 0x0000000000400521 58 [18] 0x0000000000400525 59 [19] 0x0000000000400529 60 [20] 0x000000000040052d''']) 61 62 # We check if we can pass count and skip 63 self.expect("thread trace dump instructions --count 5 --skip 6 --raw --forwards", 64 substrs=['''thread #1: tid = 3842849 65 [ 6] 0x0000000000400525 66 [ 7] 0x0000000000400529 67 [ 8] 0x000000000040052d 68 [ 9] 0x0000000000400521 69 [10] 0x0000000000400525''']) 70 71 self.expect("thread trace dump instructions --count 5 --skip 6 --raw", 72 substrs=['''thread #1: tid = 3842849 73 [ -6] 0x0000000000400525 74 [ -7] 0x0000000000400521 75 [ -8] 0x000000000040052d 76 [ -9] 0x0000000000400529 77 [-10] 0x0000000000400525''']) 78 79 # We check if we can access the thread by index id 80 self.expect("thread trace dump instructions 1 --raw", 81 substrs=['''thread #1: tid = 3842849 82 [ 0] 0x000000000040052d''']) 83 84 # We check that we get an error when using an invalid thread index id 85 self.expect("thread trace dump instructions 10", error=True, 86 substrs=['error: no thread with index: "10"']) 87 88 def testDumpFullInstructionsWithMultipleThreads(self): 89 # We load a trace with two threads 90 self.expect("trace load -v " + 91 os.path.join(self.getSourceDir(), "intelpt-trace", "trace_2threads.json")) 92 93 # We print the instructions of two threads simultaneously 94 self.expect("thread trace dump instructions 1 2 --count 2", 95 substrs=['''thread #1: tid = 3842849 96 a.out`main + 32 at main.cpp:4 97 [ 0] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5 98 [-1] 0x0000000000400529 cmpl $0x3, -0x8(%rbp) 99thread #2: tid = 3842850 100 a.out`main + 32 at main.cpp:4 101 [ 0] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5 102 [-1] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)''']) 103 104 # We use custom --count and --skip, saving the command to history for later 105 self.expect("thread trace dump instructions 1 2 --count 2 --skip 2", inHistory=True, 106 substrs=['''thread #1: tid = 3842849 107 a.out`main + 24 at main.cpp:4 108 [-2] 0x0000000000400525 addl $0x1, -0x8(%rbp) 109 a.out`main + 20 at main.cpp:5 110 [-3] 0x0000000000400521 xorl $0x1, -0x4(%rbp) 111thread #2: tid = 3842850 112 a.out`main + 24 at main.cpp:4 113 [-2] 0x0000000000400525 addl $0x1, -0x8(%rbp) 114 a.out`main + 20 at main.cpp:5 115 [-3] 0x0000000000400521 xorl $0x1, -0x4(%rbp)''']) 116 117 # We use a repeat command twice and ensure the previous count is used and the 118 # start position moves with each command. 119 self.expect("", inHistory=True, 120 substrs=['''thread #1: tid = 3842849 121 a.out`main + 32 at main.cpp:4 122 [-4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5 123 [-5] 0x0000000000400529 cmpl $0x3, -0x8(%rbp) 124thread #2: tid = 3842850 125 a.out`main + 32 at main.cpp:4 126 [-4] 0x000000000040052d jle 0x400521 ; <+20> at main.cpp:5 127 [-5] 0x0000000000400529 cmpl $0x3, -0x8(%rbp)''']) 128 129 self.expect("", inHistory=True, 130 substrs=['''thread #1: tid = 3842849 131 a.out`main + 24 at main.cpp:4 132 [-6] 0x0000000000400525 addl $0x1, -0x8(%rbp) 133 a.out`main + 20 at main.cpp:5 134 [-7] 0x0000000000400521 xorl $0x1, -0x4(%rbp) 135thread #2: tid = 3842850 136 a.out`main + 24 at main.cpp:4 137 [-6] 0x0000000000400525 addl $0x1, -0x8(%rbp) 138 a.out`main + 20 at main.cpp:5 139 [-7] 0x0000000000400521 xorl $0x1, -0x4(%rbp)''']) 140 141 def testInvalidBounds(self): 142 self.expect("trace load -v " + 143 os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json")) 144 145 # The output should be work when too many instructions are asked 146 self.expect("thread trace dump instructions --count 20 --forwards", 147 substrs=['''thread #1: tid = 3842849 148 a.out`main + 4 at main.cpp:2 149 [ 0] 0x0000000000400511 movl $0x0, -0x4(%rbp) 150 a.out`main + 11 at main.cpp:4 151 [ 1] 0x0000000000400518 movl $0x0, -0x8(%rbp) 152 [ 2] 0x000000000040051f jmp 0x400529 ; <+28> at main.cpp:4''']) 153 154 # Should print no instructions if the position is out of bounds 155 self.expect("thread trace dump instructions --skip 23", 156 endstr='no more data\n') 157 158 # Should fail with negative bounds 159 self.expect("thread trace dump instructions --skip -1", error=True) 160 self.expect("thread trace dump instructions --count -1", error=True) 161 162 def testWrongImage(self): 163 self.expect("trace load " + 164 os.path.join(self.getSourceDir(), "intelpt-trace", "trace_bad_image.json")) 165 self.expect("thread trace dump instructions --forwards", 166 substrs=['''thread #1: tid = 3842849 167 [ 0] 0x0000000000400511 error: no memory mapped at this address 168 [ 1] 0x0000000000400518 error: no memory mapped at this address''']) 169 170 def testWrongCPU(self): 171 self.expect("trace load " + 172 os.path.join(self.getSourceDir(), "intelpt-trace", "trace_wrong_cpu.json")) 173 self.expect("thread trace dump instructions --forwards", 174 substrs=['''thread #1: tid = 3842849 175 [ 0] error: unknown cpu''']) 176 177 def testMultiFileTraceWithMissingModule(self): 178 self.expect("trace load " + 179 os.path.join(self.getSourceDir(), "intelpt-trace-multi-file", "multi-file-no-ld.json")) 180 181 # This instructions in this test covers the following flow: 182 # 183 # - The trace starts with a call to libfoo, which triggers the dynamic 184 # linker, but the dynamic linker is not included in the JSON file, 185 # thus the trace reports a set of missing instructions after 186 # instruction [6]. 187 # - Then, the dump continues in the next synchronization point showing 188 # a call to an inlined function, which is displayed as [inlined]. 189 # - Finally, a call to libfoo is performed, which invokes libbar inside. 190 # 191 # Whenever there's a line or symbol change, including the inline case, a 192 # line is printed showing the symbol context change. 193 # 194 # Finally, the instruction disassembly is included in the dump. 195 self.expect("thread trace dump instructions --count 50 --forwards", 196 substrs=['''thread #1: tid = 815455 197 a.out`main + 15 at main.cpp:10 198 [ 0] 0x000000000040066f callq 0x400540 ; symbol stub for: foo() 199 a.out`symbol stub for: foo() 200 [ 1] 0x0000000000400540 jmpq *0x200ae2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 40 201 [ 2] 0x0000000000400546 pushq $0x2 202 [ 3] 0x000000000040054b jmp 0x400510 203 a.out`(none) 204 [ 4] 0x0000000000400510 pushq 0x200af2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 8 205 [ 5] 0x0000000000400516 jmpq *0x200af4(%rip) ; _GLOBAL_OFFSET_TABLE_ + 16 206 [ 6] 0x00007ffff7df1950 error: no memory mapped at this address 207 ...missing instructions 208 a.out`main + 20 at main.cpp:10 209 [ 7] 0x0000000000400674 movl %eax, -0xc(%rbp) 210 a.out`main + 23 at main.cpp:12 211 [ 8] 0x0000000000400677 movl -0xc(%rbp), %eax 212 [ 9] 0x000000000040067a addl $0x1, %eax 213 [10] 0x000000000040067f movl %eax, -0xc(%rbp) 214 a.out`main + 34 [inlined] inline_function() at main.cpp:4 215 [11] 0x0000000000400682 movl $0x0, -0x4(%rbp) 216 a.out`main + 41 [inlined] inline_function() + 7 at main.cpp:5 217 [12] 0x0000000000400689 movl -0x4(%rbp), %eax 218 [13] 0x000000000040068c addl $0x1, %eax 219 [14] 0x0000000000400691 movl %eax, -0x4(%rbp) 220 a.out`main + 52 [inlined] inline_function() + 18 at main.cpp:6 221 [15] 0x0000000000400694 movl -0x4(%rbp), %eax 222 a.out`main + 55 at main.cpp:14 223 [16] 0x0000000000400697 movl -0xc(%rbp), %ecx 224 [17] 0x000000000040069a addl %eax, %ecx 225 [18] 0x000000000040069c movl %ecx, -0xc(%rbp) 226 a.out`main + 63 at main.cpp:16 227 [19] 0x000000000040069f callq 0x400540 ; symbol stub for: foo() 228 a.out`symbol stub for: foo() 229 [20] 0x0000000000400540 jmpq *0x200ae2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 40 230 libfoo.so`foo() at foo.cpp:3 231 [21] 0x00007ffff7bd96e0 pushq %rbp 232 [22] 0x00007ffff7bd96e1 movq %rsp, %rbp 233 libfoo.so`foo() + 4 at foo.cpp:4 234 [23] 0x00007ffff7bd96e4 subq $0x10, %rsp 235 [24] 0x00007ffff7bd96e8 callq 0x7ffff7bd95d0 ; symbol stub for: bar() 236 libfoo.so`symbol stub for: bar() 237 [25] 0x00007ffff7bd95d0 jmpq *0x200a4a(%rip) ; _GLOBAL_OFFSET_TABLE_ + 32 238 libbar.so`bar() at bar.cpp:1 239 [26] 0x00007ffff79d7690 pushq %rbp 240 [27] 0x00007ffff79d7691 movq %rsp, %rbp 241 libbar.so`bar() + 4 at bar.cpp:2 242 [28] 0x00007ffff79d7694 movl $0x1, -0x4(%rbp) 243 libbar.so`bar() + 11 at bar.cpp:3 244 [29] 0x00007ffff79d769b movl -0x4(%rbp), %eax 245 [30] 0x00007ffff79d769e addl $0x1, %eax 246 [31] 0x00007ffff79d76a3 movl %eax, -0x4(%rbp) 247 libbar.so`bar() + 22 at bar.cpp:4 248 [32] 0x00007ffff79d76a6 movl -0x4(%rbp), %eax 249 [33] 0x00007ffff79d76a9 popq %rbp 250 [34] 0x00007ffff79d76aa retq''', 251 '''libfoo.so`foo() + 13 at foo.cpp:4 252 [35] 0x00007ffff7bd96ed movl %eax, -0x4(%rbp) 253 libfoo.so`foo() + 16 at foo.cpp:5 254 [36] 0x00007ffff7bd96f0 movl -0x4(%rbp), %eax 255 [37] 0x00007ffff7bd96f3 addl $0x1, %eax 256 [38] 0x00007ffff7bd96f8 movl %eax, -0x4(%rbp) 257 libfoo.so`foo() + 27 at foo.cpp:6 258 [39] 0x00007ffff7bd96fb movl -0x4(%rbp), %eax 259 [40] 0x00007ffff7bd96fe addq $0x10, %rsp 260 [41] 0x00007ffff7bd9702 popq %rbp 261 [42] 0x00007ffff7bd9703 retq''', 262 '''a.out`main + 68 at main.cpp:16 263 [43] 0x00000000004006a4 movl -0xc(%rbp), %ecx 264 [44] 0x00000000004006a7 addl %eax, %ecx 265 [45] 0x00000000004006a9 movl %ecx, -0xc(%rbp)''']) 266 267 268 self.expect("thread trace dump instructions --count 50", 269 substrs=['''thread #1: tid = 815455 270 a.out`main + 73 at main.cpp:16 271 [ 0] 0x00000000004006a9 movl %ecx, -0xc(%rbp) 272 [ -1] 0x00000000004006a7 addl %eax, %ecx 273 [ -2] 0x00000000004006a4 movl -0xc(%rbp), %ecx 274 libfoo.so`foo() + 35 at foo.cpp:6 275 [ -3] 0x00007ffff7bd9703 retq''', 276 '''[ -4] 0x00007ffff7bd9702 popq %rbp 277 [ -5] 0x00007ffff7bd96fe addq $0x10, %rsp 278 [ -6] 0x00007ffff7bd96fb movl -0x4(%rbp), %eax 279 libfoo.so`foo() + 24 at foo.cpp:5 280 [ -7] 0x00007ffff7bd96f8 movl %eax, -0x4(%rbp) 281 [ -8] 0x00007ffff7bd96f3 addl $0x1, %eax 282 [ -9] 0x00007ffff7bd96f0 movl -0x4(%rbp), %eax 283 libfoo.so`foo() + 13 at foo.cpp:4 284 [-10] 0x00007ffff7bd96ed movl %eax, -0x4(%rbp) 285 libbar.so`bar() + 26 at bar.cpp:4 286 [-11] 0x00007ffff79d76aa retq''', 287 '''[-12] 0x00007ffff79d76a9 popq %rbp 288 [-13] 0x00007ffff79d76a6 movl -0x4(%rbp), %eax 289 libbar.so`bar() + 19 at bar.cpp:3 290 [-14] 0x00007ffff79d76a3 movl %eax, -0x4(%rbp) 291 [-15] 0x00007ffff79d769e addl $0x1, %eax 292 [-16] 0x00007ffff79d769b movl -0x4(%rbp), %eax 293 libbar.so`bar() + 4 at bar.cpp:2 294 [-17] 0x00007ffff79d7694 movl $0x1, -0x4(%rbp) 295 libbar.so`bar() + 1 at bar.cpp:1 296 [-18] 0x00007ffff79d7691 movq %rsp, %rbp 297 [-19] 0x00007ffff79d7690 pushq %rbp 298 libfoo.so`symbol stub for: bar() 299 [-20] 0x00007ffff7bd95d0 jmpq *0x200a4a(%rip) ; _GLOBAL_OFFSET_TABLE_ + 32 300 libfoo.so`foo() + 8 at foo.cpp:4 301 [-21] 0x00007ffff7bd96e8 callq 0x7ffff7bd95d0 ; symbol stub for: bar() 302 [-22] 0x00007ffff7bd96e4 subq $0x10, %rsp 303 libfoo.so`foo() + 1 at foo.cpp:3 304 [-23] 0x00007ffff7bd96e1 movq %rsp, %rbp 305 [-24] 0x00007ffff7bd96e0 pushq %rbp 306 a.out`symbol stub for: foo() 307 [-25] 0x0000000000400540 jmpq *0x200ae2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 40 308 a.out`main + 63 at main.cpp:16 309 [-26] 0x000000000040069f callq 0x400540 ; symbol stub for: foo() 310 a.out`main + 60 at main.cpp:14 311 [-27] 0x000000000040069c movl %ecx, -0xc(%rbp) 312 [-28] 0x000000000040069a addl %eax, %ecx 313 [-29] 0x0000000000400697 movl -0xc(%rbp), %ecx 314 a.out`main + 52 [inlined] inline_function() + 18 at main.cpp:6 315 [-30] 0x0000000000400694 movl -0x4(%rbp), %eax 316 a.out`main + 49 [inlined] inline_function() + 15 at main.cpp:5 317 [-31] 0x0000000000400691 movl %eax, -0x4(%rbp) 318 [-32] 0x000000000040068c addl $0x1, %eax 319 [-33] 0x0000000000400689 movl -0x4(%rbp), %eax 320 a.out`main + 34 [inlined] inline_function() at main.cpp:4 321 [-34] 0x0000000000400682 movl $0x0, -0x4(%rbp) 322 a.out`main + 31 at main.cpp:12 323 [-35] 0x000000000040067f movl %eax, -0xc(%rbp) 324 [-36] 0x000000000040067a addl $0x1, %eax 325 [-37] 0x0000000000400677 movl -0xc(%rbp), %eax 326 a.out`main + 20 at main.cpp:10 327 [-38] 0x0000000000400674 movl %eax, -0xc(%rbp) 328 ...missing instructions 329 [-39] 0x00007ffff7df1950 error: no memory mapped at this address 330 a.out`(none) 331 [-40] 0x0000000000400516 jmpq *0x200af4(%rip) ; _GLOBAL_OFFSET_TABLE_ + 16 332 [-41] 0x0000000000400510 pushq 0x200af2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 8 333 a.out`symbol stub for: foo() + 11 334 [-42] 0x000000000040054b jmp 0x400510 335 [-43] 0x0000000000400546 pushq $0x2 336 [-44] 0x0000000000400540 jmpq *0x200ae2(%rip) ; _GLOBAL_OFFSET_TABLE_ + 40 337 a.out`main + 15 at main.cpp:10 338 [-45] 0x000000000040066f callq 0x400540 ; symbol stub for: foo()''']) 339 340 self.expect("thread trace dump instructions --skip 100 --forwards", inHistory=True, 341 substrs=['''thread #1: tid = 815455 342 no more data''']) 343 344 self.expect("", substrs=['''thread #1: tid = 815455 345 no more data''']) 346