home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / sun / volume3 / strace / part03 / util.c < prev   
Encoding:
C/C++ Source or Header  |  1992-03-02  |  11.1 KB  |  581 lines

  1. /*
  2.  * @(#)util.c    2.3 92/01/10
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <ctype.h>
  10. #include <errno.h>
  11. #include <sys/types.h>
  12. #include <sys/ptrace.h>
  13. #include <sys/user.h>
  14. #include <machine/reg.h>
  15. #include <a.out.h>
  16. #include <link.h>
  17.  
  18. #include "defs.h"
  19.  
  20. u_int max_str_len = DFLT_STR_LEN;
  21.  
  22. char *
  23. xlookup(xlat, val)
  24. Xlat *xlat;
  25. {
  26.     for (; xlat->str != NULL; xlat++)
  27.         if (xlat->val == val)
  28.             return xlat->str;
  29.  
  30.     return NULL;
  31. }
  32.  
  33. /*
  34.  * Print entry in Xlat table, if there.
  35.  */
  36. void
  37. printxval(xlat, val, dflt)
  38. Xlat *xlat;
  39. char *dflt;
  40. {
  41.     char *str = xlookup(xlat, val);
  42.  
  43.     if (str)
  44.         tprintf("%s", str);
  45.     else
  46.         tprintf("%s(%#x)", dflt, val);
  47. }
  48.  
  49. /*
  50.  * interpret `xlat' as an array of flags
  51.  * print the entries whose bits are on in `flags'
  52.  * return # of flags printed
  53.  */
  54. int
  55. addflags(xlat, flags)
  56. Xlat *xlat;
  57. int flags;
  58. {
  59.     int n;
  60.  
  61.     for (n = 0; xlat->str; xlat++) {
  62.         if (flags & xlat->val) {
  63.             tprintf("|%s", xlat->str);
  64.             n++;
  65.         }
  66.     }
  67.     return n;
  68. }
  69.  
  70. int
  71. printflags(xlat, flags)
  72. Xlat *xlat;
  73. int flags;
  74. {
  75.     int n;
  76.     char *format;
  77.  
  78.     format = "%s";
  79.     for (n = 0; xlat->str; xlat++) {
  80.         if (flags & xlat->val) {
  81.             tprintf(format, xlat->str);
  82.             n++;
  83.             format = "|%s";
  84.         }
  85.     }
  86.     return n;
  87. }
  88.  
  89. int
  90. printstr(pid, addr, len)
  91. {
  92.     static unsigned char *str;
  93.     int i, n, c;
  94.  
  95.     if (addr == 0) {
  96.         tprintf("(caddr_t)0");
  97.         return 0;
  98.     }
  99.     if (str == (unsigned char *)0) {
  100.         if ((str = (unsigned char *)malloc(max_str_len)) == NULL) {
  101.             (void)fprintf(stderr, "printstr: no memory\n");
  102.             return -1;
  103.         }
  104.     }
  105.  
  106.     if (len < 0) {
  107.         if (umovestr(pid, addr, n = (int)max_str_len, (char *)str) < 0) {
  108.             tprintf("%#x", addr);
  109.             return -1;
  110.         }
  111.     } else {
  112.         if (umove(pid, addr, n = MIN(len, (int)max_str_len), (char *)str) < 0) {
  113.             tprintf("%#x", addr);
  114.             return -1;
  115.         }
  116.     }
  117.  
  118.     tprintf("\"");
  119.     for (i = 0; i < n; i++) {
  120.         if (len < 0)
  121.             if (str[i] == '\0')
  122.                 break;
  123.         switch (c = str[i]) {
  124.         case '\n':
  125.             tprintf("\\n");
  126.             break;
  127.         case '\t':
  128.             tprintf("\\t");
  129.             break;
  130.         case '\r':
  131.             tprintf("\\r");
  132.             break;
  133.         default:
  134.             if (isprint(c)) {
  135.                 tprintf("%c", c);
  136.             } else {
  137.                 tprintf("\\%x", c);
  138.             }
  139.             break;
  140.         }
  141.  
  142.     }
  143.     tprintf("\"");
  144.     if (n < len || (len < 0 && i >= n)) {
  145.         tprintf("..");
  146.     }
  147.     return 0;
  148. }
  149.  
  150. #define PAGMASK    (~(PAGSIZ - 1))
  151. /*
  152.  * move `len' bytes of data from process `pid'
  153.  * at address `addr' to our space at `laddr'
  154.  */
  155. int
  156. umove(pid, addr, len, laddr)
  157. int pid;
  158. int addr, len;
  159. char *laddr;
  160. {
  161. #if 1
  162.     int n;
  163.  
  164.     while (len) {
  165.         n = MIN(len, PAGSIZ);
  166.         n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
  167.         if (ptrace(PTRACE_READDATA, pid, (char *)addr, len, laddr) < 0) {
  168.             perror("umove: ptrace(PTRACE_READDATA,..");
  169.     abort();
  170.             return -1;
  171.         }
  172.         len -= n;
  173.         addr += n;
  174.         laddr += n;
  175.     }
  176. #else
  177.     int n, m;
  178.     union {
  179.         int val;
  180.         char x[4];
  181.     } u;
  182.  
  183.     if (addr & 3) /* addr not a multiple of 4 */ {
  184.         n = addr - (addr & -4); /* residue */
  185.         addr &= -4; /* residue */
  186.         u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
  187.         bcopy(&u.x[n], laddr, m = MIN(4-n,len));
  188.         addr += 4, laddr += m, len -= m;
  189.     }
  190.     while (len) {
  191.         u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
  192.         bcopy(u.x, laddr, m = MIN(4,len));
  193.         addr += 4, laddr += m, len -= m;
  194.     }
  195. #endif
  196.     return 0;
  197. }
  198.  
  199. /*
  200.  * like `umove' but make the additional effort of looking
  201.  * for a terminating zero byte.
  202.  */
  203. int
  204. umovestr(pid, addr, len, laddr)
  205. int pid;
  206. int addr, len;
  207. char *laddr;
  208. {
  209.     int i, n, m;
  210.     union {
  211.         int val;
  212.         char x[4];
  213.     } u;
  214.  
  215.     if (addr & 3) /* addr not a multiple of 4 */ {
  216.         n = addr - (addr & -4); /* residue */
  217.         addr &= -4; /* residue */
  218.         errno = 0;
  219.         u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
  220.         if (errno) {
  221.             perror("umovestr");
  222.             return -1;
  223.         }
  224.         bcopy(&u.x[n], laddr, m = MIN(4-n,len));
  225.         while (n & 3)
  226.             if (u.x[n++] == '\0')
  227.                 return 0;
  228.         addr += 4, laddr += m, len -= m;
  229.     }
  230.     while (len) {
  231.         errno = 0;
  232.         u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
  233.         if (errno) {
  234.             perror("umovestr");
  235.             return -1;
  236.         }
  237.         bcopy(u.x, laddr, m = MIN(4,len));
  238.         for (i = 0; i < 4; i++)
  239.             if (u.x[i] == '\0')
  240.                 return 0;
  241.  
  242.         addr += 4, laddr += m, len -= m;
  243.     }
  244.     return 0;
  245. }
  246.  
  247. static int
  248. uload(cmd, pid, addr, len, laddr)
  249. enum ptracereq cmd;
  250. int pid;
  251. int addr, len;
  252. char *laddr;
  253. {
  254. #if 0
  255.     int n;
  256.  
  257.     while (len) {
  258.         n = MIN(len, PAGSIZ);
  259.         n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
  260.         if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
  261.             perror("uload: ptrace(PTRACE_WRITE, ...)");
  262.             return -1;
  263.         }
  264.         len -= n;
  265.         addr += n;
  266.         laddr += n;
  267.     }
  268. #else
  269.     enum ptracereq peek = cmd==PTRACE_WRITETEXT?
  270.                     PTRACE_PEEKTEXT:PTRACE_PEEKDATA;
  271.     enum ptracereq poke = cmd==PTRACE_WRITETEXT?
  272.                     PTRACE_POKETEXT:PTRACE_POKEDATA;
  273.     int n, m;
  274.     union {
  275.         int val;
  276.         char x[4];
  277.     } u;
  278.  
  279.     if (addr & 3) /* addr not a multiple of 4 */ {
  280.         n = addr - (addr & -4); /* residue */
  281.         addr &= -4;
  282.         u.val = ptrace(peek, pid, (char *)addr, 0);
  283.         bcopy(laddr, &u.x[n], m = MIN(4-n,len));
  284.         if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
  285.             perror("uload: POKE");
  286.             return -1;
  287.         }
  288.         addr += 4, laddr += m, len -= m;
  289.     }
  290.     while (len) {
  291.         if (len < 4) {
  292.             u.val = ptrace(peek, pid, (char *)addr, 0);
  293.         }
  294.         bcopy(laddr, u.x, m = MIN(4,len));
  295.         if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
  296.             perror("uload: POKE");
  297.             return -1;
  298.         }
  299.         addr += 4, laddr += m, len -= m;
  300.     }
  301. #endif
  302.     return 0;
  303. }
  304.  
  305. int
  306. tload(pid, addr, len, laddr)
  307. int pid;
  308. int addr, len;
  309. char *laddr;
  310. {
  311.     return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
  312. }
  313.  
  314. int
  315. dload(pid, addr, len, laddr)
  316. int pid;
  317. int addr, len;
  318. char *laddr;
  319. {
  320.     return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
  321. }
  322.  
  323. int
  324. upeek(pid, off, res)
  325. unsigned int off;
  326. int *res;
  327. {
  328.     int val;
  329.  
  330.     errno = 0;
  331.     val = ptrace(PTRACE_PEEKUSER, pid, (char *)off, 0);
  332.     if (val == -1 && errno) {
  333.         perror("upeek: ptrace(PTRACE_PEEKUSER, ... )");
  334.         return -1;
  335.     }
  336.     *res = val;
  337.     return 0;
  338. }
  339.  
  340. int
  341. getpc(pid)
  342. {
  343.     /*
  344.      * Return current program counter for `pid'
  345.      * Assumes PC is never 0xffffffff
  346.      */
  347.     struct regs regs;
  348.  
  349.     if (ptrace(PTRACE_GETREGS, pid, (char *)®s, 0) < 0) {
  350.         perror("getpc: ptrace(PTRACE_GETREGS, ...)");
  351.         return -1;
  352.     }
  353.     return regs.r_pc;
  354. }
  355.  
  356. int
  357. printcall(pid)
  358. {
  359.     struct regs regs;
  360.  
  361.     if (ptrace(PTRACE_GETREGS, pid, (char *)®s, 0) < 0) {
  362.         perror("printcall: ptrace(PTRACE_GETREGS, ...");
  363.         return -1;
  364.     }
  365. #ifdef sparc
  366.     tprintf(" [at %#x] ", regs.r_o7);
  367. #endif
  368. #ifdef m68k
  369.     {
  370.         struct frame frame;
  371.         if (ptrace(PTRACE_READDATA, tcp->pid, (char *)regs.r_areg[6],
  372.                     sizeof frame, (char *)&frame) < 0) {
  373.             perror("PTRACE_READDATA, ...");
  374.             return -1;
  375.         }
  376.         tprintf(" [at %#x] ", frame.fr_savpc);
  377.     }
  378. #endif
  379.     return 0;
  380. }
  381.  
  382. int
  383. setbpt(tcp)
  384. struct tcb *tcp;
  385. {
  386. #ifdef sparc    /* This code is slightly sparc specific */
  387.  
  388.     struct regs regs;
  389. #define BPT    0x91d02001    /* ta    1 */
  390. #define LOOP    0x10800000    /* ba    0 */
  391. #define LOOPA    0x30800000    /* ba,a    0 */
  392. #define NOP    0x01000000
  393. #if LOOPA
  394.     static int loopdeloop[1] = {LOOPA};
  395. #else
  396.     static int loopdeloop[2] = {LOOP, NOP};
  397. #endif
  398.  
  399.     if (tcp->flags & TCB_BPTSET) {
  400.         (void)fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
  401.         return -1;
  402.     }
  403.     if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) {
  404.         perror("setbpt: ptrace(PTRACE_GETREGS, ...");
  405.         return -1;
  406.     }
  407.     tcp->baddr = regs.r_o7 + 8;
  408.     if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
  409.                 sizeof tcp->inst, (char *)tcp->inst) < 0) {
  410.         perror("PTRACE_READTEXT,...");
  411.         return -1;
  412.     }
  413.  
  414.     /*
  415.      * XXX - BRUTAL MODE ON
  416.      * We cannot set a real BPT in the child, since it will not be
  417.      * traced at the moment it will reach the trap and would probably
  418.      * die with a core dump.
  419.      * Thus, we are force our way in by taking out two instructions
  420.      * and insert an eternal loop in stead, in expectance of the SIGSTOP
  421.      * generated by out PTRACE_ATTACH.
  422.      * Of cause, if we evaporate ourselves in the middle of all this...
  423.      */
  424.     if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *)tcp->baddr,
  425.                 sizeof loopdeloop, (char *)loopdeloop) < 0) {
  426.         perror("PTRACE_WRITETEXT,...");
  427.         return -1;
  428.     }
  429.     tcp->flags |= TCB_BPTSET;
  430.  
  431. #endif /* sparc */
  432.  
  433.     return 0;
  434. }
  435.  
  436. int
  437. clearbpt(tcp)
  438. struct tcb *tcp;
  439. {
  440. #ifdef sparc
  441.  
  442. #if !LOOPA
  443.     struct regs regs;
  444. #endif
  445.  
  446.     if (!(tcp->flags & TCB_BPTSET)) {
  447.         (void)fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
  448.         return -1;
  449.     }
  450.     if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *)tcp->baddr,
  451.                 sizeof tcp->inst, (char *)tcp->inst) < 0) {
  452.         perror("clearbtp: PTRACE_WRITETEXT,...");
  453.         return -1;
  454.     }
  455.     tcp->flags &= ~TCB_BPTSET;
  456.  
  457. #if !LOOPA
  458.     /*
  459.      * Since we don't have a single instruction breakpoint, we may have
  460.      * to adjust the program counter after removing the our `breakpoint'.
  461.      */
  462.     if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) {
  463.         perror("clearbpt: ptrace(PTRACE_GETREGS, ...");
  464.         return -1;
  465.     }
  466.     if ((regs.r_pc < tcp->baddr) ||
  467.                 (regs.r_pc > tcp->baddr + 4)) {
  468.         /* The breakpoint has not been reached yet */
  469.         if (debug)
  470.             (void)fprintf(stderr,
  471.                 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
  472.                     regs.r_pc, tcp->parent->baddr);
  473.         return 0;
  474.     }
  475.     if (regs.r_pc != tcp->baddr)
  476.         if (debug)
  477.             (void)fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
  478.                 regs.r_pc, tcp->baddr);
  479.  
  480.     regs.r_pc = tcp->baddr;
  481.     if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)®s, 0) < 0) {
  482.         perror("clearbpt: ptrace(PTRACE_SETREGS, ...");
  483.         return -1;
  484.     }
  485. #endif
  486.  
  487. #endif /* sparc */
  488.  
  489.     return 0;
  490. }
  491.  
  492. static
  493. getex(pid, hdr)
  494. int pid;
  495. struct exec *hdr;
  496. {
  497.     int n;
  498.  
  499.     for (n = 0; n < sizeof *hdr; n += 4) {
  500.         int res;
  501.         if (upeek(pid, (unsigned)uoff(u_exdata)+n, &res) < 0)
  502.             return -1;
  503.         bcopy((char *)&res, (char *)hdr + n, 4);
  504.     }
  505.     if (debug) {
  506.         (void)fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
  507.             hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
  508.         (void)fprintf(stderr, "Text %u Data %u Bss %u Syms %u Entry %#x]\n",
  509.             hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
  510.     }
  511.     return 0;
  512. }
  513.  
  514. int
  515. fixvfork(pid)
  516. int pid;
  517. {
  518.     /*
  519.      * Change `vfork' in a freshly exec'ed dynamically linked
  520.      * executable's (internal) symbol table to plain old `fork'
  521.      */
  522.  
  523.     struct exec hdr;
  524.     struct link_dynamic dyn;
  525.     struct link_dynamic_2 ld;
  526.     char *strtab, *cp;
  527.  
  528.     if (getex(pid, &hdr) < 0)
  529.         return -1;
  530.     if (!hdr.a_dynamic)
  531.         return -1;
  532.     
  533.     if (umove(pid, (int)N_DATADDR(hdr), sizeof dyn, (char *)&dyn) < 0) {
  534.         (void)fprintf(stderr, "Cannot read DYNAMIC\n");
  535.         return -1;
  536.     }
  537.     if (umove(pid, (int)dyn.ld_un.ld_2, sizeof ld, (char *)&ld) < 0) {
  538.         (void)fprintf(stderr, "Cannot read link_dynamic_2\n");
  539.         return -1;
  540.     }
  541.     if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
  542.         (void)fprintf(stderr, "fixvfork: out of memory\n");
  543.         return -1;
  544.     }
  545.     if (umove(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
  546.                     (int)ld.ld_symb_size, strtab) < 0)
  547.         goto err;
  548.  
  549. #if 0
  550.     for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
  551.         (void)fprintf(stderr, "[symbol: %s]\n", cp);
  552.         cp += strlen(cp)+1;
  553.     }
  554.     return 0;
  555. #endif
  556.     for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
  557.         if (strcmp(cp, "_vfork") == 0) {
  558.             if (debug)
  559.                 (void)fprintf(stderr, "fixvfork: FOUND _vfork\n");
  560.             (void)strcpy(cp, "_fork");
  561.             break;
  562.         }
  563.         cp += strlen(cp)+1;
  564.     }
  565.     if (cp < strtab + ld.ld_symb_size)
  566.         /*
  567.          * Write entire symbol table back to avoid
  568.          * memory alignment bugs in ptrace
  569.          */
  570.         if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
  571.                     (int)ld.ld_symb_size, strtab) < 0)
  572.             goto err;
  573.  
  574.     free(strtab);
  575.     return 0;
  576.  
  577. err:
  578.     free(strtab);
  579.     return -1;
  580. }
  581.