* 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 __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 && (defined(I386) || defined(M68K))
-# include <sys/reg.h>
-# define PTRACE_PEEKUSR PTRACE_PEEKUSER
-#endif
-#ifdef LINUX
-#ifndef __GLIBC__
+
+#if defined(linux) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1))
#include <linux/ptrace.h>
#endif
-#endif /* LINUX */
-#ifdef HAVE_SYS_PTRACE_H
-#include <sys/ptrace.h>
+#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
+#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) && !defined(__GLIBC__)
-
-#include <linux/unistd.h>
-
-#define _hack_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,\
- type5,arg5,syscall) \
-type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
-{ \
- long __res; \
-\
-__asm__ volatile ("or %%g0, %1, %%o0\n\t" \
- "or %%g0, %2, %%o1\n\t" \
- "or %%g0, %3, %%o2\n\t" \
- "or %%g0, %4, %%o3\n\t" \
- "or %%g0, %5, %%o4\n\t" \
- "or %%g0, %6, %%g1\n\t" \
- "t 0x10\n\t" \
- "bcc 1f\n\t" \
- "or %%g0, %%o0, %0\n\t" \
- "sub %%g0, %%o0, %0\n\t" \
- "1:\n\t" \
- : "=r" (__res) \
- : "0" ((long)(arg1)),"1" ((long)(arg2)), \
- "2" ((long)(arg3)),"3" ((long)(arg4)),"4" ((long)(arg5)), \
- "i" (__NR_##syscall) \
- : "g1", "o0", "o1", "o2", "o3", "o4"); \
-if (__res>=0) \
- return (type) __res; \
-errno = -__res; \
-return -1; \
-}
-
-static _hack_syscall5(int,_ptrace,int,__request,int,__pid,int,__addr,int,__data,int,__addr2,ptrace)
-
-#define _ptrace
-
+#if defined(LINUXSPARC) && defined (SPARC64)
+# undef PTRACE_GETREGS
+# define PTRACE_GETREGS PTRACE_GETREGS64
+# undef PTRACE_SETREGS
+# define PTRACE_SETREGS PTRACE_SETREGS64
#endif
/* macros */
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
-void
-tv_tv(tv, a, b)
-struct timeval *tv;
-int a;
-int b;
-{
- tv->tv_sec = a;
- tv->tv_usec = b;
-}
-
int
tv_nz(a)
struct timeval *a;
{
tv->tv_sec = a->tv_sec + b->tv_sec;
tv->tv_usec = a->tv_usec + b->tv_usec;
- if (tv->tv_usec > 1000000) {
+ if (tv->tv_usec >= 1000000) {
tv->tv_sec++;
tv->tv_usec -= 1000000;
}
int n;
{
tv->tv_usec = a->tv_usec * n;
- tv->tv_sec = a->tv_sec * n + a->tv_usec / 1000000;
+ tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
tv->tv_usec %= 1000000;
}
-char *
-xlookup(xlat, val)
-struct xlat *xlat;
-int val;
+const char *
+xlookup(const struct xlat *xlat, int val)
{
for (; xlat->str != NULL; xlat++)
if (xlat->val == val)
return NULL;
}
+/*
+ * Generic ptrace wrapper which tracks ESRCH errors
+ * by setting tcp->ptrace_errno to ESRCH.
+ *
+ * We assume that ESRCH indicates likely process death (SIGKILL?),
+ * modulo bugs where process somehow ended up not stopped.
+ * Unfortunately kernel uses ESRCH for that case too. Oh well.
+ *
+ * Currently used by upeek() only.
+ * TODO: use this in all other ptrace() calls while decoding.
+ */
+long
+do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
+{
+ long l;
+
+ errno = 0;
+ l = ptrace(request, tcp->pid, addr, (long) data);
+ /* Non-ESRCH errors might be our invalid reg/mem accesses,
+ * we do not record them. */
+ if (errno == ESRCH)
+ tcp->ptrace_errno = ESRCH;
+ return l;
+}
+
+/*
+ * Used when we want to unblock stopped traced process.
+ * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
+ * Returns 0 on success or if error was ESRCH
+ * (presumably process was killed while we talk to it).
+ * Otherwise prints error message and returns -1.
+ */
+int
+ptrace_restart(int op, struct tcb *tcp, int sig)
+{
+ int err;
+ const char *msg;
+
+ errno = 0;
+ ptrace(op, tcp->pid, (void *) 1, (long) sig);
+ err = errno;
+ if (!err || err == ESRCH)
+ return 0;
+
+ tcp->ptrace_errno = err;
+ msg = "SYSCALL";
+ if (op == PTRACE_CONT)
+ msg = "CONT";
+ if (op == PTRACE_DETACH)
+ msg = "DETACH";
+ fprintf(stderr, "strace: ptrace(PTRACE_%s,1,%d): %s\n",
+ msg, sig, strerror(err));
+ return -1;
+}
+
/*
* Print entry in struct xlat table, if there.
*/
void
-printxval(xlat, val, dflt)
-struct xlat *xlat;
-int val;
-char *dflt;
+printxval(const struct xlat *xlat, int val, const char *dflt)
{
- char *str = xlookup(xlat, val);
+ const char *str = xlookup(xlat, val);
if (str)
tprintf("%s", str);
tprintf("%#x /* %s */", val, dflt);
}
+#if HAVE_LONG_LONG
+/*
+ * Print 64bit argument at position llarg and return the index of the next
+ * argument.
+ */
+int
+printllval(struct tcb *tcp, const char *format, int llarg)
+{
+# if defined(FREEBSD) \
+ || (defined(LINUX) && defined(POWERPC) && !defined(POWERPC64)) \
+ || defined (LINUX_MIPSO32)
+ /* Align 64bit argument to 64bit boundary. */
+ if (llarg % 2) llarg++;
+# endif
+# if defined LINUX && (defined X86_64 || defined POWERPC64)
+ if (current_personality == 0) {
+ tprintf(format, tcp->u_arg[llarg]);
+ llarg++;
+ } else {
+# ifdef POWERPC64
+ /* Align 64bit argument to 64bit boundary. */
+ if (llarg % 2) llarg++;
+# endif
+ tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
+ llarg += 2;
+ }
+# elif defined IA64 || defined ALPHA
+ tprintf(format, tcp->u_arg[llarg]);
+ llarg++;
+# elif defined LINUX_MIPSN32
+ tprintf(format, tcp->ext_arg[llarg]);
+ llarg++;
+# else
+ tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
+ llarg += 2;
+# endif
+ return llarg;
+}
+#endif
+
/*
* Interpret `xlat' as an array of flags
* print the entries whose bits are on in `flags'
*/
int
addflags(xlat, flags)
-struct xlat *xlat;
+const struct xlat *xlat;
int flags;
{
int n;
return n;
}
+/*
+ * Interpret `xlat' as an array of flags/
+ * Print to static string the entries whose bits are on in `flags'
+ * Return static string.
+ */
+const char *
+sprintflags(const char *prefix, const struct xlat *xlat, int flags)
+{
+ static char outstr[1024];
+ int found = 0;
+
+ strcpy(outstr, prefix);
+
+ for (; xlat->str; xlat++) {
+ if ((flags & xlat->val) == xlat->val) {
+ if (found)
+ strcat(outstr, "|");
+ strcat(outstr, xlat->str);
+ flags &= ~xlat->val;
+ found = 1;
+ }
+ }
+ if (flags) {
+ if (found)
+ strcat(outstr, "|");
+ sprintf(outstr + strlen(outstr), "%#x", flags);
+ }
+
+ return outstr;
+}
+
int
-printflags(xlat, flags)
-struct xlat *xlat;
-int flags;
+printflags(const struct xlat *xlat, int flags, const char *dflt)
{
int n;
- char *sep;
+ const char *sep;
if (flags == 0 && xlat->val == 0) {
tprintf("%s", xlat->str);
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;
}
void
-printnum(tcp, addr, fmt)
-struct tcb *tcp;
-long addr;
-char *fmt;
+printnum(struct tcb *tcp, long addr, const char *fmt)
+{
+ long num;
+
+ if (!addr) {
+ tprintf("NULL");
+ return;
+ }
+ if (umove(tcp, addr, &num) < 0) {
+ tprintf("%#lx", addr);
+ return;
+ }
+ tprintf("[");
+ tprintf(fmt, num);
+ tprintf("]");
+}
+
+void
+printnum_int(struct tcb *tcp, long addr, const char *fmt)
{
int num;
tprintf("]");
}
-static char path[MAXPATHLEN + 1];
+void
+printfd(struct tcb *tcp, int fd)
+{
+ tprintf("%d", fd);
+}
void
-string_quote(str)
-char *str;
+printuid(text, uid)
+const char *text;
+unsigned long uid;
{
- char buf[2 * MAXPATHLEN + 1];
- char *s;
+ tprintf("%s", text);
+ tprintf((uid == -1) ? "%ld" : "%lu", uid);
+}
- if (!strpbrk(str, "\"\'\\")) {
- tprintf("\"%s\"", str);
- return;
+static char path[MAXPATHLEN + 1];
+
+/*
+ * Quote string `instr' of length `size'
+ * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
+ * If `len' < 0, treat `instr' as a NUL-terminated string
+ * and quote at most (`size' - 1) bytes.
+ */
+static int
+string_quote(const char *instr, char *outstr, int len, int size)
+{
+ const unsigned char *ustr = (const unsigned char *) instr;
+ char *s = outstr;
+ int usehex = 0, c, i;
+
+ if (xflag > 1)
+ usehex = 1;
+ else if (xflag) {
+ /* Check for presence of symbol which require
+ to hex-quote the whole string. */
+ for (i = 0; i < size; ++i) {
+ c = ustr[i];
+ /* Check for NUL-terminated string. */
+ if (len < 0) {
+ if (c == '\0')
+ break;
+ /* Quote at most size - 1 bytes. */
+ if (i == size - 1)
+ continue;
+ }
+ if (!isprint(c) && !isspace(c)) {
+ usehex = 1;
+ break;
+ }
+ }
}
- for (s = buf; *str; str++) {
- switch (*str) {
- case '\"': case '\'': case '\\':
- *s++ = '\\'; *s++ = *str; break;
- default:
- *s++ = *str; break;
+
+ *s++ = '\"';
+
+ if (usehex) {
+ /* Hex-quote the whole string. */
+ for (i = 0; i < size; ++i) {
+ c = ustr[i];
+ /* Check for NUL-terminated string. */
+ if (len < 0) {
+ if (c == '\0')
+ break;
+ /* Quote at most size - 1 bytes. */
+ if (i == size - 1)
+ continue;
+ }
+ sprintf(s, "\\x%02x", c);
+ s += 4;
+ }
+ } else {
+ for (i = 0; i < size; ++i) {
+ c = ustr[i];
+ /* Check for NUL-terminated string. */
+ if (len < 0) {
+ if (c == '\0')
+ break;
+ /* Quote at most size - 1 bytes. */
+ if (i == size - 1)
+ continue;
+ }
+ switch (c) {
+ case '\"': case '\\':
+ *s++ = '\\';
+ *s++ = c;
+ break;
+ case '\f':
+ *s++ = '\\';
+ *s++ = 'f';
+ break;
+ case '\n':
+ *s++ = '\\';
+ *s++ = 'n';
+ break;
+ case '\r':
+ *s++ = '\\';
+ *s++ = 'r';
+ break;
+ case '\t':
+ *s++ = '\\';
+ *s++ = 't';
+ break;
+ case '\v':
+ *s++ = '\\';
+ *s++ = 'v';
+ break;
+ default:
+ if (isprint(c))
+ *s++ = c;
+ else if (i + 1 < size
+ && isdigit(ustr[i + 1])) {
+ sprintf(s, "\\%03o", c);
+ s += 4;
+ } else {
+ sprintf(s, "\\%o", c);
+ s += strlen(s);
+ }
+ break;
+ }
}
}
+
+ *s++ = '\"';
*s = '\0';
- tprintf("\"%s\"", buf);
+
+ /* Return nonzero if the string was unterminated. */
+ return i == size;
}
+/*
+ * Print path string specified by address `addr' and length `n'.
+ * If path length exceeds `n', append `...' to the output.
+ */
void
-printpath(tcp, addr)
-struct tcb *tcp;
-long addr;
+printpathn(struct tcb *tcp, long addr, int n)
{
- if (umovestr(tcp, addr, MAXPATHLEN, path) < 0)
+ if (!addr) {
+ tprintf("NULL");
+ return;
+ }
+
+ /* Cap path length to the path buffer size,
+ and NUL-terminate the buffer. */
+ if (n > sizeof path - 1)
+ n = sizeof path - 1;
+ path[n] = '\0';
+
+ /* Fetch one byte more to find out whether path length > n. */
+ if (umovestr(tcp, addr, n + 1, path) < 0)
tprintf("%#lx", addr);
- else
- string_quote(path);
- return;
+ else {
+ static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
+ int trunc = (path[n] != '\0');
+
+ if (trunc)
+ path[n] = '\0';
+ (void) string_quote(path, outstr, -1, n + 1);
+ if (trunc)
+ strcat(outstr, "...");
+ tprintf("%s", outstr);
+ }
}
void
-printpathn(tcp, addr, n)
-struct tcb *tcp;
-long addr;
-int n;
+printpath(struct tcb *tcp, long addr)
{
- if (umovestr(tcp, addr, n, path) < 0)
- tprintf("%#lx", addr);
- else {
- path[n] = '\0';
- string_quote(path);
- }
+ printpathn(tcp, addr, sizeof path - 1);
}
+/*
+ * Print string specified by address `addr' and length `len'.
+ * If `len' < 0, treat the string as a NUL-terminated string.
+ * If string length exceeds `max_strlen', append `...' to the output.
+ */
void
-printstr(tcp, addr, len)
-struct tcb *tcp;
-long addr;
-int len;
+printstr(struct tcb *tcp, long addr, int len)
{
- static unsigned char *str = NULL;
+ static char *str = NULL;
static char *outstr;
- int i, n, c, usehex;
- char *s, *outend;
+ int size;
if (!addr) {
tprintf("NULL");
return;
}
- if (!str) {
- if ((str = malloc(max_strlen)) == NULL
- || (outstr = malloc(2*max_strlen)) == NULL) {
- fprintf(stderr, "printstr: no memory\n");
- tprintf("%#lx", addr);
- return;
- }
+ /* Allocate static buffers if they are not allocated yet. */
+ if (!str)
+ str = malloc(max_strlen + 1);
+ if (!outstr)
+ outstr = malloc(4 * max_strlen + sizeof "\"...\"");
+ if (!str || !outstr) {
+ fprintf(stderr, "out of memory\n");
+ tprintf("%#lx", addr);
+ return;
}
- outend = outstr + max_strlen * 2 - 10;
+
if (len < 0) {
- n = max_strlen;
- if (umovestr(tcp, addr, n, (char *) str) < 0) {
+ /*
+ * Treat as a NUL-terminated string: fetch one byte more
+ * because string_quote() quotes one byte less.
+ */
+ size = max_strlen + 1;
+ str[max_strlen] = '\0';
+ if (umovestr(tcp, addr, size, str) < 0) {
tprintf("%#lx", addr);
return;
}
}
else {
- n = MIN(len, max_strlen);
- if (umoven(tcp, addr, n, (char *) str) < 0) {
+ size = MIN(len, max_strlen);
+ if (umoven(tcp, addr, size, str) < 0) {
tprintf("%#lx", addr);
return;
}
}
- usehex = 0;
- if (xflag > 1)
- usehex = 1;
- else if (xflag) {
- for (i = 0; i < n; i++) {
- c = str[i];
- if (len < 0 && c == '\0')
- break;
- if (!isprint(c) && !isspace(c)) {
- usehex = 1;
- break;
- }
- }
- }
+ if (string_quote(str, outstr, len, size) &&
+ (len < 0 || len > max_strlen))
+ strcat(outstr, "...");
- s = outstr;
- *s++ = '\"';
+ tprintf("%s", outstr);
+}
- if (usehex) {
- for (i = 0; i < n; i++) {
- c = str[i];
- if (len < 0 && c == '\0')
- break;
- sprintf(s, "\\x%02x", c);
- s += 4;
- if (s > outend)
- break;
- }
+#if HAVE_SYS_UIO_H
+void
+dumpiov(tcp, len, addr)
+struct tcb * tcp;
+int len;
+long addr;
+{
+#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
+ union {
+ struct { u_int32_t base; u_int32_t len; } *iov32;
+ struct { u_int64_t base; u_int64_t len; } *iov64;
+ } iovu;
+#define iov iovu.iov64
+#define sizeof_iov \
+ (personality_wordsize[current_personality] == 4 \
+ ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
+#define iov_iov_base(i) \
+ (personality_wordsize[current_personality] == 4 \
+ ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
+#define iov_iov_len(i) \
+ (personality_wordsize[current_personality] == 4 \
+ ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
+#else
+ struct iovec *iov;
+#define sizeof_iov sizeof(*iov)
+#define iov_iov_base(i) iov[i].iov_base
+#define iov_iov_len(i) iov[i].iov_len
+#endif
+ int i;
+ unsigned long size;
+
+ size = sizeof_iov * (unsigned long) len;
+ if (size / sizeof_iov != len
+ || (iov = malloc(size)) == NULL) {
+ fprintf(stderr, "out of memory\n");
+ return;
}
- else {
- for (i = 0; i < n; i++) {
- c = str[i];
- if (len < 0 && c == '\0')
- break;
- switch (c) {
- case '\"': case '\'': case '\\':
- *s++ = '\\'; *s++ = c; break;
- case '\f':
- *s++ = '\\'; *s++ = 'f'; break;
- case '\n':
- *s++ = '\\'; *s++ = 'n'; break;
- case '\r':
- *s++ = '\\'; *s++ = 'r'; break;
- case '\t':
- *s++ = '\\'; *s++ = 't'; break;
- case '\v':
- *s++ = '\\'; *s++ = 'v'; break;
- default:
- if (isprint(c))
- *s++ = c;
- else if (i < n - 1 && isdigit(str[i + 1])) {
- sprintf(s, "\\%03o", c);
- s += 4;
- }
- else {
- sprintf(s, "\\%o", c);
- s += strlen(s);
- }
- break;
- }
- if (s > outend)
- break;
+ 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_iov_len(i), i);
+ dumpstr(tcp, (long) iov_iov_base(i),
+ iov_iov_len(i));
}
}
-
- *s++ = '\"';
- if (i < len || (len < 0 && (i == n || s > outend))) {
- *s++ = '.'; *s++ = '.'; *s++ = '.';
- }
- *s = '\0';
- tprintf("%s", outstr);
+ free((char *) iov);
+#undef sizeof_iov
+#undef iov_iov_base
+#undef iov_iov_len
+#undef iov
}
+#endif
void
dumpstr(tcp, addr, 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;
* at address `addr' to our space at `laddr'
*/
int
-umoven(tcp, addr, len, laddr)
-struct tcb *tcp;
-long addr;
-int len;
-char *laddr;
+umoven(struct tcb *tcp, long addr, int len, char *laddr)
{
-
#ifdef LINUX
int pid = tcp->pid;
int n, m;
return 0;
}
/* But if not started, we had a bogus address. */
- perror("ptrace: umoven");
+ if (addr != 0 && errno != EIO && errno != ESRCH)
+ perror("ptrace: umoven");
return -1;
}
started = 1;
/* Ran into 'end of memory' - stupid "printpath" */
return 0;
}
- perror("ptrace: umoven");
+ if (addr != 0 && errno != EIO && errno != ESRCH)
+ perror("ptrace: umoven");
return -1;
}
started = 1;
#ifdef SUNOS4
int pid = tcp->pid;
-#if 0
- int n, m;
- union {
- long val;
- char x[sizeof(long)];
- } u;
-
- if (addr & (sizeof(long) - 1)) {
- /* addr not a multiple of sizeof(long) */
- n = addr - (addr & -sizeof(long)); /* residue */
- addr &= -sizeof(long); /* residue */
- errno = 0;
- u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
- if (errno) {
- perror("umoven");
- return -1;
- }
- memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
- addr += sizeof(long), laddr += m, len -= m;
- }
- while (len) {
- errno = 0;
- u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
- if (errno) {
- perror("umoven");
- return -1;
- }
- memcpy(laddr, u.x, m = MIN(sizeof(long), len));
- addr += sizeof(long), laddr += m, len -= m;
- }
-#else /* !oldway */
int n;
while (len) {
n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
if (ptrace(PTRACE_READDATA, pid,
(char *) addr, len, laddr) < 0) {
- perror("umoven: ptrace(PTRACE_READDATA, ...)");
- abort();
+ if (errno != ESRCH) {
+ perror("umoven: ptrace(PTRACE_READDATA, ...)");
+ abort();
+ }
return -1;
}
len -= n;
addr += n;
laddr += n;
}
-#endif /* !oldway */
#endif /* SUNOS4 */
-#ifdef SVR4
-/*
- * 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
+#ifdef USE_PROCFS
+#ifdef HAVE_MP_PROCFS
+ int fd = tcp->pfd_as;
+#else
+ 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 */
+#endif /* USE_PROCFS */
return 0;
}
* for a terminating zero byte.
*/
int
-umovestr(tcp, addr, len, laddr)
-struct tcb *tcp;
-long addr;
-int len;
-char *laddr;
+umovestr(struct tcb *tcp, long addr, 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;
/* Ran into 'end of memory' - stupid "printpath" */
return 0;
}
- perror("umovestr");
+ if (addr != 0 && errno != EIO && errno != ESRCH)
+ perror("umovestr");
return -1;
}
started = 1;
/* Ran into 'end of memory' - stupid "printpath" */
return 0;
}
- perror("umovestr");
+ if (addr != 0 && errno != EIO && errno != ESRCH)
+ perror("umovestr");
return -1;
}
started = 1;
addr += sizeof(long), laddr += m, len -= m;
}
+#endif /* !USE_PROCFS */
return 0;
-#endif /* !SVR4 */
}
#ifdef LINUX
-#ifndef SPARC
-#define PTRACE_WRITETEXT 101
-#define PTRACE_WRITEDATA 102
-#endif /* !SPARC */
+# if !defined (SPARC) && !defined(SPARC64)
+# define PTRACE_WRITETEXT 101
+# define PTRACE_WRITEDATA 102
+# endif /* !SPARC && !SPARC64 */
#endif /* LINUX */
#ifdef SUNOS4
int len;
char *laddr;
{
-#if 0
- int n;
-
- while (len) {
- n = MIN(len, PAGSIZ);
- n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
- if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
- perror("uload: ptrace(PTRACE_WRITE, ...)");
- return -1;
- }
- len -= n;
- addr += n;
- laddr += n;
- }
-#else
int peek, poke;
int n, m;
union {
}
addr += sizeof(long), laddr += m, len -= m;
}
-#endif
return 0;
}
#endif /* SUNOS4 */
-#ifndef SVR4
+#ifndef USE_PROCFS
int
-upeek(pid, off, res)
-int pid;
+upeek(tcp, off, res)
+struct tcb *tcp;
long off;
long *res;
{
long val;
-#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
+# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
{
static int is_sun4m = -1;
struct utsname name;
}
is_sun4m = strcmp(name.machine, "sun4m") == 0;
if (is_sun4m) {
- extern struct xlat struct_user_offsets[];
- struct xlat *x;
+ const struct xlat *x;
for (x = struct_user_offsets; x->str; x++)
x->val += 1024;
if (is_sun4m)
off += 1024;
}
-#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
+# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
errno = 0;
- val = ptrace(PTRACE_PEEKUSER, pid, (char *) off, 0);
+ val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
if (val == -1 && errno) {
- perror("upeek: ptrace(PTRACE_PEEKUSER, ... )");
+ if (errno != ESRCH) {
+ char buf[60];
+ sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
+ perror(buf);
+ }
return -1;
}
*res = val;
return 0;
}
-#endif /* !SVR4 */
+#endif /* !USE_PROCFS */
-long
-getpc(tcp)
-struct tcb *tcp;
+void
+printcall(struct tcb *tcp)
{
+#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
+ sizeof(long) == 8 ? "[????????????????] " : \
+ NULL /* crash */)
#ifdef LINUX
- long pc;
-
-#ifdef I386
- if (upeek(tcp->pid, 4*EIP, &pc) < 0)
- return -1;
-#else /* !I386 */
-#ifdef ARM
- if (upeek(tcp->pid, 4*15, &pc) < 0)
- return -1;
-#else /* !ARM */
-#ifdef POWERPC
- if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
- return -1;
-#else
-#ifdef M68K
- if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
- return -1;
-#else /* !M68K */
-#ifdef ALPHA
- if (upeek(tcp->pid, REG_PC, &pc) < 0)
- return -1;
-#else /* !ALPHA */
-#ifdef SPARC
- struct pt_regs regs;
- if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)®s,0) < 0)
- return -1;
- pc = regs.pc;
-#endif /* SPARC */
-#endif /* ALPHA */
-#endif /* !M68K */
-#endif /* !POWERPC */
-#endif /* !ARM */
-#endif /* !I386 */
- return pc;
-#endif /* LINUX */
+# ifdef I386
+ long eip;
-#ifdef SUNOS4
- /*
- * Return current program counter for `pid'
- * Assumes PC is never 0xffffffff
- */
- struct regs regs;
+ if (upeek(tcp, 4*EIP, &eip) < 0) {
+ PRINTBADPC;
+ return;
+ }
+ tprintf("[%08lx] ", eip);
- if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) ®s, 0) < 0) {
- perror("getpc: ptrace(PTRACE_GETREGS, ...)");
- return -1;
+# elif defined(S390) || defined(S390X)
+ long psw;
+ if(upeek(tcp,PT_PSWADDR,&psw) < 0) {
+ PRINTBADPC;
+ return;
}
- return regs.r_pc;
-#endif /* SUNOS4 */
+# ifdef S390
+ tprintf("[%08lx] ", psw);
+# elif S390X
+ tprintf("[%16lx] ", psw);
+# endif
-#ifdef SVR4
- /* XXX */
- return 0;
-#endif /* SVR4 */
+# elif defined(X86_64)
+ long rip;
-}
+ if (upeek(tcp, 8*RIP, &rip) < 0) {
+ PRINTBADPC;
+ return;
+ }
+ tprintf("[%16lx] ", rip);
+# elif defined(IA64)
+ long ip;
-void
-printcall(tcp)
-struct tcb *tcp;
-{
+ if (upeek(tcp, PT_B0, &ip) < 0) {
+ PRINTBADPC;
+ return;
+ }
+ tprintf("[%08lx] ", ip);
+# elif defined(POWERPC)
+ long pc;
-#ifdef LINUX
-#ifdef I386
- long eip;
+ if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
+ PRINTBADPC;
+ return;
+ }
+# ifdef POWERPC64
+ tprintf("[%016lx] ", pc);
+# else
+ tprintf("[%08lx] ", pc);
+# endif
+# elif defined(M68K)
+ long pc;
- if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
- tprintf("[????????] ");
+ if (upeek(tcp, 4*PT_PC, &pc) < 0) {
+ tprintf ("[????????] ");
return;
}
- tprintf("[%08lx] ", eip);
-#else /* !I386K */
-#ifdef POWERPC
+ tprintf("[%08lx] ", pc);
+# elif defined(ALPHA)
long pc;
- if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0) {
+ if (upeek(tcp, REG_PC, &pc) < 0) {
+ tprintf ("[????????????????] ");
+ return;
+ }
+ tprintf("[%08lx] ", pc);
+# elif defined(SPARC) || defined(SPARC64)
+ struct pt_regs regs;
+ if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)®s,0) < 0) {
+ PRINTBADPC;
+ return;
+ }
+# if defined(SPARC64)
+ tprintf("[%08lx] ", regs.tpc);
+# else
+ tprintf("[%08lx] ", regs.pc);
+# endif
+# elif defined(HPPA)
+ long pc;
+
+ if(upeek(tcp,PT_IAOQ0,&pc) < 0) {
tprintf ("[????????] ");
return;
}
tprintf("[%08lx] ", pc);
-#else /* !POWERPC */
-#ifdef M68K
+# elif defined(MIPS)
long pc;
- if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
+ if (upeek(tcp, REG_EPC, &pc) < 0) {
tprintf ("[????????] ");
return;
}
tprintf("[%08lx] ", pc);
-#else /* !M68K */
-#ifdef ALPHA
+# elif defined(SH)
long pc;
- if (upeek(tcp->pid, REG_PC, &pc) < 0) {
+ if (upeek(tcp, 4*REG_PC, &pc) < 0) {
tprintf ("[????????] ");
return;
}
tprintf("[%08lx] ", pc);
-#else /* !ALPHA */
-#ifdef SPARC
- struct pt_regs regs;
- if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)®s,0) < 0) {
+# elif defined(SH64)
+ long pc;
+
+ if (upeek(tcp, REG_PC, &pc) < 0) {
+ tprintf ("[????????????????] ");
+ return;
+ }
+ tprintf("[%08lx] ", pc);
+# elif defined(ARM)
+ long pc;
+
+ if (upeek(tcp, 4*15, &pc) < 0) {
+ PRINTBADPC;
+ return;
+ }
+ tprintf("[%08lx] ", pc);
+# elif defined(AVR32)
+ long pc;
+
+ if (upeek(tcp, REG_PC, &pc) < 0) {
tprintf("[????????] ");
return;
}
- tprintf("[%08lx] ", regs.pc);
-#endif /* SPARC */
-#endif /* ALPHA */
-#endif /* !M68K */
-#endif /* !POWERPC */
-#endif /* !I386 */
+ tprintf("[%08lx] ", pc);
+# elif defined(BFIN)
+ long pc;
+
+ if (upeek(tcp, PT_PC, &pc) < 0) {
+ PRINTBADPC;
+ return;
+ }
+ tprintf("[%08lx] ", pc);
+#elif defined(CRISV10)
+ long pc;
+
+ if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
+ PRINTBADPC;
+ return;
+ }
+ tprintf("[%08lx] ", pc);
+#elif defined(CRISV32)
+ long pc;
+
+ if (upeek(tcp, 4*PT_ERP, &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 SVR4
-int
-setbpt(tcp)
-struct tcb *tcp;
-{
+/*
+ * These #if's are huge, please indent them correctly.
+ * It's easy to get confused otherwise.
+ */
+#ifndef USE_PROCFS
#ifdef LINUX
-#ifdef SPARC
- /* We simply use the SunOS breakpoint code. */
- struct pt_regs regs;
-#define LOOPA 0x30800000 /* ba,a 0 */
+# include "syscall.h"
- if (tcp->flags & TCB_BPTSET) {
- fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
- return -1;
+# include <sys/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
+# ifndef CLONE_STOPPED
+# define CLONE_STOPPED 0x02000000
+# 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 cfm, sof, sol;
+ long bsp;
+
+ if (ia32) {
+ /* Satisfy a false GCC warning. */
+ *state = NULL;
+ return 0;
}
- if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) {
- perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
+
+ if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
return -1;
- }
- memmove (®s.u_regs [1], ®s.u_regs [0],
- sizeof (regs.u_regs) - sizeof (regs.u_regs [0]));
- tcp->baddr = regs.u_regs[UREG_I7] + 8;
+ if (upeek(tcp, 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
+
+# ifdef SYS_fork
+static int
+get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
+{
+ int ret;
+
+ if (ia32)
+ ret = upeek (tcp, 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, 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;
- tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
- if(errno) {
- perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
+ 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;
+}
+
+/* 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)
+
+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 (AVR32)
+# define arg0_offset (REG_R12)
+# define arg1_offset (REG_R11)
+# 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
+# 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), arg0_offset, (valp)))
+# define get_arg1(tcp, cookie, valp) \
+ (upeek ((tcp), 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
+
+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;
}
/*
- * XXX - BRUTAL MODE ON
- * We cannot set a real BPT in the child, since it will not be
- * traced at the moment it will reach the trap and would probably
- * die with a core dump.
- * Thus, we are force our way in by taking out two instructions
- * and insert an eternal loop instead, in expectance of the SIGSTOP
- * generated by out PTRACE_ATTACH.
- * Of cause, if we evaporate ourselves in the middle of all this...
+ * 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.
*/
- errno = 0;
- ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOPA);
- if(errno) {
- perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
- return -1;
+ if (clone_scno[current_personality] == 0) {
+ int i;
+ for (i = 0; i < nsyscalls; ++i)
+ if (sysent[i].sys_func == sys_clone) {
+ clone_scno[current_personality] = i;
+ break;
+ }
}
- tcp->flags |= TCB_BPTSET;
-#else /* !SPARC */
-
-#if defined (I386)
-#define LOOP 0x0000feeb
-#elif defined (M68K)
-#define LOOP 0x60fe0000
-#elif defined (ALPHA)
-#define LOOP 0xc3ffffff
-#elif defined (POWERPC)
-#define LOOP 0x0000feeb
-#elif defined(ARM)
-#define LOOP -1 /* almost certainly wrong, jws */
-#else
-#error unknown architecture
-#endif
+ switch (known_scno(tcp)) {
+# 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, 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;
+# endif
+
+ case SYS_clone:
+# ifdef SYS_clone2
+ case SYS_clone2:
+# endif
+ /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
+ contrary to x86 SYS_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. */
+
+ if ((arg_setup (tcp, &state) < 0
+ || set_arg0 (tcp, &state,
+ (tcp->u_arg[arg0_index] | CLONE_PTRACE)
+ & ~(tcp->u_arg[arg0_index] & CLONE_VFORK
+ ? CLONE_VFORK | CLONE_VM : 0)) < 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;
- if (tcp->flags & TCB_BPTSET) {
- fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
- return -1;
+ default:
+ fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
+ tcp->scno, tcp->pid);
+ break;
}
-#if defined (I386)
- if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
- return -1;
-#elif defined (M68K)
- if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
- return -1;
-#elif defined (ALPHA)
- return -1;
-#elif defined (ARM)
+
return -1;
-#elif defined (POWERPC)
- if (upeek(tcp->pid, 4*PT_NIP, &tcp->baddr) < 0)
- return -1;
-#else
-#error unknown architecture
-#endif
- 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;
+}
-#endif /* SPARC */
-#endif /* LINUX */
+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))
+ if (errno != ESRCH) return -1;
+ tcp->flags &= ~TCB_BPTSET;
+ return 0;
+}
-#ifdef SUNOS4
-#ifdef SPARC /* This code is slightly sparc specific */
+# else /* !defined LINUX */
- struct pt_regs regs;
-#define BPT 0x91d02001 /* ta 1 */
-#define LOOP 0x10800000 /* ba 0 */
-#define LOOPA 0x30800000 /* ba,a 0 */
-#define NOP 0x01000000
-#if LOOPA
+int
+setbpt(tcp)
+struct tcb *tcp;
+{
+# ifdef SUNOS4
+# ifdef SPARC /* This code is slightly sparc specific */
+
+ struct regs regs;
+# define BPT 0x91d02001 /* ta 1 */
+# define LOOP 0x10800000 /* ba 0 */
+# define LOOPA 0x30800000 /* ba,a 0 */
+# define NOP 0x01000000
+# if LOOPA
static int loopdeloop[1] = {LOOPA};
-#else
+# else
static int loopdeloop[2] = {LOOP, NOP};
-#endif
+# endif
if (tcp->flags & TCB_BPTSET) {
fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
}
tcp->flags |= TCB_BPTSET;
-#endif /* SPARC */
-#endif /* SUNOS4 */
+# endif /* SPARC */
+# endif /* SUNOS4 */
return 0;
}
clearbpt(tcp)
struct tcb *tcp;
{
+# ifdef SUNOS4
+# ifdef SPARC
-#ifdef LINUX
-#ifdef I386
- long eip;
-#else /* !I386 */
-#ifdef POWERPC
- long pc;
-#else /* !POWERPC */
-#ifdef M68K
- long pc;
-#else /* !M68K */
-#ifdef ALPHA
- long pc;
-#endif /* ALPHA */
-#endif /* !M68K */
-#endif /* !POWERPC */
-#endif /* !I386 */
-
-#ifdef SPARC
- /* 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;
- }
- 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;
-#else /* !SPARC */
-
- 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;
-
-#ifdef I386
- if (upeek(tcp->pid, 4*EIP, &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;
- }
-#else /* !I386 */
-#ifdef POWERPC
- if (upeek(tcp->pid, 4*PT_NIP, &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;
- }
-#else /* !POWERPC */
-#ifdef M68K
- if (upeek(tcp->pid, 4*PT_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;
- }
-#else /* !M68K */
-#ifdef ALPHA
- if (upeek(tcp->pid, 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 /* ALPHA */
-#endif /* !M68K */
-#endif /* !POWERPC */
-#endif /* !I386 */
-#endif /* !SPARC */
-#endif /* LINUX */
-
-#ifdef SUNOS4
-#ifdef SPARC
-
-#if !LOOPA
- struct pt_regs regs;
-#endif
+# if !LOOPA
+ struct regs regs;
+# endif
if (!(tcp->flags & TCB_BPTSET)) {
fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
}
tcp->flags &= ~TCB_BPTSET;
-#if !LOOPA
+# if !LOOPA
/*
* Since we don't have a single instruction breakpoint, we may have
- * to adjust the program counter after removing the our `breakpoint'.
+ * to adjust the program counter after removing our `breakpoint'.
*/
if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) {
perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
if (debug)
fprintf(stderr,
"NOTE: PC not at bpt (pc %#x baddr %#x)\n",
- regs.r_pc, tcp->parent->baddr);
+ regs.r_pc, tcp->baddr);
return 0;
}
if (regs.r_pc != tcp->baddr)
perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
return -1;
}
-#endif /* LOOPA */
-#endif /* SPARC */
-#endif /* SUNOS4 */
+# endif /* LOOPA */
+# endif /* SPARC */
+# endif /* SUNOS4 */
return 0;
}
-#endif /* !SVR4 */
+# endif /* !defined LINUX */
+
+#endif /* !USE_PROCFS */
+
#ifdef SUNOS4
static int
-getex(pid, hdr)
-int pid;
+getex(tcp, hdr)
+struct tcb *tcp;
struct exec *hdr;
{
int n;
for (n = 0; n < sizeof *hdr; n += 4) {
long res;
- if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
+ if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
return -1;
memcpy(((char *) hdr) + n, &res, 4);
}
struct link_dynamic_2 ld;
char *strtab, *cp;
- if (getex(pid, &hdr) < 0)
+ if (getex(tcp, &hdr) < 0)
return -1;
if (!hdr.a_dynamic)
return -1;
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),
(int)ld.ld_symb_size, strtab) < 0)
goto err;
-#if 0
- for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
- fprintf(stderr, "[symbol: %s]\n", cp);
- cp += strlen(cp)+1;
- }
- return 0;
-#endif
for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
if (strcmp(cp, "_vfork") == 0) {
if (debug)