Code Monkey home page Code Monkey logo

simple-pt's Introduction

simple-pt

Introduction

simple-pt is a simple implementation of Intel Processor Trace (PT) on Linux. PT can trace all branches executed by the CPU at the hardware level with moderate overhead. simple-pt then decodes the branch trace and displays a function or instruction level trace.

PT is supported on Intel 5th generation Core (Broadwell), 6th generation Core (Skylake) CPUs, and later, as well as Goldmont based Atom CPUs (Intel Joule, Apollo Lake) and later.

Example

% sptcmd  -c tcall taskset -c 0 ./tcall
cpu   0 offset 1027688,  1003 KB, writing to ptout.0
...
Wrote sideband to ptout.sideband
% sptdecode --sideband ptout.sideband --pt ptout.0 | less
TIME      DELTA	 INSNs   OPERATION
frequency 32
0        [+0]     [+   1] _dl_aux_init+436
                  [+   6] __libc_start_main+455 -> _dl_discover_osversion
...
                  [+  13] __libc_start_main+446 -> main
                  [+   9]     main+22 -> f1
                  [+   4]	      f1+9 -> f2
                  [+   2]	      f1+19 -> f2
                  [+   5]     main+22 -> f1
                  [+   4]	      f1+9 -> f2
                  [+   2]	      f1+19 -> f2
                  [+   5]     main+22 -> f1
...

Overview

simple-pt consists of a

  • kernel driver
  • sptcmd to collect data from the kernel driver
  • sptdecode to display function or instruction traces
  • fastdecode to dump raw PT traces

It uses the libipt PT decoding library

Note that Linux 4.1 and later has an integrated PT implementation as part of Linux perf. gdb 7.10 also supports full debugging on top of PT. Intel VTune also supports PT.

If you want a full production system please use one of these. simple-pt is an experimental implementation.

Simple PT does NOT support:

  • It does not support long term tracing of more data than fits in the buffer (no interrupt) (use perf or VTune)
  • It does not support any sampling (use perf or VTune)
  • It requires root rights to collect data (use perf)
  • It does not support interactive debugging (use gdb or hardware debuggers)

Simple PT has the following functionality:

  • set up hardware to processor trace
  • supports a ring buffer of branch data, stopped on events
  • supports flushing buffer on panic
  • does not require patching the kernel (although it cheats a bit using kprobes)
  • set up PT filters, such as kernel filter, or filter ranges
  • start and stop traces at specific kernel addresses, with unlimited number
  • support tracing multiple processes
  • print all function calls in "ftrace" style
  • disassembling all executed instructions (requires xed library, optional)
  • simple driver that could be ported to older kernel releases or other operating systems
  • simple code base that is easily changed.
  • modular "unix style" design with simple tools that do only one thing
  • can dump branches before panic to kernel log and decode

Installation

Note: simple-pt now requires a new version of libipt (2.x), which has an incompatible API. Please update.

Note: The installation requirements for simple-pt have changed. It now requires the upstream version of libipt. No special branches needed anymore. Also udis86 has been replaced with xed.

Build and install libipt

git clone https://github.com/01org/processor-trace -b stable/v2.0
cd processor-trace
cmake .
make
sudo make install
sudo ldconfig

Install libelf-elf-devel or elfutils-devel or similar depending on your distribution.

Optionally install xed if you want to see disassembled instructions:

git clone https://github.com/intelxed/mbuild.git mbuild
git clone https://github.com/intelxed/xed
cd xed
mkdir obj
cd obj
../mfile.py
sudo ../mfile.py --prefix=/usr/local install

Clone simple-pt

git clone https://github.com/andikleen/simple-pt
cd simple-pt

Build the kernel module. May require installing kernel includes from your distribution.

make 

Install the kernel module

sudo make modules_install

Build the user tools

make user

If you installed xed use

make user XED=1

Check if your system supports PT

./ptfeature

Run a trace

sudo ./sptcmd -c ls ls
sudo ./sptdecode --sideband ptout.sideband --pt ptout.0 | less

On recent kernels it may be needed to separate page table separation, if you want to use process filtering

Boot the kernel with the "nopti" argument

sptcmd loads and configures the kernel driver. It runs a program with trace. It always does a global trace. It writes the pt trace data to trace files for each CPU (ptout.N where N is the CPU number). It also writes side band information needed to decode the trace into the ptout.sideband file.

-c sets a command filter, tracing only commands with that name. Otherwise everything global is traced.

