]> granicus.if.org Git - strace/blob - util.c
Fix typo
[strace] / util.c
1 /*
2  * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3  * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  *      $Id$
30  */
31
32 #include "defs.h"
33
34 #include <sys/user.h>
35 #include <sys/param.h>
36 #include <fcntl.h>
37 #ifdef SUNOS4
38 #include <machine/reg.h>
39 #include <a.out.h>
40 #include <link.h>
41 #endif /* SUNOS4 */
42 #if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 && (defined(I386) || defined(M68K))
43 # include <sys/reg.h>
44 # define PTRACE_PEEKUSR PTRACE_PEEKUSER
45 #endif
46 #ifdef LINUX
47 #ifndef __GLIBC__
48 #include <linux/ptrace.h>
49 #endif
50 #endif /* LINUX */
51
52 #ifdef HAVE_SYS_PTRACE_H
53 #include <sys/ptrace.h>
54 #endif
55
56 #ifdef SUNOS4_KERNEL_ARCH_KLUDGE
57 #include <sys/utsname.h>
58 #endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
59
60 #if defined(LINUX) && defined(SPARC) && !defined(__GLIBC__)
61
62 #include <linux/unistd.h>
63
64 #define _hack_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,\
65           type5,arg5,syscall) \
66 type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
67 { \
68       long __res; \
69 \
70 __asm__ volatile ("or %%g0, %1, %%o0\n\t" \
71                   "or %%g0, %2, %%o1\n\t" \
72                   "or %%g0, %3, %%o2\n\t" \
73                   "or %%g0, %4, %%o3\n\t" \
74                   "or %%g0, %5, %%o4\n\t" \
75                   "or %%g0, %6, %%g1\n\t" \
76                   "t 0x10\n\t" \
77                   "bcc 1f\n\t" \
78                   "or %%g0, %%o0, %0\n\t" \
79                   "sub %%g0, %%o0, %0\n\t" \
80                   "1:\n\t" \
81                   : "=r" (__res) \
82                   : "0" ((long)(arg1)),"1" ((long)(arg2)), \
83                     "2" ((long)(arg3)),"3" ((long)(arg4)),"4" ((long)(arg5)), \
84                     "i" (__NR_##syscall)  \
85                   : "g1", "o0", "o1", "o2", "o3", "o4"); \
86 if (__res>=0) \
87         return (type) __res; \
88 errno = -__res; \
89 return -1; \
90 }
91
92 static _hack_syscall5(int,_ptrace,int,__request,int,__pid,int,__addr,int,__data,int,__addr2,ptrace)
93
94 #define _ptrace
95
96 #endif
97
98 /* macros */
99 #ifndef MAX
100 #define MAX(a,b)                (((a) > (b)) ? (a) : (b))
101 #endif
102 #ifndef MIN
103 #define MIN(a,b)                (((a) < (b)) ? (a) : (b))
104 #endif
105
106 void
107 tv_tv(tv, a, b)
108 struct timeval *tv;
109 int a;
110 int b;
111 {
112         tv->tv_sec = a;
113         tv->tv_usec = b;
114 }
115
116 int
117 tv_nz(a)
118 struct timeval *a;
119 {
120         return a->tv_sec || a->tv_usec;
121 }
122
123 int
124 tv_cmp(a, b)
125 struct timeval *a, *b;
126 {
127         if (a->tv_sec < b->tv_sec
128             || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
129                 return -1;
130         if (a->tv_sec > b->tv_sec
131             || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
132                 return 1;
133         return 0;
134 }
135
136 double
137 tv_float(tv)
138 struct timeval *tv;
139 {
140         return tv->tv_sec + tv->tv_usec/1000000.0;
141 }
142
143 void
144 tv_add(tv, a, b)
145 struct timeval *tv, *a, *b;
146 {
147         tv->tv_sec = a->tv_sec + b->tv_sec;
148         tv->tv_usec = a->tv_usec + b->tv_usec;
149         if (tv->tv_usec > 1000000) {
150                 tv->tv_sec++;
151                 tv->tv_usec -= 1000000;
152         }
153 }
154
155 void
156 tv_sub(tv, a, b)
157 struct timeval *tv, *a, *b;
158 {
159         tv->tv_sec = a->tv_sec - b->tv_sec;
160         tv->tv_usec = a->tv_usec - b->tv_usec;
161         if (((long) tv->tv_usec) < 0) {
162                 tv->tv_sec--;
163                 tv->tv_usec += 1000000;
164         }
165 }
166
167 void
168 tv_div(tv, a, n)
169 struct timeval *tv, *a;
170 int n;
171 {
172         tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
173         tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
174         tv->tv_usec %= 1000000;
175 }
176
177 void
178 tv_mul(tv, a, n)
179 struct timeval *tv, *a;
180 int n;
181 {
182         tv->tv_usec = a->tv_usec * n;
183         tv->tv_sec = a->tv_sec * n + a->tv_usec / 1000000;
184         tv->tv_usec %= 1000000;
185 }
186
187 char *
188 xlookup(xlat, val)
189 struct xlat *xlat;
190 int val;
191 {
192         for (; xlat->str != NULL; xlat++)
193                 if (xlat->val == val)
194                         return xlat->str;
195         return NULL;
196 }
197
198 /*
199  * Print entry in struct xlat table, if there.
200  */
201 void
202 printxval(xlat, val, dflt)
203 struct xlat *xlat;
204 int val;
205 char *dflt;
206 {
207         char *str = xlookup(xlat, val);
208
209         if (str)
210                 tprintf("%s", str);
211         else
212                 tprintf("%#x /* %s */", val, dflt);
213 }
214
215 /*
216  * Interpret `xlat' as an array of flags
217  * print the entries whose bits are on in `flags'
218  * return # of flags printed.
219  */
220 int
221 addflags(xlat, flags)
222 struct xlat *xlat;
223 int flags;
224 {
225         int n;
226
227         for (n = 0; xlat->str; xlat++) {
228                 if (xlat->val && (flags & xlat->val) == xlat->val) {
229                         tprintf("|%s", xlat->str);
230                         flags &= ~xlat->val;
231                         n++;
232                 }
233         }
234         if (flags) {
235                 tprintf("|%#x", flags);
236                 n++;
237         }
238         return n;
239 }
240
241 int
242 printflags(xlat, flags)
243 struct xlat *xlat;
244 int flags;
245 {
246         int n;
247         char *sep;
248
249         if (flags == 0 && xlat->val == 0) {
250                 tprintf("%s", xlat->str);
251                 return 1;
252         }
253
254         sep = "";
255         for (n = 0; xlat->str; xlat++) {
256                 if (xlat->val && (flags & xlat->val) == xlat->val) {
257                         tprintf("%s%s", sep, xlat->str);
258                         flags &= ~xlat->val;
259                         sep = "|";
260                         n++;
261                 }
262         }
263         if (flags) {
264                 tprintf("%s%#x", sep, flags);
265                 n++;
266         }
267         return n;
268 }
269
270 void
271 printnum(tcp, addr, fmt)
272 struct tcb *tcp;
273 long addr;
274 char *fmt;
275 {
276         int num;
277
278         if (!addr) {
279                 tprintf("NULL");
280                 return;
281         }
282         if (umove(tcp, addr, &num) < 0) {
283                 tprintf("%#lx", addr);
284                 return;
285         }
286         tprintf("[");
287         tprintf(fmt, num);
288         tprintf("]");
289 }
290
291 static char path[MAXPATHLEN + 1];
292
293 void
294 string_quote(str)
295 char *str;
296 {
297         char buf[2 * MAXPATHLEN + 1];
298         char *s;
299
300         if (!strpbrk(str, "\"\'\\")) {
301                 tprintf("\"%s\"", str);
302                 return;
303         }
304         for (s = buf; *str; str++) {
305                 switch (*str) {
306                 case '\"': case '\'': case '\\':
307                         *s++ = '\\'; *s++ = *str; break;
308                 default:
309                         *s++ = *str; break;
310                 }
311         }
312         *s = '\0';
313         tprintf("\"%s\"", buf);
314 }
315
316 void
317 printpath(tcp, addr)
318 struct tcb *tcp;
319 long addr;
320 {
321         if (umovestr(tcp, addr, MAXPATHLEN, path) < 0)
322                 tprintf("%#lx", addr);
323         else
324                 string_quote(path);
325         return;
326 }
327
328 void
329 printpathn(tcp, addr, n)
330 struct tcb *tcp;
331 long addr;
332 int n;
333 {
334         if (umovestr(tcp, addr, n, path) < 0)
335                 tprintf("%#lx", addr);
336         else {
337                 path[n] = '\0';
338                 string_quote(path);
339         }
340 }
341
342 void
343 printstr(tcp, addr, len)
344 struct tcb *tcp;
345 long addr;
346 int len;
347 {
348         static unsigned char *str = NULL;
349         static char *outstr;
350         int i, n, c, usehex;
351         char *s, *outend;
352
353         if (!addr) {
354                 tprintf("NULL");
355                 return;
356         }
357         if (!str) {
358                 if ((str = malloc(max_strlen)) == NULL
359                     || (outstr = malloc(2*max_strlen)) == NULL) {
360                         fprintf(stderr, "printstr: no memory\n");
361                         tprintf("%#lx", addr);
362                         return;
363                 }
364         }
365         outend = outstr + max_strlen * 2 - 10;
366         if (len < 0) {
367                 n = max_strlen;
368                 if (umovestr(tcp, addr, n, (char *) str) < 0) {
369                         tprintf("%#lx", addr);
370                         return;
371                 }
372         }
373         else {
374                 n = MIN(len, max_strlen);
375                 if (umoven(tcp, addr, n, (char *) str) < 0) {
376                         tprintf("%#lx", addr);
377                         return;
378                 }
379         }
380
381         usehex = 0;
382         if (xflag > 1)
383                 usehex = 1;
384         else if (xflag) {
385                 for (i = 0; i < n; i++) {
386                         c = str[i];
387                         if (len < 0 && c == '\0')
388                                 break;
389                         if (!isprint(c) && !isspace(c)) {
390                                 usehex = 1;
391                                 break;
392                         }
393                 }
394         }
395
396         s = outstr;
397         *s++ = '\"';
398
399         if (usehex) {
400                 for (i = 0; i < n; i++) {
401                         c = str[i];
402                         if (len < 0 && c == '\0')
403                                 break;
404                         sprintf(s, "\\x%02x", c);
405                         s += 4;
406                         if (s > outend)
407                                 break;
408                 }
409         }
410         else {
411                 for (i = 0; i < n; i++) {
412                         c = str[i];
413                         if (len < 0 && c == '\0')
414                                 break;
415                         switch (c) {
416                         case '\"': case '\'': case '\\':
417                                 *s++ = '\\'; *s++ = c; break;
418                         case '\f':
419                                 *s++ = '\\'; *s++ = 'f'; break;
420                         case '\n':
421                                 *s++ = '\\'; *s++ = 'n'; break;
422                         case '\r':
423                                 *s++ = '\\'; *s++ = 'r'; break;
424                         case '\t':
425                                 *s++ = '\\'; *s++ = 't'; break;
426                         case '\v':
427                                 *s++ = '\\'; *s++ = 'v'; break;
428                         default:
429                                 if (isprint(c))
430                                         *s++ = c;
431                                 else if (i < n - 1 && isdigit(str[i + 1])) {
432                                         sprintf(s, "\\%03o", c);
433                                         s += 4;
434                                 }
435                                 else {
436                                         sprintf(s, "\\%o", c);
437                                         s += strlen(s);
438                                 }
439                                 break;
440                         }
441                         if (s > outend)
442                                 break;
443                 }
444         }
445
446         *s++ = '\"';
447         if (i < len || (len < 0 && (i == n || s > outend))) {
448                 *s++ = '.'; *s++ = '.'; *s++ = '.';
449         }
450         *s = '\0';
451         tprintf("%s", outstr);
452 }
453
454 void
455 dumpstr(tcp, addr, len)
456 struct tcb *tcp;
457 long addr;
458 int len;
459 {
460         static int strsize = -1;
461         static unsigned char *str;
462         static char outstr[80];
463         char *s;
464         int i, j;
465
466         if (strsize < len) {
467                 if (str)
468                         free(str);
469                 if ((str = malloc(len)) == NULL) {
470                         fprintf(stderr, "dump: no memory\n");
471                         return;
472                 }
473                 strsize = len;
474         }
475
476         if (umoven(tcp, addr, len, (char *) str) < 0)
477                 return;
478
479         for (i = 0; i < len; i += 16) {
480                 s = outstr;
481                 sprintf(s, " | %05x ", i);
482                 s += 9;
483                 for (j = 0; j < 16; j++) {
484                         if (j == 8)
485                                 *s++ = ' ';
486                         if (i + j < len) {
487                                 sprintf(s, " %02x", str[i + j]);
488                                 s += 3;
489                         }
490                         else {
491                                 *s++ = ' '; *s++ = ' '; *s++ = ' ';
492                         }
493                 }
494                 *s++ = ' '; *s++ = ' ';
495                 for (j = 0; j < 16; j++) {
496                         if (j == 8)
497                                 *s++ = ' ';
498                         if (i + j < len) {
499                                 if (isprint(str[i + j]))
500                                         *s++ = str[i + j];
501                                 else
502                                         *s++ = '.';
503                         }
504                         else
505                                 *s++ = ' ';
506                 }
507                 tprintf("%s |\n", outstr);
508         }
509 }
510
511 #define PAGMASK (~(PAGSIZ - 1))
512 /*
513  * move `len' bytes of data from process `pid'
514  * at address `addr' to our space at `laddr'
515  */
516 int
517 umoven(tcp, addr, len, laddr)
518 struct tcb *tcp;
519 long addr;
520 int len;
521 char *laddr;
522 {
523
524 #ifdef LINUX
525         int pid = tcp->pid;
526         int n, m;
527         int started = 0;
528         union {
529                 long val;
530                 char x[sizeof(long)];
531         } u;
532
533         if (addr & (sizeof(long) - 1)) {
534                 /* addr not a multiple of sizeof(long) */
535                 n = addr - (addr & -sizeof(long)); /* residue */
536                 addr &= -sizeof(long); /* residue */
537                 errno = 0;
538                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
539                 if (errno) {
540                         if (started && (errno==EPERM || errno==EIO)) {
541                                 /* Ran into 'end of memory' - stupid "printpath" */
542                                 return 0;
543                         }
544                         /* But if not started, we had a bogus address. */
545                         perror("ptrace: umoven");
546                         return -1;
547                 }
548                 started = 1;
549                 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
550                 addr += sizeof(long), laddr += m, len -= m;
551         }
552         while (len) {
553                 errno = 0;
554                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
555                 if (errno) {
556                         if (started && (errno==EPERM || errno==EIO)) {
557                                 /* Ran into 'end of memory' - stupid "printpath" */
558                                 return 0;
559                         }
560                         perror("ptrace: umoven");
561                         return -1;
562                 }
563                 started = 1;
564                 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
565                 addr += sizeof(long), laddr += m, len -= m;
566         }
567 #endif /* LINUX */
568
569 #ifdef SUNOS4
570         int pid = tcp->pid;
571 #if 0
572         int n, m;
573         union {
574                 long val;
575                 char x[sizeof(long)];
576         } u;
577
578         if (addr & (sizeof(long) - 1)) {
579                 /* addr not a multiple of sizeof(long) */
580                 n = addr - (addr & -sizeof(long)); /* residue */
581                 addr &= -sizeof(long); /* residue */
582                 errno = 0;
583                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
584                 if (errno) {
585                         perror("umoven");
586                         return -1;
587                 }
588                 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
589                 addr += sizeof(long), laddr += m, len -= m;
590         }
591         while (len) {
592                 errno = 0;
593                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
594                 if (errno) {
595                         perror("umoven");
596                         return -1;
597                 }
598                 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
599                 addr += sizeof(long), laddr += m, len -= m;
600         }
601 #else /* !oldway */
602         int n;
603
604         while (len) {
605                 n = MIN(len, PAGSIZ);
606                 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
607                 if (ptrace(PTRACE_READDATA, pid,
608                            (char *) addr, len, laddr) < 0) {
609                         perror("umoven: ptrace(PTRACE_READDATA, ...)");
610                         abort();
611                         return -1;
612                 }
613                 len -= n;
614                 addr += n;
615                 laddr += n;
616         }
617 #endif /* !oldway */
618 #endif /* SUNOS4 */
619
620 #ifdef SVR4
621 /*
622  * We would like to use pread preferentially for speed
623  * but even though SGI has it in their library, it no longer works.
624  */
625 #ifdef MIPS
626 #undef HAVE_PREAD
627 #endif
628 #ifdef HAVE_PREAD
629         if (pread(tcp->pfd, laddr, len, addr) == -1)
630                 return -1;
631 #else /* !HAVE_PREAD */
632         lseek(tcp->pfd, addr, SEEK_SET);
633         if (read(tcp->pfd, laddr, len) == -1)
634                 return -1;
635 #endif /* !HAVE_PREAD */
636 #endif /* SVR4 */
637
638         return 0;
639 }
640
641 /*
642  * like `umove' but make the additional effort of looking
643  * for a terminating zero byte.
644  */
645 int
646 umovestr(tcp, addr, len, laddr)
647 struct tcb *tcp;
648 long addr;
649 int len;
650 char *laddr;
651 {
652 #ifdef SVR4
653         return umoven(tcp, addr, len, laddr);
654 #else /* !SVR4 */
655         int started = 0;
656         int pid = tcp->pid;
657         int i, n, m;
658         union {
659                 long val;
660                 char x[sizeof(long)];
661         } u;
662
663         if (addr & (sizeof(long) - 1)) {
664                 /* addr not a multiple of sizeof(long) */
665                 n = addr - (addr & -sizeof(long)); /* residue */
666                 addr &= -sizeof(long); /* residue */
667                 errno = 0;
668                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
669                 if (errno) {
670                         if (started && (errno==EPERM || errno==EIO)) {
671                                 /* Ran into 'end of memory' - stupid "printpath" */
672                                 return 0;
673                         }
674                         perror("umovestr");
675                         return -1;
676                 }
677                 started = 1;
678                 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
679                 while (n & (sizeof(long) - 1))
680                         if (u.x[n++] == '\0')
681                                 return 0;
682                 addr += sizeof(long), laddr += m, len -= m;
683         }
684         while (len) {
685                 errno = 0;
686                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
687                 if (errno) {
688                         if (started && (errno==EPERM || errno==EIO)) {
689                                 /* Ran into 'end of memory' - stupid "printpath" */
690                                 return 0;
691                         }
692                         perror("umovestr");
693                         return -1;
694                 }
695                 started = 1;
696                 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
697                 for (i = 0; i < sizeof(long); i++)
698                         if (u.x[i] == '\0')
699                                 return 0;
700
701                 addr += sizeof(long), laddr += m, len -= m;
702         }
703         return 0;
704 #endif /* !SVR4 */
705 }
706
707 #ifdef LINUX
708 #ifndef SPARC
709 #define PTRACE_WRITETEXT        101
710 #define PTRACE_WRITEDATA        102
711 #endif /* !SPARC */
712 #endif /* LINUX */
713
714 #ifdef SUNOS4
715
716 static int
717 uload(cmd, pid, addr, len, laddr)
718 int cmd;
719 int pid;
720 long addr;
721 int len;
722 char *laddr;
723 {
724 #if 0
725         int n;
726
727         while (len) {
728                 n = MIN(len, PAGSIZ);
729                 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
730                 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
731                         perror("uload: ptrace(PTRACE_WRITE, ...)");
732                         return -1;
733                 }
734                 len -= n;
735                 addr += n;
736                 laddr += n;
737         }
738 #else
739         int peek, poke;
740         int n, m;
741         union {
742                 long val;
743                 char x[sizeof(long)];
744         } u;
745
746         if (cmd == PTRACE_WRITETEXT) {
747                 peek = PTRACE_PEEKTEXT;
748                 poke = PTRACE_POKETEXT;
749         }
750         else {
751                 peek = PTRACE_PEEKDATA;
752                 poke = PTRACE_POKEDATA;
753         }
754         if (addr & (sizeof(long) - 1)) {
755                 /* addr not a multiple of sizeof(long) */
756                 n = addr - (addr & -sizeof(long)); /* residue */
757                 addr &= -sizeof(long);
758                 errno = 0;
759                 u.val = ptrace(peek, pid, (char *) addr, 0);
760                 if (errno) {
761                         perror("uload: POKE");
762                         return -1;
763                 }
764                 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
765                 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
766                         perror("uload: POKE");
767                         return -1;
768                 }
769                 addr += sizeof(long), laddr += m, len -= m;
770         }
771         while (len) {
772                 if (len < sizeof(long))
773                         u.val = ptrace(peek, pid, (char *) addr, 0);
774                 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
775                 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
776                         perror("uload: POKE");
777                         return -1;
778                 }
779                 addr += sizeof(long), laddr += m, len -= m;
780         }
781 #endif
782         return 0;
783 }
784
785 int
786 tload(pid, addr, len, laddr)
787 int pid;
788 int addr, len;
789 char *laddr;
790 {
791         return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
792 }
793
794 int
795 dload(pid, addr, len, laddr)
796 int pid;
797 int addr;
798 int len;
799 char *laddr;
800 {
801         return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
802 }
803
804 #endif /* SUNOS4 */
805
806 #ifndef SVR4
807
808 int
809 upeek(pid, off, res)
810 int pid;
811 long off;
812 long *res;
813 {
814         long val;
815
816 #ifdef SUNOS4_KERNEL_ARCH_KLUDGE
817         {
818                 static int is_sun4m = -1;
819                 struct utsname name;
820
821                 /* Round up the usual suspects. */
822                 if (is_sun4m == -1) {
823                         if (uname(&name) < 0) {
824                                 perror("upeek: uname?");
825                                 exit(1);
826                         }
827                         is_sun4m = strcmp(name.machine, "sun4m") == 0;
828                         if (is_sun4m) {
829                                 extern struct xlat struct_user_offsets[];
830                                 struct xlat *x;
831
832                                 for (x = struct_user_offsets; x->str; x++)
833                                         x->val += 1024;
834                         }
835                 }
836                 if (is_sun4m)
837                         off += 1024;
838         }
839 #endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
840         errno = 0;
841         val = ptrace(PTRACE_PEEKUSER, pid, (char *) off, 0);
842         if (val == -1 && errno) {
843                 perror("upeek: ptrace(PTRACE_PEEKUSER, ... )");
844                 return -1;
845         }
846         *res = val;
847         return 0;
848 }
849
850 #endif /* !SVR4 */
851
852 long
853 getpc(tcp)
854 struct tcb *tcp;
855 {
856
857 #ifdef LINUX
858         long pc;
859
860 #ifdef I386
861         if (upeek(tcp->pid, 4*EIP, &pc) < 0)
862                 return -1;
863 #else /* !I386 */
864 #ifdef ARM
865         if (upeek(tcp->pid, 4*15, &pc) < 0)
866                 return -1;
867 #else /* !ARM */
868 #ifdef POWERPC
869         if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
870                 return -1;
871 #else
872 #ifdef M68K
873         if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
874                 return -1;
875 #else /* !M68K */
876 #ifdef ALPHA
877         if (upeek(tcp->pid, REG_PC, &pc) < 0)
878                 return -1;
879 #else /* !ALPHA */
880 #ifdef SPARC
881         struct pt_regs regs;
882         if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
883                 return -1;
884         pc = regs.pc;
885 #endif /* SPARC */
886 #endif /* ALPHA */
887 #endif /* !M68K */
888 #endif /* !POWERPC */
889 #endif /* !ARM */
890 #endif /* !I386 */
891         return pc;
892 #endif /* LINUX */
893
894 #ifdef SUNOS4
895         /*
896          * Return current program counter for `pid'
897          * Assumes PC is never 0xffffffff
898          */
899         struct regs regs;
900
901         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
902                 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
903                 return -1;
904         }
905         return regs.r_pc;
906 #endif /* SUNOS4 */
907
908 #ifdef SVR4
909         /* XXX */
910         return 0;
911 #endif /* SVR4 */
912
913 }
914
915 void
916 printcall(tcp)
917 struct tcb *tcp;
918 {
919
920 #ifdef LINUX
921 #ifdef I386
922         long eip;
923
924         if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
925                 tprintf("[????????] ");
926                 return;
927         }
928         tprintf("[%08lx] ", eip);
929 #else /* !I386K */
930 #ifdef POWERPC
931         long pc;
932
933         if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0) {
934                 tprintf ("[????????] ");
935                 return;
936         }
937         tprintf("[%08lx] ", pc);
938 #else /* !POWERPC */
939 #ifdef M68K
940         long pc;
941
942         if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
943                 tprintf ("[????????] ");
944                 return;
945         }
946         tprintf("[%08lx] ", pc);
947 #else /* !M68K */
948 #ifdef ALPHA
949         long pc;
950
951         if (upeek(tcp->pid, REG_PC, &pc) < 0) {
952                 tprintf ("[????????] ");
953                 return;
954         }
955         tprintf("[%08lx] ", pc);
956 #else /* !ALPHA */
957 #ifdef SPARC
958         struct pt_regs regs;
959         if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
960                 tprintf("[????????] ");
961                 return;
962         }
963         tprintf("[%08lx] ", regs.pc);
964 #endif /* SPARC */
965 #endif /* ALPHA */
966 #endif /* !M68K */
967 #endif /* !POWERPC */
968 #endif /* !I386 */
969 #endif /* LINUX */
970
971 #ifdef SUNOS4
972         struct regs regs;
973
974         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
975                 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
976                 tprintf("[????????] ");
977                 return;
978         }
979         tprintf("[%08x] ", regs.r_o7);
980 #endif /* SUNOS4 */
981
982 #ifdef SVR4
983         /* XXX */
984         tprintf("[????????] ");
985 #endif
986
987 }
988
989 #ifndef SVR4
990
991 int
992 setbpt(tcp)
993 struct tcb *tcp;
994 {
995
996 #ifdef LINUX
997 #ifdef SPARC
998         /* We simply use the SunOS breakpoint code. */
999
1000         struct pt_regs regs;
1001 #define LOOPA   0x30800000      /* ba,a 0 */
1002
1003         if (tcp->flags & TCB_BPTSET) {
1004                 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1005                 return -1;
1006         }
1007         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1008                 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1009                 return -1;
1010         }
1011         memmove (&regs.u_regs [1], &regs.u_regs [0],
1012                  sizeof (regs.u_regs) - sizeof (regs.u_regs [0]));
1013         tcp->baddr = regs.u_regs[UREG_I7] + 8;
1014         errno = 0;
1015         tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1016         if(errno) {
1017                 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1018                 return -1;
1019         }
1020
1021         /*
1022          * XXX - BRUTAL MODE ON
1023          * We cannot set a real BPT in the child, since it will not be
1024          * traced at the moment it will reach the trap and would probably
1025          * die with a core dump.
1026          * Thus, we are force our way in by taking out two instructions
1027          * and insert an eternal loop instead, in expectance of the SIGSTOP
1028          * generated by out PTRACE_ATTACH.
1029          * Of cause, if we evaporate ourselves in the middle of all this...
1030          */
1031         errno = 0;
1032         ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOPA);
1033         if(errno) {
1034                 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1035                 return -1;
1036         }
1037         tcp->flags |= TCB_BPTSET;
1038
1039 #else /* !SPARC */
1040
1041 #if defined (I386)
1042 #define LOOP    0x0000feeb
1043 #elif defined (M68K)
1044 #define LOOP    0x60fe0000
1045 #elif defined (ALPHA)
1046 #define LOOP    0xc3ffffff
1047 #elif defined (POWERPC)
1048 #define LOOP 0x0000feeb
1049 #elif defined(ARM)
1050 #define LOOP -1  /* almost certainly wrong, jws */
1051 #else
1052 #error unknown architecture
1053 #endif
1054
1055         if (tcp->flags & TCB_BPTSET) {
1056                 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1057                 return -1;
1058         }
1059 #if defined (I386)
1060         if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1061                 return -1;
1062 #elif defined (M68K)
1063         if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1064           return -1;
1065 #elif defined (ALPHA)
1066         return -1;
1067 #elif defined (ARM)
1068         return -1;
1069 #elif defined (POWERPC)
1070         if (upeek(tcp->pid, 4*PT_NIP, &tcp->baddr) < 0)
1071                 return -1;
1072 #else
1073 #error unknown architecture
1074 #endif
1075         if (debug)
1076                 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1077         tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1078         if (errno) {
1079                 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1080                 return -1;
1081         }
1082         ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1083         if (errno) {
1084                 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1085                 return -1;
1086         }
1087         tcp->flags |= TCB_BPTSET;
1088
1089 #endif /* SPARC */
1090 #endif /* LINUX */
1091
1092 #ifdef SUNOS4
1093 #ifdef SPARC    /* This code is slightly sparc specific */
1094
1095         struct pt_regs regs;
1096 #define BPT     0x91d02001      /* ta   1 */
1097 #define LOOP    0x10800000      /* ba   0 */
1098 #define LOOPA   0x30800000      /* ba,a 0 */
1099 #define NOP     0x01000000
1100 #if LOOPA
1101         static int loopdeloop[1] = {LOOPA};
1102 #else
1103         static int loopdeloop[2] = {LOOP, NOP};
1104 #endif
1105
1106         if (tcp->flags & TCB_BPTSET) {
1107                 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1108                 return -1;
1109         }
1110         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1111                 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1112                 return -1;
1113         }
1114         tcp->baddr = regs.r_o7 + 8;
1115         if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1116                                 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1117                 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1118                 return -1;
1119         }
1120
1121         /*
1122          * XXX - BRUTAL MODE ON
1123          * We cannot set a real BPT in the child, since it will not be
1124          * traced at the moment it will reach the trap and would probably
1125          * die with a core dump.
1126          * Thus, we are force our way in by taking out two instructions
1127          * and insert an eternal loop in stead, in expectance of the SIGSTOP
1128          * generated by out PTRACE_ATTACH.
1129          * Of cause, if we evaporate ourselves in the middle of all this...
1130          */
1131         if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1132                         sizeof loopdeloop, (char *) loopdeloop) < 0) {
1133                 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1134                 return -1;
1135         }
1136         tcp->flags |= TCB_BPTSET;
1137
1138 #endif /* SPARC */
1139 #endif /* SUNOS4 */
1140
1141         return 0;
1142 }
1143
1144 int
1145 clearbpt(tcp)
1146 struct tcb *tcp;
1147 {
1148
1149 #ifdef LINUX
1150 #ifdef I386
1151         long eip;
1152 #else /* !I386 */
1153 #ifdef POWERPC
1154         long pc;
1155 #else /* !POWERPC */
1156 #ifdef M68K
1157         long pc;
1158 #else /* !M68K */
1159 #ifdef ALPHA
1160         long pc;
1161 #endif /* ALPHA */
1162 #endif /* !M68K */
1163 #endif /* !POWERPC */
1164 #endif /* !I386 */
1165
1166 #ifdef SPARC
1167         /* Again, we borrow the SunOS breakpoint code. */
1168         if (!(tcp->flags & TCB_BPTSET)) {
1169                 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1170                 return -1;
1171         }
1172         errno = 0;
1173         ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1174         if(errno) {
1175                 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1176                 return -1;
1177         }
1178         tcp->flags &= ~TCB_BPTSET;
1179 #else /* !SPARC */
1180
1181         if (debug)
1182                 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1183         if (!(tcp->flags & TCB_BPTSET)) {
1184                 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1185                 return -1;
1186         }
1187         errno = 0;
1188         ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1189         if (errno) {
1190                 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1191                 return -1;
1192         }
1193         tcp->flags &= ~TCB_BPTSET;
1194
1195 #ifdef I386
1196         if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1197                 return -1;
1198         if (eip != tcp->baddr) {
1199                 /* The breakpoint has not been reached yet.  */
1200                 if (debug)
1201                         fprintf(stderr,
1202                                 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1203                                         eip, tcp->baddr);
1204                 return 0;
1205         }
1206 #else /* !I386 */
1207 #ifdef POWERPC
1208         if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
1209                 return -1;
1210         if (pc != tcp->baddr) {
1211                 /* The breakpoint has not been reached yet.  */
1212                 if (debug)
1213                         fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1214                                 pc, tcp->baddr);
1215                 return 0;
1216         }
1217 #else /* !POWERPC */
1218 #ifdef M68K
1219         if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1220                 return -1;
1221         if (pc != tcp->baddr) {
1222                 /* The breakpoint has not been reached yet.  */
1223                 if (debug)
1224                         fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1225                                 pc, tcp->baddr);
1226                 return 0;
1227         }
1228 #else /* !M68K */
1229 #ifdef ALPHA
1230         if (upeek(tcp->pid, REG_PC, &pc) < 0)
1231                 return -1;
1232         if (pc != tcp->baddr) {
1233                 /* The breakpoint has not been reached yet.  */
1234                 if (debug)
1235                         fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1236                                 pc, tcp->baddr);
1237                 return 0;
1238         }
1239 #endif /* ALPHA */
1240 #endif /* !M68K */
1241 #endif /* !POWERPC */
1242 #endif /* !I386 */
1243 #endif /* !SPARC */
1244 #endif /* LINUX */
1245
1246 #ifdef SUNOS4
1247 #ifdef SPARC
1248
1249 #if !LOOPA
1250         struct pt_regs regs;
1251 #endif
1252
1253         if (!(tcp->flags & TCB_BPTSET)) {
1254                 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1255                 return -1;
1256         }
1257         if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1258                                 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1259                 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1260                 return -1;
1261         }
1262         tcp->flags &= ~TCB_BPTSET;
1263
1264 #if !LOOPA
1265         /*
1266          * Since we don't have a single instruction breakpoint, we may have
1267          * to adjust the program counter after removing the our `breakpoint'.
1268          */
1269         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1270                 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1271                 return -1;
1272         }
1273         if ((regs.r_pc < tcp->baddr) ||
1274                                 (regs.r_pc > tcp->baddr + 4)) {
1275                 /* The breakpoint has not been reached yet */
1276                 if (debug)
1277                         fprintf(stderr,
1278                                 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1279                                         regs.r_pc, tcp->parent->baddr);
1280                 return 0;
1281         }
1282         if (regs.r_pc != tcp->baddr)
1283                 if (debug)
1284                         fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1285                                 regs.r_pc, tcp->baddr);
1286
1287         regs.r_pc = tcp->baddr;
1288         if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1289                 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1290                 return -1;
1291         }
1292 #endif /* LOOPA */
1293 #endif /* SPARC */
1294 #endif /* SUNOS4 */
1295
1296         return 0;
1297 }
1298
1299 #endif /* !SVR4 */
1300
1301 #ifdef SUNOS4
1302
1303 static int
1304 getex(pid, hdr)
1305 int pid;
1306 struct exec *hdr;
1307 {
1308         int n;
1309
1310         for (n = 0; n < sizeof *hdr; n += 4) {
1311                 long res;
1312                 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
1313                         return -1;
1314                 memcpy(((char *) hdr) + n, &res, 4);
1315         }
1316         if (debug) {
1317                 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1318                         hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1319                 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1320                         hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1321         }
1322         return 0;
1323 }
1324
1325 int
1326 fixvfork(tcp)
1327 struct tcb *tcp;
1328 {
1329         int pid = tcp->pid;
1330         /*
1331          * Change `vfork' in a freshly exec'ed dynamically linked
1332          * executable's (internal) symbol table to plain old `fork'
1333          */
1334
1335         struct exec hdr;
1336         struct link_dynamic dyn;
1337         struct link_dynamic_2 ld;
1338         char *strtab, *cp;
1339
1340         if (getex(pid, &hdr) < 0)
1341                 return -1;
1342         if (!hdr.a_dynamic)
1343                 return -1;
1344
1345         if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1346                 fprintf(stderr, "Cannot read DYNAMIC\n");
1347                 return -1;
1348         }
1349         if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1350                 fprintf(stderr, "Cannot read link_dynamic_2\n");
1351                 return -1;
1352         }
1353         if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
1354                 fprintf(stderr, "fixvfork: out of memory\n");
1355                 return -1;
1356         }
1357         if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1358                                         (int)ld.ld_symb_size, strtab) < 0)
1359                 goto err;
1360
1361 #if 0
1362         for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1363                 fprintf(stderr, "[symbol: %s]\n", cp);
1364                 cp += strlen(cp)+1;
1365         }
1366         return 0;
1367 #endif
1368         for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1369                 if (strcmp(cp, "_vfork") == 0) {
1370                         if (debug)
1371                                 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1372                         strcpy(cp, "_fork");
1373                         break;
1374                 }
1375                 cp += strlen(cp)+1;
1376         }
1377         if (cp < strtab + ld.ld_symb_size)
1378                 /*
1379                  * Write entire symbol table back to avoid
1380                  * memory alignment bugs in ptrace
1381                  */
1382                 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1383                                         (int)ld.ld_symb_size, strtab) < 0)
1384                         goto err;
1385
1386         free(strtab);
1387         return 0;
1388
1389 err:
1390         free(strtab);
1391         return -1;
1392 }
1393
1394 #endif /* SUNOS4 */