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