sptdecode then decodes the trace for a CPU using the side band information. When it should decode kernel code it needs to run as root to be able to read /proc/kcore. If it's not run as root kernel code will not be shown.

Another way to use simple-pt is to run the workload with PT running in the background and only dump on an event.

Start trace and dump trace on event:

sudo ./sptcmd --enable
<run workload>
<some event of interest happens and triggers:>
sudo ./sptcmd --dump
sudo ./sptdecode --sideband ptout.sideband --pt ptout.0 | less

Another way is to use --stop-address or --stop-range to stop the trace on specific kernel symbols being executed. Note that these options only affect the trace on their current CPU.

Run test suite

sudo ./tester

Design overview

The kernel driver manages the PT hardware and allocates the trace buffers. It also sets up some custom trace points for the sideband data.

The simple-pt kernel driver is configured using module parameters. Many can be changed at runtime through /sys/module/simple_pt/parameters. A few need a driver reload

Use modinfo simple-pt.ko

to show all allowed parameters. For most parameters sptcmd has options to set them up. That is the recommended interface.

sptcmd configures the driver, starts the trace and runs the trace command. The driver sets up a ring buffer and runs the the processor trace for each CPU until stopped. Then it calls sptdump to write the buffer for each CPU to a ptout.N file (N is the number of the CPU)

For the side band information ftrace with some custom trace points defined by the driver is used. sptsideband converts the ftrace output into the .sideband files used by the decoder.

sptdecode then reads the PT data, the sideband data, the executables, the kernel code through /proc/kcore, and uses the libipt decoder to reconstruct the trace.

Manpages

Changing the PT buffer sizes

To change the PT buffer size the driver needs to be loaded manually. The PT buffer size can be changed with the pt_buffer_order parameter.

rmmod simple_pt # if it was loaded
modprobe simple_pt pt_buffer_order=10

The size is specified in 2^n 4K pages. The default is 9 (2MB). The maximum limit is the kernel's MAX_ORDER limit, typically 8MB. The allocation may also fail if the kernel memory is too fragmented. In this case quitting a large process may help.

When ptfeature shows the "multiple toPA entries" feature it is possible to allocate multiple PT buffers with the pt_num_buffers parameter. All the buffers are logically concatenated. The default is one buffer. The maximum is 511 buffers.

Using simple-pt for panic debugging

simple-pt can be used to print a number of branches before a panic.

insmod simple-pt.ko start=1 print_panic_psbs=4
<panic system>
<collect log from serial console>

The number after print_panic_psbs specifies the length of the logged trace (expressed in number of PT sync points)

The PT information is logged in base64 format to the kernel log. It can be recovered with the base64log.py utility

base64log.py < log > ptlog
sptdecode --elf vmlinux --pt ptlog

This method currently does not support modules or ring 3 code, or multiple PT buffers.

Notes

  • To limit the program to one CPU use sptcmd taskset -c CPU ..

  • To demangle C++ symbols pipe output through c++filt

  • To start/stop around specific user code bracket it with dummy syscalls that you can then put a kernel trigger on. The test suite uses personality(21212212) and prctl(12341234). This will be improved in the future.

  • perf or the BIOS may be already using the PT hardware. If you know it's safe you can take over the PT hardware with --force -d.

  • When configuring the driver manually you need to manually reset any parameters you do not want anymore. sptcmd takes care of that automatically.

  • Some Debian kernels are built without CONFIG_KALLSYMS_ALL. When you see an "Cannot find task_lock" error message load the simple_pt module like this

    insmod simple_pt.ko tasklist_lock_ptr=0x$(grep tasklist_lock /boot/System.map-$(uname -r) | awk ' {print $1}')

  • Various older Linux kernels have problems with ftrace in kernel modules. simple-pt relies on ftrace output for its sideband. "tester" has a special test. If there are problems likely the workarounds in "compat.h" (e.g. the ifdefs) need to be adjusted. Upgrading to a newer kernel should fix the problem too.

  • The time in different ptout files collected on the same system without reboot is synchronized. However the synchronization is not fine grained enough to directly determine causality of nearby memory accesses.

Current limitations:

  • When kernel tracing is disabled (-K) multiple processes cannot be distinguished by the decoder.

  • Enabling/Disabling tracing causes the kernel to modify itself, which can cause the PT decoder to lose synchronization. sptcmd disables trace points. Workaround is to keep trace points running after the trace ends with -k, or disable kernel tracing. This can sometimes affect the test suite. If this happens try "tester -k"

  • sptcmd does not continuously save side band data, so events at the beginning of a trace may not be saved. For complex workloads it may be needed to increase the trace buffers in /sys/kernel/debug/tracing/buffer_size_kb.

  • The decoder does not (currently) support reusing the same address region in a process for different code (for example after dlclose/dlopen)

  • Tracing JITed code is not supported.

  • On Skylake the trace time occasionally jumps backwards after frequency changes.

  • Decoder loses synchronization in some cases where it shouldn't.

  • Binaries with spaces in the name are not supported (due to limitations in sptsideband.py)

  • On 5.7+ kernels using symbol names located in modules in --start/stop-addr will leak the module count of the module.

  • On systems with page table isolation active the -C filter can only filter on user code or kernel code, but not both at the same time. To avoid this boot with pti=off. Note this may make the system suspectible to Meltdown.

Porting simple-pt

There is some Linux specific code in the driver, but the basic PT hardware configuration should be straight forward to adapt to other environments. The minimum support needed is memory allocation, a mechanism to call a callback on all CPUs (IPIs), and a mechanism to establish a shared buffer with the decoding tool (implemented using mmap on a character device). When suspend-to-ram is supported it's also useful to have a callback after resume to reinitialize the hardware.

The kernel driver is configured using global variables with Linux's moduleparams mechanism. This can be replaced with simple hard coded variables.

The driver supports Linux "kprobes" and "kallsyms" to set custom triggers. That code is all optional and can be removed. Such optional code is generally marked as optional.

The user tools should be portable to POSIX C99 based systems. The code to access the kernel image will need to be adapted. Porting to non DWARF/ELF based systems will need more work.

Contact

For bugs please file a github issue.

Andi Kleen

simple-pt's People

Contributors

alexeydmitriev avatar andikleen avatar bash-c avatar ganboing avatar jingfelix avatar mmisono avatar preusser avatar radiolok avatar yangxi avatar zhengjunxing avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

simple-pt's Issues

some code wrong with cr3 filter or i have not understand cr3 filter mechanism

Accroding to the Intel® 64 and IA-32 Architectures Software Developer’s Manual.pdf section 35.2.7.6 IA32_RTIT_CR3_MATCH MSR Intel says Bits 63:5 hold the CR3 address value to match, bits 4:0 are reserved to 0.
image
But in your code at simple-pt.c line 774 function set_cr3_filter

static void set_cr3_filter(void *arg)
{
	u64 val;

	if (pt_rdmsrl_safe(MSR_IA32_RTIT_CTL, &val) < 0)
		return;
	if ((val & TRACE_EN) && pt_wrmsrl_safe(MSR_IA32_RTIT_CTL, val & ~TRACE_EN) < 0)
		return;
	if (pt_wrmsrl_safe(MSR_IA32_CR3_MATCH, *(u64 *)arg) < 0)
		pr_err("cpu %d, cannot set cr3 filter\n", smp_processor_id());
	if ((val & TRACE_EN) && pt_wrmsrl_safe(MSR_IA32_RTIT_CTL, val) < 0)
		return;
}

You haven't set the low 5bit of arg(the value of cr3) to 0, this may cause general-protection fault (#GP)
We know when low 5 bit is 0 ,the mask is 0xffffffffffffffe0
hex(0b1111111111111111111111111111111111111111111111111111111111100000)=0xffffffffffffffe0L
so this is my code for set_cr3_filter,you can ignore the code for logging.

static void set_cr3_filter_fix(void *arg)
{
        u64 val;

        if (pt_rdmsrl_safe(MSR_IA32_RTIT_CTL, &val) < 0)
                return;
        if ((val & TRACE_EN) && pt_wrmsrl_safe(MSR_IA32_RTIT_CTL, val & ~TRACE_EN) < 0)
                return;
        pr_err("now arg: %p,before set_cr3_filter",*(u64 *)arg);
        pr_err("simple-pt:Cpu %d Ready to set_cr3_filter: cr3:%p",smp_processor_id(),(*(u64 *)arg )&0xffffffffffffffe0 ) ;
        if (pt_wrmsrl_safe(MSR_IA32_CR3_MATCH, (*(u64 *)arg )&0xffffffffffffffe0 ) < 0)
                pr_err("cpu %d, cannot set cr3 filter\n", smp_processor_id());
        if ((val & TRACE_EN) && pt_wrmsrl_safe(MSR_IA32_RTIT_CTL, val) < 0)
                return;
}

