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
[...]