0

I'm using ptrace system call in C language:

long ptrace(enum __ptrace_request requête, pid_t pid, void *addr, void *data);

But I don't know what void *addr refers to...

In this example, I wanted to get the address of the current instruction which is in RIP:

unsigned long ip = ptrace(PTRACE_PEEKUSER, child, 8 * RIP, NULL);

Where child refers to the PID of the child process, I don't understand why do we need to multiply RIP by 8 and why RIP is used as an integer constant (defined in <sys/reg.h> as 16).

16*8 = 128 is an integer constant: is it a valid (void *addr) ?

Rachid K.
  • 4,490
  • 3
  • 11
  • 30
  • See: https://man7.org/linux/man-pages/man2/ptrace.2.html mostrly after the parameter request is explained: "The value of request determines the action to be performed" – Sir Jo Black Sep 19 '22 at 08:44

1 Answers1

1

ptrace() is actually a variadic function as stated in the manual:

Although arguments to ptrace() are interpreted according to the prototype given, glibc currently declares ptrace() as a variadic function with only the request argument fixed. It is recommended to always supply four arguments, even if the requested operation does not use them, setting unused/ignored arguments to 0L or (void *) 0.

Hence, depending on the request (1st parameter), the following parameters will be interpreted accordingly as the function should be actually viewed as something like long ptrace(enum __ptrace_request request, ...);.

In the source code of the GLIBC, it is defined as follow in sysdeps/unix/sysv/linux/ptrace.c:

long int
ptrace (enum __ptrace_request request, ...)
{
  long int res, ret;
  va_list ap;
  pid_t pid;
  void *addr, *data;

  va_start (ap, request);
  pid = va_arg (ap, pid_t);
  addr = va_arg (ap, void *);
  data = va_arg (ap, void *);
  va_end (ap);

  if (request > 0 && request < 4)
    data = &ret;

  res = INLINE_SYSCALL (ptrace, 4, request, pid, addr, data);
  if (res >= 0 && request > 0 && request < 4)
    {
      __set_errno (0);
      return ret;
    }

  return res;
}

In the preceding, you can see that it is a variadic function which uses va_arg() to get a pid followed by two void * before passing them to the actual ptrace() system call.
Concerning the 8 * RIP multiplication, it is said in the header file (</sys/reg.h>) that RIP constant is a index in a array of 8 bytes longs. Hence the multiplication:

#ifdef __x86_64__
/* Index into an array of 8 byte longs returned from ptrace for
   location of the users' stored general purpose registers.  */

# define R15    0
# define R14    1
# define R13    2
# define R12    3
# define RBP    4
# define RBX    5
# define R11    6
# define R10    7
# define R9 8
# define R8 9
# define RAX    10
# define RCX    11
# define RDX    12
# define RSI    13
# define RDI    14
# define ORIG_RAX 15
# define RIP    16
[...]
Rachid K.
  • 4,490
  • 3
  • 11
  • 30