And i have another question, after I perform this patch. I can only get trace log for my specific process in ring0 code,but can not get any log for my specific process in ring3 code. I wonder know it's my code error or i have not understand the mechanism of cr3 filter? Could you help figure out this question?
I want to use cr3 filter to trace an specific process both ring0 and cr3 code. thanks all.

insmod simple_pt.ko failed.

I was follow the simple-pt install guidence, and everything went well until the last step.

When I executed "./ptfeature", it got an output of "No PT support", and I find the simple_pt.ko is not in the kernel module.

So I run "insmod simple_pt.ko", the output is as follows:
"insmod:ERROR: could not insert module :Input/output error"

And then I run dmesg to see the kernel log, the output is as follows:
qq 20180409165454

By the way, I was install simple-pt in a kvm-qemu virtual machine.

libipt.so.1 and libipt.so.0 : library mismatch

On running a sample trace, sudo ./sptcmd -c ls ls, the trace is getting captured succesfully. However on decoding the trace using

sudo ./sptdecode --sideband ptout.sideband --pt ptout.0 | less

an error is displayed regarding libipt:

./sptdecode: error while loading shared libraries: libipt.so.1: cannot open shared object file: No such file or directory

On checking for if libipt is correctly installed, using sudo ldconfig -p | grep libipt,

libiptc.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libiptc.so.0

I guess this is some mismatch due to libipt.so.0 and libipt.so.1. How should I resolve this?

sptdecode.c:158:4: error: ‘ptic_error’ undeclared

Hi @andikleen,

I hope you are doing great!

I came across with an error while running "make user" and hope you can help me. Thank you.

sptdecode.c:158:4: error: ‘ptic_error’ undeclared (first use in this function); did you mean ‘perror’?
158 | [ptic_error] = "error",
| ^~~~~~~~~~
| perror
sptdecode.c:158:4: note: each undeclared identifier is reported only once for each function it appears in
sptdecode.c:158:4: error: array index in initializer not of integer type
sptdecode.c:158:4: note: (near initialization for ‘class_name’)
make: *** [: sptdecode.o] Error 1

Best,
Puming

Missed one instruction on call

400894 0 call insn: e8 27 fe ff ff callq 0x4006c0
//4006c0: ff 25 4a f9 7f 00 jmpq *0x7ff94a(%rip) # c00010 <sleep@GLIBC_2.2.5> /this line is missing from the output (copied from objdump -d)/
4006c6 0 other insn: 68 02 00 00 00 pushq $0x2

undefined reference to `pt_insn_get_cr3'

Hi,
While compiling simple_pt, at the stage "make user UDIS86=1", I got the following error:
simple-pt/sptdecode.c:437: undefined reference to `pt_insn_get_cr3'
collect2: error: ld returned 1 exit status
make: *** [sptdecode] Error 1

I have followed steps described in the README. Help is required.
thanks

trace stream does not match query

I have a current kernel, booted with nopti, inet_pt is supported and built from the current github state:

# dmesg|grep nopti
[    0.000000] Command line: BOOT_IMAGE=/vmlinuz-4.19.0-kali1-amd64 root=/dev/mapper/kali--vg-root ro quiet nopti
# ./ptfeature 
Supports PT
toPA output support:            1
multiple toPA entries:          1
single range:                   1
trace transport output:         0
payloads are LIP:               0
cycle accurate mode / psb freq: 1
filtering / stop / mtc:         1
CR3 match:                      1
Number of address ranges:       2
Supports filter ranges:         1
Supports stop ranges:           1
Valid cycles thresholds:        1 2 3 4 5 6 7 8 9 10 11 12 13 14 
Valid PSB frequencies:          1 2 3 4 5 6 
Valid MTC frequencies:          1 4 7 10 
TSC ratio:                      2 242
Bus frequency:                  121.000008
Family:                         6
Model:                          142
Stepping:                       9

to show that the issue is present with the example commands in the README:

 # ./sptcmd -c ls ls
[... ls output ...]
cpu   0 offset    176,     0 KB, writing to ptout.0
cpu   1 offset    272,     0 KB, writing to ptout.1
cpu   2 offset    144,     0 KB, writing to ptout.2
cpu   3 offset    416,     0 KB, writing to ptout.3
Wrote sideband to ptout.sideband
# ./sptdecode --sideband ptout.sideband --pt ptout.0
TIME      DELTA         INSNs   OPERATION
b0:0: error trace stream does not match query
b0: sync forward: trace stream does not match query

and this happens for any command. the kernel module is present.
when I unload the kernel module and use perf I get stuff (and perf report shows branches etc.):

