Advertisement
Guest User

Untitled

a guest
Mar 17th, 2022
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 4.99 KB | None | 0 0
  1. ive process tracing
  2.  
  3. When you are debugging a process, you can turn on intel-pt tracing, which will “record” all the instructions that the process will execute. After turning it on, you can continue debugging, and at any breakpoint, you can inspect the instruction list.
  4.  
  5. For example:
  6.  
  7. lldb <target>
  8. > b main
  9. > run
  10. > process trace start # start tracing on all threads, including future ones
  11. # keep debugging until you hit a breakpoint
  12. > thread trace dump instructions
  13. # this should output something like
  14.  
  15. thread #2: tid = 2861133, total instructions = 5305673
  16.   libc.so.6`__GI___libc_read + 45 at read.c:25:1
  17.     [4962255] 0x00007fffeb64c63d    subq   $0x10, %rsp
  18.     [4962256] 0x00007fffeb64c641    movq   %rdi, -0x18(%rbp)
  19.   libc.so.6`__GI___libc_read + 53 [inlined] __libc_read at read.c:26:10
  20.     [4962257] 0x00007fffeb64c645    callq  0x7fffeb66b640            ; __libc_enable_asynccancel
  21.   libc.so.6`__libc_enable_asynccancel
  22.     [4962258] 0x00007fffeb66b640    movl   %fs:0x308, %eax
  23.   libc.so.6`__libc_enable_asynccancel + 8
  24.     [4962259] 0x00007fffeb66b648    movl   %eax, %r11d
  25.    
  26. # you can keep pressing ENTER to see more and more instructions
  27.  
  28. The number between brackets is the instruction index, and by default the current thread will be picked.
  29.  
  30. Configuring the trace size
  31.  
  32. The CPU stores the instruction list in a compressed format in a ring buffer, which keeps the latest information. By default, LLDB uses a buffer of 4KB per thread, but you can change it by running. The size must be a power of 2 and at least 4KB.
  33.  
  34.  thread trace start all -s <size_in_bytes>
  35.  
  36. For reference, a 1MB trace buffer can easily store around 5M instructions.
  37.  
  38. Printing more instructions
  39.  
  40. If you want to dump more instructions at a time, you can run
  41.  
  42. thread trace dump instructions -c <count>
  43.  
  44. Printing the instructions of another thread
  45.  
  46. By default the current thread will be picked when dumping instructions, but you can do
  47.  
  48. thread trace dump instructions <#thread index>
  49. #e.g.
  50. thread trace dump instructions 8
  51.  
  52. to select another thread.
  53.  
  54. Crash Analysis
  55.  
  56. What if you are debugging + tracing a process that crashes? Then you can just do
  57.  
  58. thread trace dump instructions
  59.  
  60. To inspect how it crashed! There’s nothing special that you need to do. For example
  61.  
  62. * thread #1, name = 'a.out', stop reason = signal SIGFPE: integer divide by zero
  63.     frame #0: 0x00000000004009f1 a.out`main at main.cpp:8:14
  64.    6       int x;
  65.    7       cin >> x;
  66. -> 8       cout << 12 / x << endl;
  67.    9       return 0;
  68.    10  }
  69. (lldb) thread trace dump instructions -c 5
  70. thread #1: tid = 604302, total instructions = 8388
  71.   libstdc++.so.6`std::istream::operator>>(int&) + 181
  72.     [8383] 0x00007ffff7b41665    popq   %rbp
  73.     [8384] 0x00007ffff7b41666    retq
  74.   a.out`main + 66 at main.cpp:8:14
  75.     [8385] 0x00000000004009e8    movl   -0x4(%rbp), %ecx
  76.     [8386] 0x00000000004009eb    movl   $0xc, %eax
  77.     [8387] 0x00000000004009f0    cltd
  78.  
  79. Note: at this moment, we are not including the failed instruction in the trace, but in the future we might do it for readability.
  80.  
  81.  
  82. Offline Trace Analysis
  83.  
  84. It’s also possible to record a trace using a custom Intel PT collector and decode + symbolicate the trace using LLDB. For that, the command trace load is useful.
  85.  
  86. In order to use trace load, you need to first create a JSON file with the definition of the trace session. For example
  87.  
  88. {
  89.   "trace": {
  90.     "type": "intel-pt",
  91.     "pt_cpu": {
  92.       "vendor": "intel",
  93.       "family": 6,
  94.       "model": 79,
  95.       "stepping": 1
  96.     }
  97.   },
  98.   "processes": [
  99.     {
  100.       "pid": 815455,
  101.       "triple": "x86_64-*-linux",
  102.       "threads": [
  103.         {
  104.           "tid": 815455,
  105.           "traceFile": "trace.file" # raw thread-specific trace from the AUX buffer
  106.         }
  107.       ],
  108.       "modules": [ # this are all the shared libraries + the main executable
  109.         {
  110.           "file": "a.out", # optional if it's the same as systemPath
  111.           "systemPath": "a.out",
  112.           "loadAddress": "0x0000000000400000",
  113.         },
  114.         {
  115.           "file": "libfoo.so",
  116.           "systemPath": "/usr/lib/libfoo.so",
  117.           "loadAddress": "0x00007ffff7bd9000",
  118.         },
  119.         {
  120.           "systemPath": "libbar.so",
  121.           "loadAddress": "0x00007ffff79d7000",
  122.         }
  123.       ]
  124.     }
  125.   ]
  126. }
  127.  
  128. You can see the full schema by typing
  129.  
  130. > trace schema intel-pt
  131.  
  132. The JSON file mainly contains all the shared libraries that were part of the traced process, along with their memory load address. If the analysis is done on the same computer where the traces were obtained, it’s enough to use the “systemPath” field. If the analysis is done on a different machines, these files need to be copied over and the “file” field should point to the location of the file relative to the JSON file.
  133.  
  134. Once you have the JSON file and the module files in place, you can simple run
  135.  
  136. lldb
  137. > trace load /path/to/json
  138. > thread trace dump instructions <optional thread index>
  139.  
  140. Then it’s like in the live session case
  141.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement