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