# perf record -e intel_pt//u ls
[... ls output ...]
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.068 MB perf.data ]

any idea what the issue could be?
thanks!

sudo make modules_install error

make -C /lib/modules/uname -r/build M=pwd modules_install
make[1]: Entering directory '/usr/src/linux-headers-4.10.0-19-generic'
INSTALL /home/zhanggen/simple-pt/simple-pt.ko
At main.c:158:
** - SSL error:02001002:system library:fopen:No such file or directory: bss_file.c:175

  • SSL error:2006D080:BIO routines:BIO_new_file:no such file: bss_file.c:178**
    sign-file: certs/signing_key.pem: No such file or directory
    INSTALL /home/zhanggen/simple-pt/test-ftrace.ko
    At main.c:158:
    **- SSL error:02001002:system library:fopen:No such file or directory: bss_file.c:175
  • SSL error:2006D080:BIO routines:BIO_new_file:no such file: bss_file.c:178**
    sign-file: certs/signing_key.pem: No such file or directory
    DEPMOD 4.10.0-19-generic
    make[1]: Leaving directory '/usr/src/linux-headers-4.10.0-19-generic'

No trace captured when tracing a single function: onoff.c

The code provided in onoff.c does not capturing the trace and write to the ptout.(CPU NUMBER) files. I also tried writing into the /sys/module/simple_pt/parameters/log_dump file in order to dump the captured trace. However neither of the following seem to capture the trace and write to the ptout files.

//Remaining Functions same as in onoff.c
void dump(int flag)
{
    sptcmd(flag,"/sys/module/simple_pt/parameters/log_dump");
}

int main(){
onoff(1);
// Disable clear on start
disable_clear();
start(1);
f1();
write(1, "foo\n", 4);
onoff(0);
dump(1);
}
//Remaining Functions same as in onoff.c
void dump(int flag)
{
    sptcmd(flag,"/sys/module/simple_pt/parameters/log_dump");
}

int main(){
onoff(1);
// Disable clear on start
disable_clear();
start(1);
f1();
write(1, "foo\n", 4);
dump(1);
onoff(0);
}

timestamp issue

While I am running the test (using the default parameters in simple-pt.c)

sudo ./sptcmd -c ls ls
sudo ./sptdecode --sideband ptout.sideband --pt ptout.0 | less

There are no (or only very few) timestamps shown in the output. Could you shed some light on the possible causes? Does simple-pt support using CYC/MTC packets?

Thanks

build issue: cannot find dwarf headers

I can't build the user tools using 'make user'
I get the following errors:
dwarf.c:32:31: fatal error: libdwarf/libdwarf.h: Datei oder Verzeichnis nicht gefunden
dwarf.c:33:28: fatal error: libdwarf/dwarf.h: Datei oder Verzeichnis nicht gefunden

This means it can not find the header files. Changing the includes to libdwarf.h instead of libdwarf/libdwarf.h solves this issue.
Why is that?

To trace assembly instruction execution patterns

Sir,

We would like to trace assembly instruction execution patterns ( RDTSC - CLFLUSH - RDTSC ) running on our guest VM from our host OS.

Is it possible to accomplish this task by using "simple-pt"?

May we pass process id of our VM to "sptcmd" command to collect trace from our VM?

set up PMI handler

Can you set up PMI hander for buffer overflow?

I try it but fail.

I set the second to last ToPA entry with TOPA_STOP | TOPA_INT and call register_die_notifier in simple_pt_init to register NMI handler, like as following:

static int __kprobes pt_int_handler(struct notifier_block *self, unsigned long cmd, void *__args) {
    pr_err("reach pt PMI interrupt!!\n");
    on_each_cpu(stop_pt, NULL, 1);

    return NOTIFY_STOP;
}

static __read_mostly struct notifier_block pt_int_notifier = {
    .notifier_call          = pt_int_handler,
    .next                   = NULL,
    .priority               = 0
};

static int register_pmi_handler(void) {
    apic_write(APIC_LVTPC,APIC_DM_NMI);
    register_die_notifier(&pt_int_notifier);
    return 0;
}

when I execute gdb, interrupt is raised successfully, but failed for other processes.

I don't know why.

XED

PLEASE UPDATE THE XED INSTALL procedure.
THANKS

struct pt_isn has no member named ... : Error in building user tools

After following the instructions exactly and installing libipt from https://github.com/01org/processor-trace, building user tools throws an error regarding the struct pt_isn not having certain members.

