Project Url: mqf20/ghidra-PT
Introduction: Tool for integrating Intel Processor Trace (PT) with Ghidra.
More: Author   ReportBugs   
Ghidra Integration with Intel Processor Trace Prerequisites CPU with Intel PT Support perf cmake Intel XED libipt and ptxed Ghidra Installation Example


CPU with Intel PT Support

Verify that Intel PT is supported by your CPU and display its capabilities:

$ ls /sys/devices/intel_pt/format

branch  cyc  cyc_thresh  fup_on_ptw  mtc  mtc_period  noretcomp  psb_period  pt  ptw  pwr_evt  tsc


Use apt:

sudo apt install linux-tools-common linux-tools-generic linux-tools-`uname -r`

Verify that Intel PT is supported by perf:

perf list | grep intel_pt


Use apt:

sudo apt install cmake

Intel XED

Clone the Intel XED Github repository:

git clone mbuild

git clone

cd xed

./ --share

./ examples

sudo ./ --prefix=/usr/local install

sudo ldconfig

sudo cp ./obj/wkit/examples/obj/xed /usr/local/bin

libipt and ptxed

Clone the libipt Github repository:

git clone

Configure cmake to build ptxed:

cd libipt

mkdir build && cd build

cmake .. -D PTXED=ON

Finally build:


sudo make install

sudo ldconfig


Tested on Ghidra 10.0.


Copy ghidra_scripts/ into {GHIDRA_INSTALL_PATH}/Ghidra/Features/Base/ghidra_scripts.


We will use a simple C++ program for demonstration:

#include <iostream>
#include <cstdlib>

int main(int argc, char *argv[]) {

    if (argc > 1) {

        std::cout << "You have entered " << argc << " arguments:" << "\n"; 

        for (int i = 0; i < argc; ++i) 
            std::cout << argv[i] << "\n"; 

    } else {

        std::cout << "Usage: " << argv[0] << " [arguments]\n";


    return EXIT_SUCCESS;

Build the C++ program:

g++ main.cpp -o app_O0_g -O0 -g

Test the C++ program:

$ ./app_O0_g "hello world"
You have entered 2 arguments:
hello world

Assume that we are only interested in tracing the .text section. Using readelf, we know that .text section’s offset is 0x10c0 and size is 0x2b5:

$ readelf -S ./app_O0_g

There are 36 section headers, starting at offset 0x8e58:
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [16] .text             PROGBITS         00000000000010c0  000010c0
       00000000000002b5  0000000000000000  AX       0     0     16

Before we collect an execution trace using perf, you may have to:

echo kernel.kptr_restrict=0 | sudo tee -a /etc/sysctl.conf # Configure sysctl.conf to make kernel symbols visible:

echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid # Configure system to allow events by all users

Run perf record with the required filter:

$ perf record -e intel_pt/cyc=0,noretcomp,tsc=0,mtc=0/u --filter 'filter 0x10c0 / 0x2b5 @ ./app_O0_g' -o -- ./app_O0_g "hello world"

You have entered 2 arguments:
hello world
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.003 MB ]

By default, the Intel PT trace output and auxiliary data generated by perf record are saved to We only want the Intel PT trace output (without the auxiliary data) -- we can extract the Intel PT trace output using libipt's perf-read-aux.bash:

sudo apt install gawk # required by perf-read-aux.bash


By default, libipt's perf-read-aux.bash will save the Intel PT trace output in a new file with the -idx??.bin appendix (where ?? will depend on your CPU number).

Finally, we use ptxed to reconstruct the control flow:

{LIBIPT_INSTALL_PATH}/build/bin/ptxed --pt ./ --raw ./app_O0_g:0x555555554000 > ptxed_output # update the path ./ accordingly

Note that we use the base address 0x555555554000 for the .text section because perf record will automatically disable ASLR.

Beware, the output of ptxed can be verbose:

$ tail ./ptxed_output
00005555555550fe  cmp rax, rdi
0000555555555101  jz 0x555555555118
0000555555555118  ret
000055555555518c  mov byte ptr [rip+0x2fbd], 0x1
0000555555555193  pop rbp
0000555555555194  ret
[cbr: 2d]
[cbr: 2e]
[paging, cr3: 00000002aee0a000]

Next, import the C++ program into Ghidra at the same base address 0x555555554000 (IMPORTANT!!!).

In Ghidra's Code Browser,


The console will display some useful information:> Running...> >> opening /home/user/ptxed_output> >> processed 201 addresses> Finished!


Inspired by:

About Me
GitHub: Trinea
Facebook: Dev Tools