Search code examples
clinuxsignalsposixptrace

Is there any arch-agnostic way of obtaining instruction pointer on SIGTRAP?


I'm looking for an arch-agnostic way to obtain the instruction pointer (AKA program counter) of the last attempted instruction (or one past it) on which SIGTRAP was generated, from the perspective of a ptrace tracer.

An arch-dependent way is to use PTRACE_GETREGS and pick e.g. EIP on i386, RIP on x86_64, PC on ARM etc..

I've tried using siginfo.si_addr as well as siginfo.si_ptr from PTRACE_GETSIGINFO-returned struct, but these values appear completely wrong (4 hex digits instead of 8, and not even similar to the true address), so they don't seem to be what I need.

In Linux I've also tried making use of 30th field of /proc/<pid>/task/<tid>/stat, which the kernel fills in fs/proc/array.c:do_task_stat() with KSTK_EIP(task) (which, despite being named x86-centric, appears defined for many other architectures). But for some reason on my ARMv6 Linux 4.9.28+ (Raspbian 8) I get zeros for both program counter and stack pointer.

So, is there any arch-independent way of determining the current/next address defined by POSIX or at least available in Linux?


Solution

  • You might use /proc/[pid]/syscall.

    mark@ubuntu:~$ gdb python
    ...
    ...
    ... 
    Program received signal SIGINT, Interrupt.
    0x00007ffff78ed573 in __select_nocancel () at ../sysdeps/unix/syscall-template.S:84
    84  ../sysdeps/unix/syscall-template.S: No such file or directory.
    (gdb) 
    
    mark@ubuntu:~/$ ps aux | grep python
    mark      77858  0.2  0.7  90216 37780 pts/2    S+   15:13   0:00 gdb python
    mark      77860  0.0  0.1  38416  6424 pts/2    t    15:13   0:00 /usr/bin/python
    

    (see that 77860 is traced - t)

    mark@ubuntu:~/$ sudo cat /proc/77860/syscall
    23 0x1 0x7fffffffd980 0x0 0x0 0x0 0x7ffff7fdb700 0x7fffffffd958 0x7ffff78ed573
    

    0x7fffffffd958 is sp and 0x7ffff78ed573 is the program counter.

    I couldn't find any ptrace call that helps here.

    http://man7.org/linux/man-pages/man5/proc.5.html

       /proc/[pid]/syscall (since Linux 2.6.27)
              This file exposes the system call number and argument regis‐
              ters for the system call currently being executed by the
              process, followed by the values of the stack pointer and pro‐
              gram counter registers.  The values of all six argument regis‐
              ters are exposed, although most system calls use fewer regis‐
              ters.
    
              If the process is blocked, but not in a system call, then the
              file displays -1 in place of the system call number, followed
              by just the values of the stack pointer and program counter.
              If process is not blocked, then the file contains just the
              string "running".