cc -g -Wall -DHAVE_XED=1 -I ../processor-trace/libipt/include -c -o sptdecode.o sptdecode.c
sptdecode.c: In function ‘transfer_events’:
sptdecode.c:84:26: error: ‘struct pt_insn’ has no member named ‘aborted’
#define T(x) si->x = insn->x;
^
sptdecode.c:86:2: note: in expansion of macro ‘T’
T(aborted);
^
sptdecode.c:84:26: error: ‘struct pt_insn’ has no member named ‘committed’
#define T(x) si->x = insn->x;
^
sptdecode.c:87:2: note: in expansion of macro ‘T’
T(committed);
^
sptdecode.c:84:26: error: ‘struct pt_insn’ has no member named ‘disabled’
#define T(x) si->x = insn->x;
^
sptdecode.c:88:2: note: in expansion of macro ‘T’
T(disabled);
^
sptdecode.c:84:26: error: ‘struct pt_insn’ has no member named ‘enabled’
#define T(x) si->x = insn->x;
^
sptdecode.c:89:2: note: in expansion of macro ‘T’
T(enabled);
^
sptdecode.c:84:26: error: ‘struct pt_insn’ has no member named ‘resumed’
#define T(x) si->x = insn->x;
^
sptdecode.c:90:2: note: in expansion of macro ‘T’
T(resumed);
^
sptdecode.c:84:26: error: ‘struct pt_insn’ has no member named ‘interrupted’
#define T(x) si->x = insn->x;
^
sptdecode.c:91:2: note: in expansion of macro ‘T’
T(interrupted);
^
sptdecode.c:84:26: error: ‘struct pt_insn’ has no member named ‘resynced’
#define T(x) si->x = insn->x;
^
sptdecode.c:92:2: note: in expansion of macro ‘T’
T(resynced);
^
sptdecode.c: In function ‘print_insn’:
sptdecode.c:287:10: error: ‘struct pt_insn’ has no member named ‘enabled’
if (insn->enabled)
^
sptdecode.c:289:10: error: ‘struct pt_insn’ has no member named ‘disabled’
if (insn->disabled)
^
sptdecode.c:291:10: error: ‘struct pt_insn’ has no member named ‘resumed’
if (insn->resumed)
^
sptdecode.c:293:10: error: ‘struct pt_insn’ has no member named ‘interrupted’
if (insn->interrupted)
^
sptdecode.c: In function ‘decode’:
sptdecode.c:510:11: error: ‘struct pt_insn’ has no member named ‘enabled’
insn.enabled || insn.disabled || insn.resumed || insn.interrupted ||
^
sptdecode.c:510:27: error: ‘struct pt_insn’ has no member named ‘disabled’
insn.enabled || insn.disabled || insn.resumed || insn.interrupted ||
^
sptdecode.c:510:44: error: ‘struct pt_insn’ has no member named ‘resumed’
insn.enabled || insn.disabled || insn.resumed || insn.interrupted ||
^
sptdecode.c:510:60: error: ‘struct pt_insn’ has no member named ‘interrupted’
insn.enabled || insn.disabled || insn.resumed || insn.interrupted ||
^
sptdecode.c:511:11: error: ‘struct pt_insn’ has no member named ‘resynced’
insn.resynced || insn.stopped || insn.aborted) {
^
sptdecode.c:511:28: error: ‘struct pt_insn’ has no member named ‘stopped’
insn.resynced || insn.stopped || insn.aborted) {
^
sptdecode.c:511:44: error: ‘struct pt_insn’ has no member named ‘aborted’
insn.resynced || insn.stopped || insn.aborted) {
^
: recipe for target 'sptdecode.o' failed
make: *** [sptdecode.o] Error 1

"error no memory mapped at this address" : for userspace commands

Hi,

I am currently using the February 2017 commit of simple-pt and the March commit of Intel PT as the newer versions are giving me errors and I am not able to even successfully run the tester. With these versions, I am able to run the tester binary successfully. Also the trace is being captured correctly and being decoded correctly for the kernel space calls. However, when I run a purely userspace program (a simple c++ for loop) and capture the trace,

/simple-pt$ sudo ./sptcmd test
Wrote initial process maps to ptout.maps
cpu   0 offset    368,     0 KB, writing to ptout.0
cpu   1 offset    368,     0 KB, writing to ptout.1
cpu   2 offset    368,     0 KB, writing to ptout.2
cpu   3 offset  25888,    25 KB, writing to ptout.3
cpu   4 offset    368,     0 KB, writing to ptout.4
cpu   5 offset    368,     0 KB, writing to ptout.5
cpu   6 offset    368,     0 KB, writing to ptout.6
cpu   7 offset    384,     0 KB, writing to ptout.7
Wrote sideband to ptout.sideband


on decoding the trace of the ptout3.out file, an error of no memory being mapped at this address is observed (as in the code snippet below).

simple-pt$ sudo ./sptdecode --sideband ptout.sideband --pt ptout.3 | less

TIME      DELTA         INSNs   OPERATION
frequency 40
0         [+0]          [+   1] native_write_msr_safe+10
                        [+   2] restart.part.16+66 -> mutex_unlock
                        [+   7] param_attr_store+125 -> mutex_unlock
                        [+   8] kernfs_fop_write+137 -> kernfs_put_active
                        [+   2] kernfs_fop_write+145 -> mutex_unlock
                        [+   4] kernfs_fop_write+159 -> kfree
                        [+  17] vfs_write+299 -> __fsnotify_parent
                        [+   7] vfs_write+324 -> fsnotify
                        [+  15] vfs_write+344 -> __sb_end_write
                        [+   8]     __sb_end_write+28 -> percpu_up_read
a8:7f6c0c0376e0: error no memory mapped at this address
b96:7f6c0bfcbb74: error no memory mapped at this address
1316:7f6c0bfcbb74: error no memory mapped at this address
1a96:4b9328: error no memory mapped at this address
2216:4b91fb: error no memory mapped at this address
298e:4b9317: error no memory mapped at this address
3116:7f6c0bf677a1: error no memory mapped at this address
389e:7f6c0bfed1f0: error no memory mapped at this address
43e6:475e4b: error no memory mapped at this address
4b4e:4b9443: error no memory mapped at this address
52de:475e4b: error no memory mapped at this address
5a56:7f6c0bf67881: error no memory mapped at this address
328808    [+328808]     [+   1] get_close_on_exec+40
61f0:7f6c0c037b07: error no memory mapped at this address
61f0: sync forward: reached end of trace stream

Since the tester is running perfectly fine and the kernel space calls are being decoded correctly, I am not able to figure out why the userspace calls are returning with this error (I even tried to decode the trace on other programs like gzip, etc. however this error persists).

License?

Hello, what is the license of this code?

Cannot make user - ‘print_ip’ used but never defined

When I try to run "make user" on an Ubuntu 32bit 14.04.3 system I get this error:

useruser@ubuntu:~/simple-pt$ make user
cc -g -Wall -I ../processor-trace/libipt/include -c -o sptdecode.o sptdecode.c
sptdecode.c:134:13: error: conflicting types for ‘print_ip’
static void print_ip(uint64_t ip, unsigned long cr3)
^
sptdecode.c:90:13: note: previous declaration of ‘print_ip’ was here
static void print_ip(uint64_t ip, uint64_t cr3);
^
sptdecode.c: In function ‘print_ip’:
sptdecode.c:140:4: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘uint64_t’ [-Wformat=]
printf("+%ld", ip - sym->val);
^
sptdecode.c:142:3: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘uint64_t’ [-Wformat=]
printf("%lx", ip);
^
sptdecode.c: In function ‘print_insn’:
sptdecode.c:232:3: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘uint64_t’ [-Wformat=]
insn_class(insn->iclass));
^
sptdecode.c:232:3: warning: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 3 has type ‘uint64_t’ [-Wformat=]
sptdecode.c: In function ‘remove_loops’:
sptdecode.c:297:7: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘uint64_t’ [-Wformat=]
insn, l[j].iterations);
^
sptdecode.c:297:7: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 3 has type ‘uint64_t’ [-Wformat=]
sptdecode.c: In function ‘decode’:
sptdecode.c:401:4: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘uint64_t’ [-Wformat=]
printf("%lx: sync forward: %s\n", pos, pt_errstr(pt_errcode(err)));
^
sptdecode.c:482:5: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘uint64_t’ [-Wformat=]
pt_errstr(pt_errcode(err)));
^
sptdecode.c:482:5: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 3 has type ‘uint64_t’ [-Wformat=]
sptdecode.c: At top level:
sptdecode.c:90:13: warning: ‘print_ip’ used but never defined [enabled by default]
static void print_ip(uint64_t ip, uint64_t cr3);
^
make: *** [sptdecode.o] Error 1

