*/
#include "defs.h"
-#include <sys/user.h>
#include <sys/param.h>
#include <fcntl.h>
#if HAVE_SYS_XATTR_H
#endif
#include <sys/uio.h>
-#if defined(IA64)
-# include <asm/ptrace_offsets.h>
-# include <asm/rse.h>
-#endif
-
-#ifdef HAVE_SYS_REG_H
-# include <sys/reg.h>
-#endif
-
+#include "regs.h"
#include "ptrace.h"
int
}
void
-printnum(struct tcb *tcp, long addr, const char *fmt)
+printnum_long(struct tcb *tcp, long addr, const char *fmt)
{
long num;
fprintf(stderr, "Out of memory\n");
return;
}
- if (umoven(tcp, addr, size, (char *) iov) >= 0) {
+ if (umoven(tcp, addr, size, iov) >= 0) {
for (i = 0; i < len; i++) {
/* include the buffer number to make it easy to
* match up the trace with the source */
strsize = len + 16;
}
- if (umoven(tcp, addr, len, (char *) str) < 0)
+ if (umoven(tcp, addr, len, str) < 0)
return;
/* Space-pad to 16 bytes */
#define PAGMASK (~(PAGSIZ - 1))
/*
* move `len' bytes of data from process `pid'
- * at address `addr' to our space at `laddr'
+ * at address `addr' to our space at `our_addr'
*/
int
-umoven(struct tcb *tcp, long addr, unsigned int len, char *laddr)
+umoven(struct tcb *tcp, long addr, unsigned int len, void *our_addr)
{
+ char *laddr = our_addr;
int pid = tcp->pid;
unsigned int n, m, nread;
union {
*res = val;
return 0;
}
-
-/* Note! On new kernels (about 2.5.46+), we use PTRACE_O_TRACECLONE
- * and PTRACE_O_TRACE[V]FORK for tracing children.
- * If you are adding a new arch which is only supported by newer kernels,
- * you most likely don't need to add any code below
- * beside a dummy "return 0" block in change_syscall().
- */
-
-/*
- * These #if's are huge, please indent them correctly.
- * It's easy to get confused otherwise.
- */
-
-#include "syscall.h"
-
-#ifndef CLONE_PTRACE
-# define CLONE_PTRACE 0x00002000
-#endif
-#ifndef CLONE_VFORK
-# define CLONE_VFORK 0x00004000
-#endif
-#ifndef CLONE_VM
-# define CLONE_VM 0x00000100
-#endif
-
-#ifdef IA64
-
-typedef unsigned long *arg_setup_state;
-
-static int
-arg_setup(struct tcb *tcp, arg_setup_state *state)
-{
- unsigned long cfm, sof, sol;
- long bsp;
-
- if (ia64_ia32mode) {
- /* Satisfy a false GCC warning. */
- *state = NULL;
- return 0;
- }
-
- if (upeek(tcp->pid, PT_AR_BSP, &bsp) < 0)
- return -1;
- if (upeek(tcp->pid, PT_CFM, (long *) &cfm) < 0)
- return -1;
-
- sof = (cfm >> 0) & 0x7f;
- sol = (cfm >> 7) & 0x7f;
- bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
-
- *state = (unsigned long *) bsp;
- return 0;
-}
-
-# define arg_finish_change(tcp, state) 0
-
-static int
-get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
-{
- int ret;
-
- if (ia64_ia32mode)
- ret = upeek(tcp->pid, PT_R11, valp);
- else
- ret = umoven(tcp,
- (unsigned long) ia64_rse_skip_regs(*state, 0),
- sizeof(long), (void *) valp);
- return ret;
-}
-
-static int
-get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
-{
- int ret;
-
- if (ia64_ia32mode)
- ret = upeek(tcp->pid, PT_R9, valp);
- else
- ret = umoven(tcp,
- (unsigned long) ia64_rse_skip_regs(*state, 1),
- sizeof(long), (void *) valp);
- return ret;
-}
-
-static int
-set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
-{
- int req = PTRACE_POKEDATA;
- void *ap;
-
- if (ia64_ia32mode) {
- ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
- req = PTRACE_POKEUSER;
- } else
- ap = ia64_rse_skip_regs(*state, 0);
- errno = 0;
- ptrace(req, tcp->pid, ap, val);
- return errno ? -1 : 0;
-}
-
-static int
-set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
-{
- int req = PTRACE_POKEDATA;
- void *ap;
-
- if (ia64_ia32mode) {
- ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
- req = PTRACE_POKEUSER;
- } else
- ap = ia64_rse_skip_regs(*state, 1);
- errno = 0;
- ptrace(req, tcp->pid, ap, val);
- return errno ? -1 : 0;
-}
-
-/* ia64 does not return the input arguments from functions (and syscalls)
- according to ia64 RSE (Register Stack Engine) behavior. */
-
-# define restore_arg0(tcp, state, val) ((void) (state), 0)
-# define restore_arg1(tcp, state, val) ((void) (state), 0)
-
-#elif defined(SPARC) || defined(SPARC64)
-
-# if defined(SPARC64)
-# undef PTRACE_GETREGS
-# define PTRACE_GETREGS PTRACE_GETREGS64
-# undef PTRACE_SETREGS
-# define PTRACE_SETREGS PTRACE_SETREGS64
-# endif
-
-typedef struct pt_regs arg_setup_state;
-
-# define arg_setup(tcp, state) \
- (ptrace(PTRACE_GETREGS, (tcp)->pid, (char *) (state), 0))
-# define arg_finish_change(tcp, state) \
- (ptrace(PTRACE_SETREGS, (tcp)->pid, (char *) (state), 0))
-
-# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
-# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
-# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
-# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
-# define restore_arg0(tcp, state, val) 0
-
-#else /* other architectures */
-
-# if defined S390 || defined S390X
-/* Note: this is only true for the `clone' system call, which handles
- arguments specially. We could as well say that its first two arguments
- are swapped relative to other architectures, but that would just be
- another #ifdef in the calls. */
-# define arg0_offset PT_GPR3
-# define arg1_offset PT_ORIGGPR2
-# define restore_arg0(tcp, state, val) ((void) (state), 0)
-# define restore_arg1(tcp, state, val) ((void) (state), 0)
-# define arg0_index 1
-# define arg1_index 0
-# elif defined(ALPHA) || defined(MIPS)
-# define arg0_offset REG_A0
-# define arg1_offset (REG_A0+1)
-# elif defined(POWERPC)
-# define arg0_offset (sizeof(unsigned long)*PT_R3)
-# define arg1_offset (sizeof(unsigned long)*PT_R4)
-# define restore_arg0(tcp, state, val) ((void) (state), 0)
-# elif defined(HPPA)
-# define arg0_offset PT_GR26
-# define arg1_offset (PT_GR26-4)
-# elif defined(X86_64) || defined(X32)
-# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
-# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
-# elif defined(SH)
-# define arg0_offset (4*(REG_REG0+4))
-# define arg1_offset (4*(REG_REG0+5))
-# elif defined(SH64)
- /* ABI defines arg0 & 1 in r2 & r3 */
-# define arg0_offset (REG_OFFSET+16)
-# define arg1_offset (REG_OFFSET+24)
-# define restore_arg0(tcp, state, val) 0
-# elif defined CRISV10 || defined CRISV32
-# define arg0_offset (4*PT_R11)
-# define arg1_offset (4*PT_ORIG_R10)
-# define restore_arg0(tcp, state, val) 0
-# define restore_arg1(tcp, state, val) 0
-# define arg0_index 1
-# define arg1_index 0
-# else
-# define arg0_offset 0
-# define arg1_offset 4
-# if defined ARM
-# define restore_arg0(tcp, state, val) 0
-# endif
-# endif
-
-typedef int arg_setup_state;
-
-# define arg_setup(tcp, state) (0)
-# define arg_finish_change(tcp, state) 0
-# define get_arg0(tcp, cookie, valp) (upeek((tcp)->pid, arg0_offset, (valp)))
-# define get_arg1(tcp, cookie, valp) (upeek((tcp)->pid, arg1_offset, (valp)))
-
-static int
-set_arg0(struct tcb *tcp, void *cookie, long val)
-{
- return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
-}
-
-static int
-set_arg1(struct tcb *tcp, void *cookie, long val)
-{
- return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
-}
-
-#endif /* architectures */
-
-#ifndef restore_arg0
-# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
-#endif
-#ifndef restore_arg1
-# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
-#endif
-
-#ifndef arg0_index
-# define arg0_index 0
-# define arg1_index 1
-#endif
-
-static int
-change_syscall(struct tcb *tcp, arg_setup_state *state, int new)
-{
-#if defined(I386)
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_EAX * 4), new) < 0)
- return -1;
- return 0;
-#elif defined(X86_64)
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_RAX * 8), new) < 0)
- return -1;
- return 0;
-#elif defined(X32)
- /* setbpt/clearbpt never used: */
- /* X32 is only supported since about linux-3.0.30 */
-#elif defined(POWERPC)
- if (ptrace(PTRACE_POKEUSER, tcp->pid,
- (char*)(sizeof(unsigned long)*PT_R0), new) < 0)
- return -1;
- return 0;
-#elif defined(S390) || defined(S390X)
- /* s390 linux after 2.4.7 has a hook in entry.S to allow this */
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR2), new) < 0)
- return -1;
- return 0;
-#elif defined(M68K)
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_ORIG_D0), new) < 0)
- return -1;
- return 0;
-#elif defined(SPARC) || defined(SPARC64)
- state->u_regs[U_REG_G1] = new;
- return 0;
-#elif defined(MIPS)
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), new) < 0)
- return -1;
- return 0;
-#elif defined(ALPHA)
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), new) < 0)
- return -1;
- return 0;
-#elif defined(AVR32)
- /* setbpt/clearbpt never used: */
- /* AVR32 is only supported since about linux-2.6.19 */
-#elif defined(BFIN)
- /* setbpt/clearbpt never used: */
- /* Blackfin is only supported since about linux-2.6.23 */
-#elif defined(IA64)
- if (ia64_ia32mode) {
- switch (new) {
- case 2:
- break; /* x86 SYS_fork */
- case SYS_clone:
- new = 120;
- break;
- default:
- fprintf(stderr, "%s: unexpected syscall %d\n",
- __FUNCTION__, new);
- return -1;
- }
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R1), new) < 0)
- return -1;
- } else if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R15), new) < 0)
- return -1;
- return 0;
-#elif defined(HPPA)
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR20), new) < 0)
- return -1;
- return 0;
-#elif defined(SH)
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*(REG_REG0+3)), new) < 0)
- return -1;
- return 0;
-#elif defined(SH64)
- /* Top half of reg encodes the no. of args n as 0x1n.
- Assume 0 args as kernel never actually checks... */
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_SYSCALL),
- 0x100000 | new) < 0)
- return -1;
- return 0;
-#elif defined(CRISV10) || defined(CRISV32)
- if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_R9), new) < 0)
- return -1;
- return 0;
-#elif defined(ARM)
- /* Some kernels support this, some (pre-2.6.16 or so) don't. */
-# ifndef PTRACE_SET_SYSCALL
-# define PTRACE_SET_SYSCALL 23
-# endif
- if (ptrace(PTRACE_SET_SYSCALL, tcp->pid, 0, new & 0xffff) != 0)
- return -1;
- return 0;
-#elif defined(AARCH64)
- /* setbpt/clearbpt never used: */
- /* AARCH64 is only supported since about linux-3.0.31 */
-#elif defined(TILE)
- /* setbpt/clearbpt never used: */
- /* Tilera CPUs are only supported since about linux-2.6.34 */
-#elif defined(MICROBLAZE)
- /* setbpt/clearbpt never used: */
- /* microblaze is only supported since about linux-2.6.30 */
-#elif defined(OR1K)
- /* never reached; OR1K is only supported by kernels since 3.1.0. */
-#elif defined(METAG)
- /* setbpt/clearbpt never used: */
- /* Meta is only supported since linux-3.7 */
-#elif defined(XTENSA)
- /* setbpt/clearbpt never used: */
- /* Xtensa is only supported since linux 2.6.13 */
-#elif defined(ARC)
- /* setbpt/clearbpt never used: */
- /* ARC only supported since 3.9 */
-#else
-#warning Do not know how to handle change_syscall for this architecture
-#endif /* architecture */
- return -1;
-}
-
-int
-setbpt(struct tcb *tcp)
-{
- static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
- arg_setup_state state;
-
- if (tcp->flags & TCB_BPTSET) {
- fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
- return -1;
- }
-
- /*
- * It's a silly kludge to initialize this with a search at runtime.
- * But it's better than maintaining another magic thing in the
- * godforsaken tables.
- */
- if (clone_scno[current_personality] == 0) {
- unsigned int i;
- for (i = 0; i < nsyscalls; ++i)
- if (sysent[i].sys_func == sys_clone) {
- clone_scno[current_personality] = i;
- break;
- }
- }
-
- if (tcp->s_ent->sys_func == sys_fork) {
- if (arg_setup(tcp, &state) < 0
- || get_arg0(tcp, &state, &tcp->inst[0]) < 0
- || get_arg1(tcp, &state, &tcp->inst[1]) < 0
- || change_syscall(tcp, &state,
- clone_scno[current_personality]) < 0
- || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
- || set_arg1(tcp, &state, 0) < 0
- || arg_finish_change(tcp, &state) < 0)
- return -1;
- tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
- tcp->u_arg[arg1_index] = 0;
- tcp->flags |= TCB_BPTSET;
- return 0;
- }
-
- if (tcp->s_ent->sys_func == sys_clone) {
- /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
- contrary to x86 vfork above. Even on x86 we turn the
- vfork semantics into plain fork - each application must not
- depend on the vfork specifics according to POSIX. We would
- hang waiting for the parent resume otherwise. We need to
- clear also CLONE_VM but only in the CLONE_VFORK case as
- otherwise we would break pthread_create. */
-
- long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
- if (new_arg0 & CLONE_VFORK)
- new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
- if (arg_setup(tcp, &state) < 0
- || set_arg0(tcp, &state, new_arg0) < 0
- || arg_finish_change(tcp, &state) < 0)
- return -1;
- tcp->inst[0] = tcp->u_arg[arg0_index];
- tcp->inst[1] = tcp->u_arg[arg1_index];
- tcp->flags |= TCB_BPTSET;
- return 0;
- }
-
- fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
- tcp->scno, tcp->pid);
- return -1;
-}
-
-int
-clearbpt(struct tcb *tcp)
-{
- arg_setup_state state;
- if (arg_setup(tcp, &state) < 0
- || change_syscall(tcp, &state, tcp->scno) < 0
- || restore_arg0(tcp, &state, tcp->inst[0]) < 0
- || restore_arg1(tcp, &state, tcp->inst[1]) < 0
- || arg_finish_change(tcp, &state))
- if (errno != ESRCH)
- return -1;
- tcp->flags &= ~TCB_BPTSET;
- return 0;
-}