* Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
* Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
* Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
+ * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
+ * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Linux for s390 port by D.J. Barrow
+ * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include "defs.h"
+#include <signal.h>
+#include <sys/syscall.h>
#include <sys/user.h>
#include <sys/param.h>
#include <fcntl.h>
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
#ifdef SUNOS4
#include <machine/reg.h>
#include <a.out.h>
#include <link.h>
#endif /* SUNOS4 */
-#if defined(linux)
+#if defined(linux) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1))
#include <linux/ptrace.h>
-#endif
+#endif
+
+#if defined(LINUX) && defined(IA64)
+# include <asm/ptrace_offsets.h>
+# include <asm/rse.h>
+#endif
#ifdef HAVE_SYS_REG_H
#include <sys/reg.h>
# define PTRACE_PEEKUSR PTRACE_PEEKUSER
-#endif
-
-#ifdef HAVE_SYS_PTRACE_H
-#include <sys/ptrace.h>
+#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 <linux/ptrace.h>
+# undef ia64_fpreg
+# undef pt_all_user_regs
#endif
#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
#include <sys/utsname.h>
#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
-#if defined(LINUX) && defined(SPARC)
+#if defined(LINUXSPARC)
-#include <asm/reg.h>
+# define fpq kernel_fpq
+# define fq kernel_fq
+# define fpu kernel_fpu
+# include <asm/reg.h>
+# 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__)
"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" \
char *
xlookup(xlat, val)
-struct xlat *xlat;
+const struct xlat *xlat;
int val;
{
for (; xlat->str != NULL; xlat++)
*/
void
printxval(xlat, val, dflt)
-struct xlat *xlat;
+const struct xlat *xlat;
int val;
-char *dflt;
+const char *dflt;
{
char *str = xlookup(xlat, val);
*/
int
addflags(xlat, flags)
-struct xlat *xlat;
+const struct xlat *xlat;
int flags;
{
int n;
}
int
-printflags(xlat, flags)
-struct xlat *xlat;
+printflags(xlat, flags, dflt)
+const struct xlat *xlat;
int flags;
+const char *dflt;
{
int n;
char *sep;
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;
}
long addr;
char *fmt;
{
- int num;
+ long num;
if (!addr) {
tprintf("NULL");
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
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);
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';
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;
}
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;
if (str)
free(str);
if ((str = malloc(len)) == NULL) {
- fprintf(stderr, "dump: no memory\n");
+ fprintf(stderr, "out of memory\n");
return;
}
strsize = len;
/* Ran into 'end of memory' - stupid "printpath" */
return 0;
}
- perror("ptrace: umoven");
+ if (addr != 0)
+ perror("ptrace: umoven");
return -1;
}
started = 1;
#endif /* !oldway */
#endif /* SUNOS4 */
-#ifdef SVR4
-#ifdef SVR4_MP
- if (pread(tcp->pfd_as, laddr, len, addr) == -1)
- return -1;
+#ifdef USE_PROCFS
+#ifdef HAVE_MP_PROCFS
+ 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)
- return -1;
-#else /* !HAVE_PREAD */
- lseek(tcp->pfd, addr, SEEK_SET);
- if (read(tcp->pfd, laddr, len) == -1)
+ lseek(fd, addr, SEEK_SET);
+ if (read(fd, laddr, len) == -1)
return -1;
-#endif /* !HAVE_PREAD */
-#endif /* SVR4_MP */
-#endif /* SVR4 */
+#endif /* USE_PROCFS */
return 0;
}
int len;
char *laddr;
{
-#ifdef SVR4
- return umoven(tcp, addr, len, laddr);
-#else /* !SVR4 */
+#ifdef USE_PROCFS
+#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;
int i, n, m;
addr += sizeof(long), laddr += m, len -= m;
}
+#endif /* !USE_PROCFS */
return 0;
-#endif /* !SVR4 */
}
#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
#endif /* SUNOS4 */
-#ifndef SVR4
+#ifndef USE_PROCFS
int
upeek(pid, off, 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;
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;
return 0;
}
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
long
getpc(tcp)
#ifdef LINUX
long pc;
-
#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;
#elif defined(ARM)
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)
#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) || 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 */
return 0;
#endif /* SVR4 */
+#ifdef FREEBSD
+ struct reg regs;
+ pread(tcp->pfd_reg, ®s, sizeof(regs), 0);
+ return regs.r_eip;
+#endif /* FREEBSD */
}
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);
-#else /* !I386K */
-#ifdef POWERPC
+
+#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) {
+ 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;
}
tprintf("[%08lx] ", pc);
-#else /* !POWERPC */
-#ifdef M68K
+#elif defined(M68k)
long pc;
if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
return;
}
tprintf("[%08lx] ", pc);
-#else /* !M68K */
-#ifdef ALPHA
+#elif defined(ALPHA)
long pc;
if (upeek(tcp->pid, REG_PC, &pc) < 0) {
- tprintf ("[????????] ");
+ tprintf ("[????????????????] ");
return;
}
tprintf("[%08lx] ", pc);
-#else /* !ALPHA */
-#ifdef 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);
-#endif /* SPARC */
-#endif /* ALPHA */
-#endif /* !M68K */
-#endif /* !POWERPC */
-#endif /* !I386 */
+#elif defined(HPPA)
+ long pc;
+
+ if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0) {
+ tprintf ("[????????] ");
+ 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 */
#ifdef SUNOS4
if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) ®s, 0) < 0) {
perror("printcall: ptrace(PTRACE_GETREGS, ...)");
- tprintf("[????????] ");
+ PRINTBADPC;
return;
}
tprintf("[%08x] ", regs.r_o7);
#ifdef SVR4
/* XXX */
- tprintf("[????????] ");
+ PRINTBADPC;
+#endif
+
+#ifdef FREEBSD
+ struct reg regs;
+ pread(tcp->pfd_reg, ®s, sizeof(regs), 0);
+ tprintf("[%08x] ", regs.r_eip);
+#endif /* FREEBSD */
+}
+
+#ifndef USE_PROCFS
+
+#if defined LINUX
+
+#include <sys/syscall.h>
+#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;
}
-#ifndef SVR4
+#else
int
setbpt(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) {
* 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
+ 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;
+ pid_t pid;
-#if defined (I386)
+ pid = tcp->pid;
+ if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
+ return -1;
+ if (upeek(pid, PT_CR_IIP, &addr) < 0)
+ return -1;
+ /* 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);
+ if (errno) {
+ perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
+ return -1;
+ }
+
+ errno = 0;
+ ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
+ ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
+ if (errno) {
+ perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
+ return -1;
+ }
+ tcp->flags |= TCB_BPTSET;
+ }
+#else /* !IA64 */
+
+#if defined (I386) || defined(X86_64)
#define LOOP 0x0000feeb
#elif defined (M68K)
#define LOOP 0x60fe0000
#elif defined (ALPHA)
-#define LOOP 0xc3ffffff
+#define LOOP 0xc3ffffff
#elif defined (POWERPC)
-#define LOOP 0x0000feeb
+#define LOOP 0x48000000
#elif defined(ARM)
-#define LOOP -1 /* almost certainly wrong, jws */
+#define LOOP 0xEAFFFFFE
#elif defined(MIPS)
-#define LOOP 0x1000ffff
+#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 <loc>,r0 */
+#elif defined(SH)
+#ifdef __LITTLE_ENDIAN__
+#define LOOP 0x0000affe
+#else
+#define LOOP 0xfeaf0000
+#endif
#else
#error unknown architecture
#endif
#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;
#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) || 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
}
tcp->flags |= TCB_BPTSET;
-#endif /* SPARC */
+#endif /* !IA64 */
+#endif /* SPARC || SPARC64 */
#endif /* LINUX */
#ifdef SUNOS4
{
#ifdef LINUX
-#ifdef I386
+#if defined(I386) || defined(X86_64)
long eip;
-#else /* !I386 */
-#ifdef POWERPC
+#elif defined(POWERPC)
long pc;
-#else /* !POWERPC */
-#ifdef M68K
+#elif defined(M68K)
long pc;
-#else /* !M68K */
-#ifdef ALPHA
+#elif defined(ALPHA)
long pc;
-#endif /* ALPHA */
-#endif /* !M68K */
-#endif /* !POWERPC */
-#endif /* !I386 */
+#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);
return -1;
}
tcp->flags &= ~TCB_BPTSET;
-#else /* !SPARC */
+#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;
+
+ pid = tcp->pid;
+
+ if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
+ return -1;
+ if (upeek(pid, PT_CR_IIP, &addr) < 0)
+ return -1;
+
+ /* restore original bundle: */
+ errno = 0;
+ ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
+ ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
+ if (errno) {
+ perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
+ return -1;
+ }
+
+ /* restore original "ri" in ipsr: */
+ ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
+ errno = 0;
+ ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
+ if (errno) {
+ perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
+ return -1;
+ }
+
+ tcp->flags &= ~TCB_BPTSET;
+
+ if (addr != (tcp->baddr & ~0x3)) {
+ /* 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 /* !IA64 && !SPARC && !SPARC64 */
if (debug)
fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
eip, tcp->baddr);
return 0;
}
-#else /* !I386 */
-#ifdef POWERPC
- if (upeek(tcp->pid, 4*PT_NIP, &pc) < 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, sizeof(unsigned long)*PT_NIP, &pc) < 0)
return -1;
if (pc != tcp->baddr) {
/* The breakpoint has not been reached yet. */
pc, tcp->baddr);
return 0;
}
-#else /* !POWERPC */
-#ifdef M68K
+#elif defined(M68K)
if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
return -1;
if (pc != tcp->baddr) {
pc, tcp->baddr);
return 0;
}
-#else /* !M68K */
-#ifdef ALPHA
+#elif defined(ALPHA)
if (upeek(tcp->pid, REG_PC, &pc) < 0)
return -1;
if (pc != tcp->baddr) {
pc, tcp->baddr);
return 0;
}
-#endif /* ALPHA */
-#endif /* !M68K */
-#endif /* !POWERPC */
-#endif /* !I386 */
-#endif /* !SPARC */
+#elif defined(HPPA)
+ if (upeek(tcp->pid, PT_IAOQ0, &iaoq) < 0)
+ return -1;
+ iaoq &= ~0x03;
+ if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
+ /* The breakpoint has not been reached yet. */
+ if (debug)
+ fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
+ iaoq, tcp->baddr);
+ return 0;
+ }
+ iaoq = tcp->baddr | 3;
+ /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
+ * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
+ * has no significant effect.
+ */
+ 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 && !SPARC64 && !IA64 */
#endif /* LINUX */
#ifdef SUNOS4
return 0;
}
-#endif /* !SVR4 */
+#endif
+
+#endif /* !USE_PROCFS */
#ifdef SUNOS4
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),