Missing branches in decoded trace

Hi Andi,

Consider this code snippet compiled with no optimizations (i.e., gcc -g snippet.c). You can ignore the code inside the if then and if else basic blocks as it is not important. The main point is that the loop checks the branch condition at each iteration and then either:

  1. falls through the then basic block on even iterations (if branch taken), or
  2. jumps to the else basic block on odd iterations (if branch not taken)

does that for 500,000,000 times and ends with a jump to the return 0; (i.e., loop branch becomes "not taken").

int main() {
	volatile int i=0, a=1, b=2, n=500000000;
	for (i=0; i<n; ++i) { // loop branch: taken (present in decoded trace)
		a++;
		a--;
		if (b<a) {    // if branch: taken (present in decoded trace)
			b=a*a-2*b;
			a=b*b*b-a*a-3;
		}
		else {        // if branch: not taken (not present in decoded trace)
			a=b*b-2*a;
			b=a*a*a - b*b -3;
		}	
	}
	return 0;
}

Given this intended execution pattern, when tracing and decoding we would expect to see an output like this (simplified for clarity, the RIPs of the dynamic/executed basic blocks are actually printed):

loop branch: taken
if branch:   taken
loop branch: taken
if branch:   not taken
loop branch: taken
if branch:   taken
loop branch: taken
if branch:   not taken
....
loop branch: not taken

