X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=util.c;h=e477cf10e9ac0f52f894e866b20867d9f6a7aadc;hb=aa524c88c49814863cb7f19e5c8a8eeca6ce22fe;hp=db5408e97cb864ab59a993751e33ed0196a0db74;hpb=c1652e2095fcd9ac62cf2669ef6aec5fd0052851;p=strace diff --git a/util.c b/util.c index db5408e9..e477cf10 100644 --- a/util.c +++ b/util.c @@ -35,9 +35,14 @@ #include "defs.h" +#include +#include #include #include #include +#if HAVE_SYS_UIO_H +#include +#endif #ifdef SUNOS4 #include #include @@ -46,10 +51,11 @@ #if defined(linux) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1)) #include -#endif +#endif #if defined(LINUX) && defined(IA64) -#include +# include +# include #endif #ifdef HAVE_SYS_REG_H @@ -57,16 +63,38 @@ # define PTRACE_PEEKUSR PTRACE_PEEKUSER #elif defined(HAVE_LINUX_PTRACE_H) #undef PTRACE_SYSCALL +# ifdef HAVE_STRUCT_IA64_FPREG +# define ia64_fpreg XXX_ia64_fpreg +# endif +# ifdef HAVE_STRUCT_PT_ALL_USER_REGS +# define pt_all_user_regs XXX_pt_all_user_regs +# endif #include +# undef ia64_fpreg +# undef pt_all_user_regs #endif #ifdef SUNOS4_KERNEL_ARCH_KLUDGE #include #endif /* SUNOS4_KERNEL_ARCH_KLUDGE */ -#if defined(LINUX) && defined(SPARC) +#if defined(LINUXSPARC) -#include +# define fpq kernel_fpq +# define fq kernel_fq +# define fpu kernel_fpu +# include +# undef fpq +# undef fq +# undef fpu + +#if defined (SPARC64) +# define r_pc r_tpc +# undef PTRACE_GETREGS +# define PTRACE_GETREGS PTRACE_GETREGS64 +# undef PTRACE_SETREGS +# define PTRACE_SETREGS PTRACE_SETREGS64 +#endif /* SPARC64 */ #if !defined(__GLIBC__) @@ -84,7 +112,11 @@ __asm__ volatile ("or %%g0, %1, %%o0\n\t" \ "or %%g0, %4, %%o3\n\t" \ "or %%g0, %5, %%o4\n\t" \ "or %%g0, %6, %%g1\n\t" \ +#if defined (SPARC64) + "t 0x6d\n\t" \ +#else "t 0x10\n\t" \ +#endif "bcc 1f\n\t" \ "or %%g0, %%o0, %0\n\t" \ "sub %%g0, %%o0, %0\n\t" \ @@ -199,7 +231,7 @@ int n; char * xlookup(xlat, val) -struct xlat *xlat; +const struct xlat *xlat; int val; { for (; xlat->str != NULL; xlat++) @@ -213,9 +245,9 @@ int val; */ void printxval(xlat, val, dflt) -struct xlat *xlat; +const struct xlat *xlat; int val; -char *dflt; +const char *dflt; { char *str = xlookup(xlat, val); @@ -232,7 +264,7 @@ char *dflt; */ int addflags(xlat, flags) -struct xlat *xlat; +const struct xlat *xlat; int flags; { int n; @@ -252,9 +284,10 @@ int flags; } int -printflags(xlat, flags) -struct xlat *xlat; +printflags(xlat, flags, dflt) +const struct xlat *xlat; int flags; +const char *dflt; { int n; char *sep; @@ -273,10 +306,23 @@ int flags; n++; } } - if (flags) { - tprintf("%s%#x", sep, flags); - n++; + + if (n) { + if (flags) { + tprintf("%s%#x", sep, flags); + n++; + } + } else { + if (flags) { + tprintf("%#x", flags); + if (dflt) + tprintf(" /* %s */", dflt); + } else { + if (dflt) + tprintf("0"); + } } + return n; } @@ -286,7 +332,7 @@ struct tcb *tcp; long addr; char *fmt; { - int num; + long num; if (!addr) { tprintf("NULL"); @@ -301,6 +347,15 @@ char *fmt; tprintf("]"); } +void +printuid(text, uid) +const char *text; +unsigned long uid; +{ + tprintf("%s", text); + tprintf((uid == -1) ? "%ld" : "%lu", uid); +} + static char path[MAXPATHLEN + 1]; void @@ -331,7 +386,9 @@ printpath(tcp, addr) struct tcb *tcp; long addr; { - if (umovestr(tcp, addr, MAXPATHLEN, path) < 0) + if (addr == 0) + tprintf("NULL"); + else if (umovestr(tcp, addr, MAXPATHLEN, path) < 0) tprintf("%#lx", addr); else string_quote(path); @@ -344,7 +401,9 @@ struct tcb *tcp; long addr; int n; { - if (umovestr(tcp, addr, n, path) < 0) + if (addr == 0) + tprintf("NULL"); + else if (umovestr(tcp, addr, n, path) < 0) tprintf("%#lx", addr); else { path[n] = '\0'; @@ -370,7 +429,7 @@ int len; if (!str) { if ((str = malloc(max_strlen)) == NULL || (outstr = malloc(2*max_strlen)) == NULL) { - fprintf(stderr, "printstr: no memory\n"); + fprintf(stderr, "out of memory\n"); tprintf("%#lx", addr); return; } @@ -464,6 +523,38 @@ int len; tprintf("%s", outstr); } +#if HAVE_SYS_UIO_H +void +dumpiov(tcp, len, addr) +struct tcb * tcp; +int len; +long addr; +{ + struct iovec *iov; + int i; + unsigned long size; + + size = sizeof(*iov) * (unsigned long) len; + if (size / sizeof(*iov) != len + || (iov = (struct iovec *) malloc(size)) == NULL) { + fprintf(stderr, "out of memory\n"); + return; + } + if (umoven(tcp, addr, size, (char *) iov) >= 0) { + for (i = 0; i < len; i++) { + /* include the buffer number to make it easy to + * match up the trace with the source */ + tprintf(" * %lu bytes in buffer %d\n", + (unsigned long)iov[i].iov_len, i); + dumpstr(tcp, (long) iov[i].iov_base, + iov[i].iov_len); + } + } + free((char *) iov); + +} +#endif + void dumpstr(tcp, addr, len) struct tcb *tcp; @@ -480,7 +571,7 @@ int len; if (str) free(str); if ((str = malloc(len)) == NULL) { - fprintf(stderr, "dump: no memory\n"); + fprintf(stderr, "out of memory\n"); return; } strsize = len; @@ -570,7 +661,8 @@ char *laddr; /* Ran into 'end of memory' - stupid "printpath" */ return 0; } - perror("ptrace: umoven"); + if (addr != 0) + perror("ptrace: umoven"); return -1; } started = 1; @@ -632,25 +724,13 @@ char *laddr; #ifdef USE_PROCFS #ifdef HAVE_MP_PROCFS - if (pread(tcp->pfd_as, laddr, len, addr) == -1) - return -1; + int fd = tcp->pfd_as; #else -/* - * We would like to use pread preferentially for speed - * but even though SGI has it in their library, it no longer works. - */ -#ifdef MIPS -#undef HAVE_PREAD + int fd = tcp->pfd; #endif -#ifdef HAVE_PREAD - if (pread(tcp->pfd, laddr, len, addr) == -1) + lseek(fd, addr, SEEK_SET); + if (read(fd, laddr, len) == -1) return -1; -#else /* !HAVE_PREAD */ - lseek(tcp->pfd, addr, SEEK_SET); - if (read(tcp->pfd, laddr, len) == -1) - return -1; -#endif /* !HAVE_PREAD */ -#endif /* HAVE_MP_PROCFS */ #endif /* USE_PROCFS */ return 0; @@ -668,7 +748,34 @@ int len; char *laddr; { #ifdef USE_PROCFS - return umoven(tcp, addr, len, laddr); +#ifdef HAVE_MP_PROCFS + int fd = tcp->pfd_as; +#else + int fd = tcp->pfd; +#endif + /* Some systems (e.g. FreeBSD) can be upset if we read off the + end of valid memory, avoid this by trying to read up + to page boundaries. But we don't know what a page is (and + getpagesize(2) (if it exists) doesn't necessarily return + hardware page size). Assume all pages >= 1024 (a-historical + I know) */ + + int page = 1024; /* How to find this? */ + int move = page - (addr & (page - 1)); + int left = len; + + lseek(fd, addr, SEEK_SET); + + while (left) { + if (move > left) move = left; + if ((move = read(fd, laddr, move)) <= 0) + return left != len ? 0 : -1; + if (memchr (laddr, 0, move)) break; + left -= move; + laddr += move; + addr += move; + move = page; + } #else /* !USE_PROCFS */ int started = 0; int pid = tcp->pid; @@ -718,15 +825,15 @@ char *laddr; addr += sizeof(long), laddr += m, len -= m; } - return 0; #endif /* !USE_PROCFS */ + return 0; } #ifdef LINUX -#ifndef SPARC +#if !defined (SPARC) && !defined(SPARC64) #define PTRACE_WRITETEXT 101 #define PTRACE_WRITEDATA 102 -#endif /* !SPARC */ +#endif /* !SPARC && !SPARC64 */ #endif /* LINUX */ #ifdef SUNOS4 @@ -844,8 +951,8 @@ long *res; } is_sun4m = strcmp(name.machine, "sun4m") == 0; if (is_sun4m) { - extern struct xlat struct_user_offsets[]; - struct xlat *x; + extern const struct xlat struct_user_offsets[]; + const struct xlat *x; for (x = struct_user_offsets; x->str; x++) x->val += 1024; @@ -858,7 +965,9 @@ long *res; errno = 0; val = ptrace(PTRACE_PEEKUSER, pid, (char *) off, 0); if (val == -1 && errno) { - perror("upeek: ptrace(PTRACE_PEEKUSER, ... )"); + char buf[60]; + sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)",pid,off); + perror(buf); return -1; } *res = val; @@ -877,6 +986,9 @@ struct tcb *tcp; #if defined(I386) if (upeek(tcp->pid, 4*EIP, &pc) < 0) return -1; +#elif defined(X86_64) + if (upeek(tcp->pid, 8*RIP, &pc) < 0) + return -1; #elif defined(IA64) if (upeek(tcp->pid, PT_B0, &pc) < 0) return -1; @@ -884,7 +996,7 @@ struct tcb *tcp; if (upeek(tcp->pid, 4*15, &pc) < 0) return -1; #elif defined(POWERPC) - if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0) + if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0) return -1; #elif defined(M68k) if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) @@ -895,16 +1007,23 @@ struct tcb *tcp; #elif defined(MIPS) if (upeek(tcp->pid, REG_EPC, &pc) < 0) return -1; -#elif defined(SPARC) +#elif defined(SPARC) || defined(SPARC64) struct regs regs; if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)®s,0) < 0) return -1; pc = regs.r_pc; -#elif defined(S390) +#elif defined(S390) || defined(S390X) if(upeek(tcp->pid,PT_PSWADDR,&pc) < 0) + return -1; #elif defined(HPPA) if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0) return -1; +#elif defined(SH) + if (upeek(tcp->pid, 4*REG_PC ,&pc) < 0) + return -1; +#elif defined(SH64) + if (upeek(tcp->pid, REG_PC ,&pc) < 0) + return -1; #endif return pc; #endif /* LINUX */ @@ -939,28 +1058,52 @@ void printcall(tcp) struct tcb *tcp; { +#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \ + sizeof(long) == 8 ? "[????????????????] " : \ + NULL /* crash */) #ifdef LINUX #ifdef I386 long eip; if (upeek(tcp->pid, 4*EIP, &eip) < 0) { - tprintf("[????????] "); + PRINTBADPC; return; } tprintf("[%08lx] ", eip); -#elif defined(IA62) + +#elif defined(S390) || defined(S390X) + long psw; + if(upeek(tcp->pid,PT_PSWADDR,&psw) < 0) { + PRINTBADPC; + return; + } +#ifdef S390 + tprintf("[%08lx] ", psw); +#elif S390X + tprintf("[%16lx] ", psw); +#endif + +#elif defined(X86_64) + long rip; + + if (upeek(tcp->pid, 8*RIP, &rip) < 0) { + PRINTBADPC; + return; + } + tprintf("[%16lx] ", rip); +#elif defined(IA64) long ip; if (upeek(tcp->pid, PT_B0, &ip) < 0) { - tprintf("[????????] "); + PRINTBADPC; return; } tprintf("[%08lx] ", ip); #elif defined(POWERPC) long pc; - if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0) { + if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0) { tprintf ("[????????] "); return; } @@ -977,14 +1120,14 @@ struct tcb *tcp; long pc; if (upeek(tcp->pid, REG_PC, &pc) < 0) { - tprintf ("[????????] "); + tprintf ("[????????????????] "); return; } tprintf("[%08lx] ", pc); -#elif defined(SPARC) +#elif defined(SPARC) || defined(SPARC64) struct regs regs; if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)®s,0) < 0) { - tprintf("[????????] "); + PRINTBADPC; return; } tprintf("[%08lx] ", regs.r_pc); @@ -996,6 +1139,38 @@ struct tcb *tcp; return; } tprintf("[%08lx] ", pc); +#elif defined(MIPS) + long pc; + + if (upeek(tcp->pid, REG_EPC, &pc) < 0) { + tprintf ("[????????] "); + return; + } + tprintf("[%08lx] ", pc); +#elif defined(SH) + long pc; + + if (upeek(tcp->pid, 4*REG_PC, &pc) < 0) { + tprintf ("[????????] "); + return; + } + tprintf("[%08lx] ", pc); +#elif defined(SH64) + long pc; + + if (upeek(tcp->pid, REG_PC, &pc) < 0) { + tprintf ("[????????????????] "); + return; + } + tprintf("[%08lx] ", pc); +#elif defined(ARM) + long pc; + + if (upeek(tcp->pid, 4*15, &pc) < 0) { + PRINTBADPC; + return; + } + tprintf("[%08lx] ", pc); #endif /* !architecture */ #endif /* LINUX */ @@ -1004,7 +1179,7 @@ struct tcb *tcp; if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) ®s, 0) < 0) { perror("printcall: ptrace(PTRACE_GETREGS, ...)"); - tprintf("[????????] "); + PRINTBADPC; return; } tprintf("[%08x] ", regs.r_o7); @@ -1012,7 +1187,7 @@ struct tcb *tcp; #ifdef SVR4 /* XXX */ - tprintf("[????????] "); + PRINTBADPC; #endif #ifdef FREEBSD @@ -1024,16 +1199,284 @@ struct tcb *tcp; #ifndef USE_PROCFS +#if defined LINUX + +#include +#ifndef CLONE_PTRACE +# define CLONE_PTRACE 0x00002000 +#endif + +#ifdef IA64 + +/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32 + subsystem has them for x86... */ +#define SYS_fork 2 +#define SYS_vfork 190 + +typedef unsigned long *arg_setup_state; + +static int +arg_setup(struct tcb *tcp, arg_setup_state *state) +{ + unsigned long *bsp, cfm, sof, sol; + + if (ia32) + return 0; + + if (upeek(tcp->pid, PT_AR_BSP, (long *) &bsp) < 0) + return -1; + if (upeek(tcp->pid, PT_CFM, (long *) &cfm) < 0) + return -1; + + sof = (cfm >> 0) & 0x7f; + sol = (cfm >> 7) & 0x7f; + bsp = ia64_rse_skip_regs(bsp, -sof + sol); + + *state = bsp; + return 0; +} + +# define arg_finish_change(tcp, state) 0 + +#ifdef SYS_fork +static int +get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp) +{ + int ret; + + if (ia32) + 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 (ia32) + 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; +} +#endif + +static int +set_arg0 (struct tcb *tcp, arg_setup_state *state, long val) +{ + int req = PTRACE_POKEDATA; + void *ap; + + if (ia32) { + 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 (ia32) { + 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; +} + +#elif defined (SPARC) || defined (SPARC64) + +typedef struct 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)->r_o0, 0) +# define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0) +# define set_arg0(tcp, state, val) ((state)->r_o0 = (val), 0) +# define set_arg1(tcp, state, val) ((state)->r_o1 = (val), 0) +# define restore_arg0(tcp, state, val) 0 + +#else + +# 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) +# 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 +# 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 + +#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 + +int +setbpt(tcp) +struct tcb *tcp; +{ + extern int change_syscall(struct tcb *, int); + arg_setup_state state; + + if (tcp->flags & TCB_BPTSET) { + fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid); + return -1; + } + + switch (tcp->scno) { +#ifdef SYS_vfork + case SYS_vfork: +#endif +#ifdef SYS_fork + case SYS_fork: +#endif +#if defined SYS_fork || defined SYS_vfork + 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, SYS_clone) < 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; +#endif + + case SYS_clone: +#ifdef SYS_clone2 + case SYS_clone2: +#endif + if ((tcp->u_arg[arg0_index] & CLONE_PTRACE) == 0 + && (arg_setup (tcp, &state) < 0 + || set_arg0 (tcp, &state, + tcp->u_arg[arg0_index] | CLONE_PTRACE) < 0 + || arg_finish_change (tcp, &state) < 0)) + return -1; + tcp->flags |= TCB_BPTSET; + tcp->inst[0] = tcp->u_arg[arg0_index]; + tcp->inst[1] = tcp->u_arg[arg1_index]; + return 0; + + default: + fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n", + tcp->scno, tcp->pid); + break; + } + + return -1; +} + +int +clearbpt(tcp) +struct tcb *tcp; +{ + arg_setup_state state; + if (arg_setup (tcp, &state) < 0 + || restore_arg0 (tcp, &state, tcp->inst[0]) < 0 + || restore_arg1 (tcp, &state, tcp->inst[1]) < 0 + || arg_finish_change (tcp, &state)) + return -1; + tcp->flags &= ~TCB_BPTSET; + return 0; +} + +#else + int setbpt(tcp) struct tcb *tcp; { #ifdef LINUX -#ifdef SPARC +#if defined (SPARC) || defined (SPARC64) /* We simply use the SunOS breakpoint code. */ struct regs regs; + unsigned long inst; #define LOOPA 0x30800000 /* ba,a 0 */ if (tcp->flags & TCB_BPTSET) { @@ -1063,25 +1506,55 @@ struct tcb *tcp; * Of cause, if we evaporate ourselves in the middle of all this... */ errno = 0; - ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOPA); + inst = LOOPA; +#if defined (SPARC64) + inst <<= 32; + inst |= (tcp->inst[0] & 0xffffffffUL); +#endif + ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, inst); if(errno) { perror("setbpt: ptrace(PTRACE_POKETEXT, ...)"); return -1; } tcp->flags |= TCB_BPTSET; -#else /* !SPARC */ +#else /* !SPARC && !SPARC64 */ #ifdef IA64 - /* - * Our strategy here is to replace the bundle that contained - * the clone() syscall with a bundle of the form: - * - * { 1: br 1b; br 1b; br 1b } - * - * This ensures that the newly forked child will loop - * endlessly until we've got a chance to attach to it. - */ - { + if (ia32) { +# define LOOP 0x0000feeb + if (tcp->flags & TCB_BPTSET) { + fprintf(stderr, "PANIC: bpt already set in pid %u\n", + tcp->pid); + return -1; + } + if (upeek(tcp->pid, PT_CR_IIP, &tcp->baddr) < 0) + return -1; + if (debug) + fprintf(stderr, "[%d] setting bpt at %lx\n", + tcp->pid, tcp->baddr); + tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, + (char *) tcp->baddr, 0); + if (errno) { + perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)"); + return -1; + } + ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP); + if (errno) { + perror("setbpt: ptrace(PTRACE_POKETEXT, ...)"); + return -1; + } + tcp->flags |= TCB_BPTSET; + } else { + /* + * Our strategy here is to replace the bundle that + * contained the clone() syscall with a bundle of the + * form: + * + * { 1: br 1b; br 1b; br 1b } + * + * This ensures that the newly forked child will loop + * endlessly until we've got a chance to attach to it. + */ # define LOOP0 0x0000100000000017 # define LOOP1 0x4000000000200000 unsigned long addr, ipsr; @@ -1092,11 +1565,14 @@ struct tcb *tcp; return -1; if (upeek(pid, PT_CR_IIP, &addr) < 0) return -1; - tcp->baddr = addr | ((ipsr >> 41) & 0x3); /* store "ri" in low two bits */ + /* store "ri" in low two bits */ + tcp->baddr = addr | ((ipsr >> 41) & 0x3); errno = 0; - tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0, 0); - tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8, 0); + tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0, + 0); + tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8, + 0); if (errno) { perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)"); return -1; @@ -1113,22 +1589,30 @@ struct tcb *tcp; } #else /* !IA64 */ -#if defined (I386) +#if defined (I386) || defined(X86_64) #define LOOP 0x0000feeb #elif defined (M68K) #define LOOP 0x60fe0000 #elif defined (ALPHA) #define LOOP 0xc3ffffff #elif defined (POWERPC) -#define LOOP 0x0000feeb +#define LOOP 0x48000000 #elif defined(ARM) #define LOOP 0xEAFFFFFE #elif defined(MIPS) #define LOOP 0x1000ffff #elif defined(S390) #define LOOP 0xa7f40000 /* BRC 15,0 */ +#elif defined(S390X) +#define LOOP 0xa7f4000000000000UL /* BRC 15,0 */ #elif defined(HPPA) #define LOOP 0xe81f1ff7 /* b,l,n ,r0 */ +#elif defined(SH) +#ifdef __LITTLE_ENDIAN__ +#define LOOP 0x0000affe +#else +#define LOOP 0xfeaf0000 +#endif #else #error unknown architecture #endif @@ -1140,6 +1624,9 @@ struct tcb *tcp; #if defined (I386) if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0) return -1; +#elif defined (X86_64) + if (upeek(tcp->pid, 8*RIP, &tcp->baddr) < 0) + return -1; #elif defined (M68K) if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0) return -1; @@ -1150,15 +1637,18 @@ struct tcb *tcp; #elif defined (MIPS) return -1; /* FIXME: I do not know what i do - Flo */ #elif defined (POWERPC) - if (upeek(tcp->pid, 4*PT_NIP, &tcp->baddr) < 0) + if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &tcp->baddr) < 0) return -1; -#elif defined(S390) +#elif defined(S390) || defined(S390X) if (upeek(tcp->pid,PT_PSWADDR, &tcp->baddr) < 0) return -1; #elif defined(HPPA) if (upeek(tcp->pid, PT_IAOQ0, &tcp->baddr) < 0) return -1; tcp->baddr &= ~0x03; +#elif defined(SH) + if (upeek(tcp->pid, 4*REG_PC, &tcp->baddr) < 0) + return -1; #else #error unknown architecture #endif @@ -1177,7 +1667,7 @@ struct tcb *tcp; tcp->flags |= TCB_BPTSET; #endif /* !IA64 */ -#endif /* SPARC */ +#endif /* SPARC || SPARC64 */ #endif /* LINUX */ #ifdef SUNOS4 @@ -1238,7 +1728,7 @@ struct tcb *tcp; { #ifdef LINUX -#if defined(I386) +#if defined(I386) || defined(X86_64) long eip; #elif defined(POWERPC) long pc; @@ -1248,9 +1738,11 @@ struct tcb *tcp; long pc; #elif defined(HPPA) long iaoq; +#elif defined(SH) + long pc; #endif /* architecture */ -#ifdef SPARC +#if defined (SPARC) || defined (SPARC64) /* Again, we borrow the SunOS breakpoint code. */ if (!(tcp->flags & TCB_BPTSET)) { fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid); @@ -1264,7 +1756,34 @@ struct tcb *tcp; } tcp->flags &= ~TCB_BPTSET; #elif defined(IA64) - { + if (ia32) { + unsigned long addr; + + if (debug) + fprintf(stderr, "[%d] clearing bpt\n", tcp->pid); + if (!(tcp->flags & TCB_BPTSET)) { + fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid); + return -1; + } + errno = 0; + ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]); + if (errno) { + perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)"); + return -1; + } + tcp->flags &= ~TCB_BPTSET; + + if (upeek(tcp->pid, PT_CR_IIP, &addr) < 0) + return -1; + if (addr != tcp->baddr) { + /* The breakpoint has not been reached yet. */ + if (debug) + fprintf(stderr, + "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n", + addr, tcp->baddr); + return 0; + } + } else { unsigned long addr, ipsr; pid_t pid; @@ -1303,7 +1822,7 @@ struct tcb *tcp; return 0; } } -#else /* !IA64 && ! SPARC */ +#else /* !IA64 && !SPARC && !SPARC64 */ if (debug) fprintf(stderr, "[%d] clearing bpt\n", tcp->pid); @@ -1330,8 +1849,19 @@ struct tcb *tcp; eip, tcp->baddr); return 0; } +#elif defined(X86_64) + if (upeek(tcp->pid, 8*RIP, &eip) < 0) + return -1; + if (eip != tcp->baddr) { + /* The breakpoint has not been reached yet. */ + if (debug) + fprintf(stderr, + "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n", + eip, tcp->baddr); + return 0; + } #elif defined(POWERPC) - if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0) + if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0) return -1; if (pc != tcp->baddr) { /* The breakpoint has not been reached yet. */ @@ -1378,8 +1908,19 @@ struct tcb *tcp; */ ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq); ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq); +#elif defined(SH) + if (upeek(tcp->pid, 4*REG_PC, &pc) < 0) + return -1; + if (pc != tcp->baddr) { + /* The breakpoint has not been reached yet. */ + if (debug) + fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n", + pc, tcp->baddr); + return 0; + } + #endif /* arch */ -#endif /* !SPARC && !IA64 */ +#endif /* !SPARC && !SPARC64 && !IA64 */ #endif /* LINUX */ #ifdef SUNOS4 @@ -1435,6 +1976,8 @@ struct tcb *tcp; return 0; } +#endif + #endif /* !USE_PROCFS */ #ifdef SUNOS4 @@ -1490,7 +2033,7 @@ struct tcb *tcp; return -1; } if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) { - fprintf(stderr, "fixvfork: out of memory\n"); + fprintf(stderr, "out of memory\n"); return -1; } if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),