home *** CD-ROM | disk | FTP | other *** search
- /*
- * @(#)util.c 2.3 92/01/10
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/ptrace.h>
- #include <sys/user.h>
- #include <machine/reg.h>
- #include <a.out.h>
- #include <link.h>
-
- #include "defs.h"
-
- u_int max_str_len = DFLT_STR_LEN;
-
- char *
- xlookup(xlat, val)
- Xlat *xlat;
- {
- for (; xlat->str != NULL; xlat++)
- if (xlat->val == val)
- return xlat->str;
-
- return NULL;
- }
-
- /*
- * Print entry in Xlat table, if there.
- */
- void
- printxval(xlat, val, dflt)
- Xlat *xlat;
- char *dflt;
- {
- char *str = xlookup(xlat, val);
-
- if (str)
- tprintf("%s", str);
- else
- tprintf("%s(%#x)", dflt, val);
- }
-
- /*
- * interpret `xlat' as an array of flags
- * print the entries whose bits are on in `flags'
- * return # of flags printed
- */
- int
- addflags(xlat, flags)
- Xlat *xlat;
- int flags;
- {
- int n;
-
- for (n = 0; xlat->str; xlat++) {
- if (flags & xlat->val) {
- tprintf("|%s", xlat->str);
- n++;
- }
- }
- return n;
- }
-
- int
- printflags(xlat, flags)
- Xlat *xlat;
- int flags;
- {
- int n;
- char *format;
-
- format = "%s";
- for (n = 0; xlat->str; xlat++) {
- if (flags & xlat->val) {
- tprintf(format, xlat->str);
- n++;
- format = "|%s";
- }
- }
- return n;
- }
-
- int
- printstr(pid, addr, len)
- {
- static unsigned char *str;
- int i, n, c;
-
- if (addr == 0) {
- tprintf("(caddr_t)0");
- return 0;
- }
- if (str == (unsigned char *)0) {
- if ((str = (unsigned char *)malloc(max_str_len)) == NULL) {
- (void)fprintf(stderr, "printstr: no memory\n");
- return -1;
- }
- }
-
- if (len < 0) {
- if (umovestr(pid, addr, n = (int)max_str_len, (char *)str) < 0) {
- tprintf("%#x", addr);
- return -1;
- }
- } else {
- if (umove(pid, addr, n = MIN(len, (int)max_str_len), (char *)str) < 0) {
- tprintf("%#x", addr);
- return -1;
- }
- }
-
- tprintf("\"");
- for (i = 0; i < n; i++) {
- if (len < 0)
- if (str[i] == '\0')
- break;
- switch (c = str[i]) {
- case '\n':
- tprintf("\\n");
- break;
- case '\t':
- tprintf("\\t");
- break;
- case '\r':
- tprintf("\\r");
- break;
- default:
- if (isprint(c)) {
- tprintf("%c", c);
- } else {
- tprintf("\\%x", c);
- }
- break;
- }
-
- }
- tprintf("\"");
- if (n < len || (len < 0 && i >= n)) {
- tprintf("..");
- }
- return 0;
- }
-
- #define PAGMASK (~(PAGSIZ - 1))
- /*
- * move `len' bytes of data from process `pid'
- * at address `addr' to our space at `laddr'
- */
- int
- umove(pid, addr, len, laddr)
- int pid;
- int addr, len;
- char *laddr;
- {
- #if 1
- int n;
-
- while (len) {
- n = MIN(len, PAGSIZ);
- n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
- if (ptrace(PTRACE_READDATA, pid, (char *)addr, len, laddr) < 0) {
- perror("umove: ptrace(PTRACE_READDATA,..");
- abort();
- return -1;
- }
- len -= n;
- addr += n;
- laddr += n;
- }
- #else
- int n, m;
- union {
- int val;
- char x[4];
- } u;
-
- if (addr & 3) /* addr not a multiple of 4 */ {
- n = addr - (addr & -4); /* residue */
- addr &= -4; /* residue */
- u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
- bcopy(&u.x[n], laddr, m = MIN(4-n,len));
- addr += 4, laddr += m, len -= m;
- }
- while (len) {
- u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
- bcopy(u.x, laddr, m = MIN(4,len));
- addr += 4, laddr += m, len -= m;
- }
- #endif
- return 0;
- }
-
- /*
- * like `umove' but make the additional effort of looking
- * for a terminating zero byte.
- */
- int
- umovestr(pid, addr, len, laddr)
- int pid;
- int addr, len;
- char *laddr;
- {
- int i, n, m;
- union {
- int val;
- char x[4];
- } u;
-
- if (addr & 3) /* addr not a multiple of 4 */ {
- n = addr - (addr & -4); /* residue */
- addr &= -4; /* residue */
- errno = 0;
- u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
- if (errno) {
- perror("umovestr");
- return -1;
- }
- bcopy(&u.x[n], laddr, m = MIN(4-n,len));
- while (n & 3)
- if (u.x[n++] == '\0')
- return 0;
- addr += 4, laddr += m, len -= m;
- }
- while (len) {
- errno = 0;
- u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
- if (errno) {
- perror("umovestr");
- return -1;
- }
- bcopy(u.x, laddr, m = MIN(4,len));
- for (i = 0; i < 4; i++)
- if (u.x[i] == '\0')
- return 0;
-
- addr += 4, laddr += m, len -= m;
- }
- return 0;
- }
-
- static int
- uload(cmd, pid, addr, len, laddr)
- enum ptracereq cmd;
- int pid;
- int addr, 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
- enum ptracereq peek = cmd==PTRACE_WRITETEXT?
- PTRACE_PEEKTEXT:PTRACE_PEEKDATA;
- enum ptracereq poke = cmd==PTRACE_WRITETEXT?
- PTRACE_POKETEXT:PTRACE_POKEDATA;
- int n, m;
- union {
- int val;
- char x[4];
- } u;
-
- if (addr & 3) /* addr not a multiple of 4 */ {
- n = addr - (addr & -4); /* residue */
- addr &= -4;
- u.val = ptrace(peek, pid, (char *)addr, 0);
- bcopy(laddr, &u.x[n], m = MIN(4-n,len));
- if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
- perror("uload: POKE");
- return -1;
- }
- addr += 4, laddr += m, len -= m;
- }
- while (len) {
- if (len < 4) {
- u.val = ptrace(peek, pid, (char *)addr, 0);
- }
- bcopy(laddr, u.x, m = MIN(4,len));
- if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
- perror("uload: POKE");
- return -1;
- }
- addr += 4, laddr += m, len -= m;
- }
- #endif
- return 0;
- }
-
- int
- tload(pid, addr, len, laddr)
- int pid;
- int addr, len;
- char *laddr;
- {
- return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
- }
-
- int
- dload(pid, addr, len, laddr)
- int pid;
- int addr, len;
- char *laddr;
- {
- return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
- }
-
- int
- upeek(pid, off, res)
- unsigned int off;
- int *res;
- {
- int val;
-
- errno = 0;
- val = ptrace(PTRACE_PEEKUSER, pid, (char *)off, 0);
- if (val == -1 && errno) {
- perror("upeek: ptrace(PTRACE_PEEKUSER, ... )");
- return -1;
- }
- *res = val;
- return 0;
- }
-
- int
- getpc(pid)
- {
- /*
- * Return current program counter for `pid'
- * Assumes PC is never 0xffffffff
- */
- struct regs regs;
-
- if (ptrace(PTRACE_GETREGS, pid, (char *)®s, 0) < 0) {
- perror("getpc: ptrace(PTRACE_GETREGS, ...)");
- return -1;
- }
- return regs.r_pc;
- }
-
- int
- printcall(pid)
- {
- struct regs regs;
-
- if (ptrace(PTRACE_GETREGS, pid, (char *)®s, 0) < 0) {
- perror("printcall: ptrace(PTRACE_GETREGS, ...");
- return -1;
- }
- #ifdef sparc
- tprintf(" [at %#x] ", regs.r_o7);
- #endif
- #ifdef m68k
- {
- struct frame frame;
- if (ptrace(PTRACE_READDATA, tcp->pid, (char *)regs.r_areg[6],
- sizeof frame, (char *)&frame) < 0) {
- perror("PTRACE_READDATA, ...");
- return -1;
- }
- tprintf(" [at %#x] ", frame.fr_savpc);
- }
- #endif
- return 0;
- }
-
- int
- setbpt(tcp)
- struct tcb *tcp;
- {
- #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
- static int loopdeloop[2] = {LOOP, NOP};
- #endif
-
- if (tcp->flags & TCB_BPTSET) {
- (void)fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
- return -1;
- }
- if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) {
- perror("setbpt: ptrace(PTRACE_GETREGS, ...");
- return -1;
- }
- tcp->baddr = regs.r_o7 + 8;
- if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
- sizeof tcp->inst, (char *)tcp->inst) < 0) {
- perror("PTRACE_READTEXT,...");
- 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 in stead, in expectance of the SIGSTOP
- * generated by out PTRACE_ATTACH.
- * Of cause, if we evaporate ourselves in the middle of all this...
- */
- if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *)tcp->baddr,
- sizeof loopdeloop, (char *)loopdeloop) < 0) {
- perror("PTRACE_WRITETEXT,...");
- return -1;
- }
- tcp->flags |= TCB_BPTSET;
-
- #endif /* sparc */
-
- return 0;
- }
-
- int
- clearbpt(tcp)
- struct tcb *tcp;
- {
- #ifdef sparc
-
- #if !LOOPA
- struct regs regs;
- #endif
-
- if (!(tcp->flags & TCB_BPTSET)) {
- (void)fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
- return -1;
- }
- if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *)tcp->baddr,
- sizeof tcp->inst, (char *)tcp->inst) < 0) {
- perror("clearbtp: PTRACE_WRITETEXT,...");
- return -1;
- }
- tcp->flags &= ~TCB_BPTSET;
-
- #if !LOOPA
- /*
- * Since we don't have a single instruction breakpoint, we may have
- * to adjust the program counter after removing the our `breakpoint'.
- */
- if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) {
- perror("clearbpt: ptrace(PTRACE_GETREGS, ...");
- return -1;
- }
- if ((regs.r_pc < tcp->baddr) ||
- (regs.r_pc > tcp->baddr + 4)) {
- /* The breakpoint has not been reached yet */
- if (debug)
- (void)fprintf(stderr,
- "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
- regs.r_pc, tcp->parent->baddr);
- return 0;
- }
- if (regs.r_pc != tcp->baddr)
- if (debug)
- (void)fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
- regs.r_pc, tcp->baddr);
-
- regs.r_pc = tcp->baddr;
- if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)®s, 0) < 0) {
- perror("clearbpt: ptrace(PTRACE_SETREGS, ...");
- return -1;
- }
- #endif
-
- #endif /* sparc */
-
- return 0;
- }
-
- static
- getex(pid, hdr)
- int pid;
- struct exec *hdr;
- {
- int n;
-
- for (n = 0; n < sizeof *hdr; n += 4) {
- int res;
- if (upeek(pid, (unsigned)uoff(u_exdata)+n, &res) < 0)
- return -1;
- bcopy((char *)&res, (char *)hdr + n, 4);
- }
- if (debug) {
- (void)fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
- hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
- (void)fprintf(stderr, "Text %u Data %u Bss %u Syms %u Entry %#x]\n",
- hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
- }
- return 0;
- }
-
- int
- fixvfork(pid)
- int pid;
- {
- /*
- * Change `vfork' in a freshly exec'ed dynamically linked
- * executable's (internal) symbol table to plain old `fork'
- */
-
- struct exec hdr;
- struct link_dynamic dyn;
- struct link_dynamic_2 ld;
- char *strtab, *cp;
-
- if (getex(pid, &hdr) < 0)
- return -1;
- if (!hdr.a_dynamic)
- return -1;
-
- if (umove(pid, (int)N_DATADDR(hdr), sizeof dyn, (char *)&dyn) < 0) {
- (void)fprintf(stderr, "Cannot read DYNAMIC\n");
- return -1;
- }
- if (umove(pid, (int)dyn.ld_un.ld_2, sizeof ld, (char *)&ld) < 0) {
- (void)fprintf(stderr, "Cannot read link_dynamic_2\n");
- return -1;
- }
- if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
- (void)fprintf(stderr, "fixvfork: out of memory\n");
- return -1;
- }
- if (umove(pid, (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; ) {
- (void)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)
- (void)fprintf(stderr, "fixvfork: FOUND _vfork\n");
- (void)strcpy(cp, "_fork");
- break;
- }
- cp += strlen(cp)+1;
- }
- if (cp < strtab + ld.ld_symb_size)
- /*
- * Write entire symbol table back to avoid
- * memory alignment bugs in ptrace
- */
- if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
- (int)ld.ld_symb_size, strtab) < 0)
- goto err;
-
- free(strtab);
- return 0;
-
- err:
- free(strtab);
- return -1;
- }
-