Instead, we only see the taken loop branch and the taken if branch in an arbitrary order:

loop branch: taken
loop branch: taken
loop branch: taken
loop branch: taken
if branch:   taken
loop branch: taken
if branch:   taken
loop branch: taken
loop branch: taken
loop branch: taken
...

Moreover, there are far less than 2 * 500,000,000 + 1 entries in the output file, the trace doesn't end with the loop branch: not taken and successive runs yield different decoded outputs.... Intel PT's documentation mentions something about not capturing the prefix of the trace, but says nothing about the suffix, or about sampling branches or any kind of randomness in the tracing process (or it's possible that we misunderstood the documentation : -) ).

And that's not all. When we change to code to get rid of the a++ and a-- lines inside the loop (i.e., first 2 lines after the for instruction), we start to see the "not taken" branch of the if statement from time to time, but still everything is printed in an arbitrary order:

loop branch: taken
if branch:   not taken
loop branch: taken
loop branch: taken
loop branch: taken
if branch:   taken
loop branch: taken
if branch:   taken
loop branch: taken
loop branch: taken
if branch:   not taken
loop branch: taken
...

This is a bit confusing and maybe we're not using correct tracing / decoding arguments. As far as our understanding goes, both conditional jumps (loop and if statement) should be captured by Intel PT along with their direction (i.e., taken / not taken) at each iteration. Then, the decoder should be able to tell which basic blocks execute at each iteration based on the direction of the two branches and print out the starting RIP of each such block.

What are we missing?
Thanks.

P.S. We are currently running 7e47800

'-c' flag and kernel pages isolation

Hi, Andi

You wrote that '-c' flag doesn't work because of kernel page isolation.
Could you help me to understand how simple-pt deals with processes. How does simple-pt distinguish one process from another? According to what I see at simple-pt.c you set some trace points to scheduler in order to handle context switch and save this information somewhere? Is it right?
And you mentioned that now a process have multiple page tables. Am I right that the purpose of this is to handle different address spaces for application and kernel?
Since it works this way nowadays, how to extract a trace for a specified TID/PID from simple-pt trace? I talk about hypothetical availability for such thing even is this requires writing code.

--Sergey

SSL error in installing kernel module

When I try installing the kernel module using "sudo make modules_install", i get the following SSL error. I am not sure which kernel dependencies to install to get rid of this error.

make -C /lib/modules/uname -r/build M=pwd modules_install
make[1]: Entering directory '/usr/src/linux-headers-4.4.0-36-generic'
INSTALL /workspace/siddhant/simple-pt/simple-pt.ko
At main.c:222:
SSL error:02001002:system library:fopen:No such file or directory: bss_file.c:175
SSL error:2006D080:BIO routines:BIO_new_file:no such file: bss_file.c:178
sign-file: certs/signing_key.pem: No such file or directory
INSTALL /workspace/siddhant/simple-pt/test-ftrace.ko
At main.c:222:
SSL error:02001002:system library:fopen:No such file or directory: bss_file.c:175
SSL error:2006D080:BIO routines:BIO_new_file:no such file: bss_file.c:178
sign-file: certs/signing_key.pem: No such file or directory
DEPMOD 4.4.0-36-generic
make[1]: Leaving directory '/usr/src/linux-headers-4.4.0-36-generic'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.