]> granicus.if.org Git - strace/blob - util.c
Reduce bss usage and speed up string printing
[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 <signal.h>
39 #include <sys/syscall.h>
40 #include <sys/user.h>
41 #include <sys/param.h>
42 #include <fcntl.h>
43 #if HAVE_SYS_UIO_H
44 #include <sys/uio.h>
45 #endif
46 #ifdef SUNOS4
47 #include <machine/reg.h>
48 #include <a.out.h>
49 #include <link.h>
50 #endif /* SUNOS4 */
51
52 #if defined(linux) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1))
53 #include <linux/ptrace.h>
54 #endif
55
56 #if defined(LINUX) && defined(IA64)
57 # include <asm/ptrace_offsets.h>
58 # include <asm/rse.h>
59 #endif
60
61 #ifdef HAVE_SYS_REG_H
62 #include <sys/reg.h>
63 # define PTRACE_PEEKUSR PTRACE_PEEKUSER
64 #elif defined(HAVE_LINUX_PTRACE_H)
65 #undef PTRACE_SYSCALL
66 # ifdef HAVE_STRUCT_IA64_FPREG
67 #  define ia64_fpreg XXX_ia64_fpreg
68 # endif
69 # ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70 #  define pt_all_user_regs XXX_pt_all_user_regs
71 # endif
72 #include <linux/ptrace.h>
73 # undef ia64_fpreg
74 # undef pt_all_user_regs
75 #endif
76
77 #ifdef SUNOS4_KERNEL_ARCH_KLUDGE
78 #include <sys/utsname.h>
79 #endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
80
81 #if defined(LINUXSPARC) && defined (SPARC64)
82 # undef PTRACE_GETREGS
83 # define PTRACE_GETREGS PTRACE_GETREGS64
84 # undef PTRACE_SETREGS
85 # define PTRACE_SETREGS PTRACE_SETREGS64
86 #endif
87
88 /* macros */
89 #ifndef MAX
90 #define MAX(a,b)                (((a) > (b)) ? (a) : (b))
91 #endif
92 #ifndef MIN
93 #define MIN(a,b)                (((a) < (b)) ? (a) : (b))
94 #endif
95
96 int
97 tv_nz(struct timeval *a)
98 {
99         return a->tv_sec || a->tv_usec;
100 }
101
102 int
103 tv_cmp(struct timeval *a, struct timeval *b)
104 {
105         if (a->tv_sec < b->tv_sec
106             || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
107                 return -1;
108         if (a->tv_sec > b->tv_sec
109             || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
110                 return 1;
111         return 0;
112 }
113
114 double
115 tv_float(struct timeval *tv)
116 {
117         return tv->tv_sec + tv->tv_usec/1000000.0;
118 }
119
120 void
121 tv_add(struct timeval *tv, struct timeval *a, struct timeval *b)
122 {
123         tv->tv_sec = a->tv_sec + b->tv_sec;
124         tv->tv_usec = a->tv_usec + b->tv_usec;
125         if (tv->tv_usec >= 1000000) {
126                 tv->tv_sec++;
127                 tv->tv_usec -= 1000000;
128         }
129 }
130
131 void
132 tv_sub(struct timeval *tv, struct timeval *a, struct timeval *b)
133 {
134         tv->tv_sec = a->tv_sec - b->tv_sec;
135         tv->tv_usec = a->tv_usec - b->tv_usec;
136         if (((long) tv->tv_usec) < 0) {
137                 tv->tv_sec--;
138                 tv->tv_usec += 1000000;
139         }
140 }
141
142 void
143 tv_div(struct timeval *tv, struct timeval *a, int n)
144 {
145         tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
146         tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
147         tv->tv_usec %= 1000000;
148 }
149
150 void
151 tv_mul(struct timeval *tv, struct timeval *a, int n)
152 {
153         tv->tv_usec = a->tv_usec * n;
154         tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
155         tv->tv_usec %= 1000000;
156 }
157
158 const char *
159 xlookup(const struct xlat *xlat, int val)
160 {
161         for (; xlat->str != NULL; xlat++)
162                 if (xlat->val == val)
163                         return xlat->str;
164         return NULL;
165 }
166
167 #if !defined HAVE_STPCPY
168 char *
169 stpcpy(char *dst, const char *src)
170 {
171         while ((*dst = *src++) != '\0')
172                 dst++;
173         return dst;
174 }
175 #endif
176
177 /*
178  * Generic ptrace wrapper which tracks ESRCH errors
179  * by setting tcp->ptrace_errno to ESRCH.
180  *
181  * We assume that ESRCH indicates likely process death (SIGKILL?),
182  * modulo bugs where process somehow ended up not stopped.
183  * Unfortunately kernel uses ESRCH for that case too. Oh well.
184  *
185  * Currently used by upeek() only.
186  * TODO: use this in all other ptrace() calls while decoding.
187  */
188 long
189 do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
190 {
191         long l;
192
193         errno = 0;
194         l = ptrace(request, tcp->pid, addr, (long) data);
195         /* Non-ESRCH errors might be our invalid reg/mem accesses,
196          * we do not record them. */
197         if (errno == ESRCH)
198                 tcp->ptrace_errno = ESRCH;
199         return l;
200 }
201
202 /*
203  * Used when we want to unblock stopped traced process.
204  * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
205  * Returns 0 on success or if error was ESRCH
206  * (presumably process was killed while we talk to it).
207  * Otherwise prints error message and returns -1.
208  */
209 int
210 ptrace_restart(int op, struct tcb *tcp, int sig)
211 {
212         int err;
213         const char *msg;
214
215         errno = 0;
216         ptrace(op, tcp->pid, (void *) 1, (long) sig);
217         err = errno;
218         if (!err || err == ESRCH)
219                 return 0;
220
221         tcp->ptrace_errno = err;
222         msg = "SYSCALL";
223         if (op == PTRACE_CONT)
224                 msg = "CONT";
225         if (op == PTRACE_DETACH)
226                 msg = "DETACH";
227         perror_msg("ptrace(PTRACE_%s,1,%d)", msg, sig);
228         return -1;
229 }
230
231 /*
232  * Print entry in struct xlat table, if there.
233  */
234 void
235 printxval(const struct xlat *xlat, int val, const char *dflt)
236 {
237         const char *str = xlookup(xlat, val);
238
239         if (str)
240                 tprints(str);
241         else
242                 tprintf("%#x /* %s */", val, dflt);
243 }
244
245 #if HAVE_LONG_LONG
246 /*
247  * Print 64bit argument at position llarg and return the index of the next
248  * argument.
249  */
250 int
251 printllval(struct tcb *tcp, const char *format, int llarg)
252 {
253 # if defined(FREEBSD) \
254      || (defined(LINUX) && defined(POWERPC) && !defined(POWERPC64)) \
255      || defined(LINUX_MIPSO32) \
256      || defined(__ARM_EABI__)
257         /* Align 64bit argument to 64bit boundary.  */
258         llarg = (llarg + 1) & 0x1e;
259 # endif
260 # if defined LINUX && (defined X86_64 || defined POWERPC64)
261         if (current_personality == 0) {
262                 tprintf(format, tcp->u_arg[llarg]);
263                 llarg++;
264         } else {
265 #  ifdef POWERPC64
266                 /* Align 64bit argument to 64bit boundary.  */
267                 llarg = (llarg + 1) & 0x1e;
268 #  endif
269                 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
270                 llarg += 2;
271         }
272 # elif defined IA64 || defined ALPHA
273         tprintf(format, tcp->u_arg[llarg]);
274         llarg++;
275 # elif defined LINUX_MIPSN32
276         tprintf(format, tcp->ext_arg[llarg]);
277         llarg++;
278 # else
279         tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
280         llarg += 2;
281 # endif
282         return llarg;
283 }
284 #endif
285
286 /*
287  * Interpret `xlat' as an array of flags
288  * print the entries whose bits are on in `flags'
289  * return # of flags printed.
290  */
291 void
292 addflags(const struct xlat *xlat, int flags)
293 {
294         for (; xlat->str; xlat++) {
295                 if (xlat->val && (flags & xlat->val) == xlat->val) {
296                         tprintf("|%s", xlat->str);
297                         flags &= ~xlat->val;
298                 }
299         }
300         if (flags) {
301                 tprintf("|%#x", flags);
302         }
303 }
304
305 /*
306  * Interpret `xlat' as an array of flags.
307  * Print to static string the entries whose bits are on in `flags'
308  * Return static string.
309  */
310 const char *
311 sprintflags(const char *prefix, const struct xlat *xlat, int flags)
312 {
313         static char outstr[1024];
314         char *outptr;
315         int found = 0;
316
317         outptr = stpcpy(outstr, prefix);
318
319         for (; xlat->str; xlat++) {
320                 if ((flags & xlat->val) == xlat->val) {
321                         if (found)
322                                 *outptr++ = '|';
323                         outptr = stpcpy(outptr, xlat->str);
324                         flags &= ~xlat->val;
325                         found = 1;
326                 }
327         }
328         if (flags) {
329                 if (found)
330                         *outptr++ = '|';
331                 outptr += sprintf(outptr, "%#x", flags);
332         }
333
334         return outstr;
335 }
336
337 int
338 printflags(const struct xlat *xlat, int flags, const char *dflt)
339 {
340         int n;
341         const char *sep;
342
343         if (flags == 0 && xlat->val == 0) {
344                 tprints(xlat->str);
345                 return 1;
346         }
347
348         sep = "";
349         for (n = 0; xlat->str; xlat++) {
350                 if (xlat->val && (flags & xlat->val) == xlat->val) {
351                         tprintf("%s%s", sep, xlat->str);
352                         flags &= ~xlat->val;
353                         sep = "|";
354                         n++;
355                 }
356         }
357
358         if (n) {
359                 if (flags) {
360                         tprintf("%s%#x", sep, flags);
361                         n++;
362                 }
363         } else {
364                 if (flags) {
365                         tprintf("%#x", flags);
366                         if (dflt)
367                                 tprintf(" /* %s */", dflt);
368                 } else {
369                         if (dflt)
370                                 tprints("0");
371                 }
372         }
373
374         return n;
375 }
376
377 void
378 printnum(struct tcb *tcp, long addr, const char *fmt)
379 {
380         long num;
381
382         if (!addr) {
383                 tprints("NULL");
384                 return;
385         }
386         if (umove(tcp, addr, &num) < 0) {
387                 tprintf("%#lx", addr);
388                 return;
389         }
390         tprints("[");
391         tprintf(fmt, num);
392         tprints("]");
393 }
394
395 void
396 printnum_int(struct tcb *tcp, long addr, const char *fmt)
397 {
398         int num;
399
400         if (!addr) {
401                 tprints("NULL");
402                 return;
403         }
404         if (umove(tcp, addr, &num) < 0) {
405                 tprintf("%#lx", addr);
406                 return;
407         }
408         tprints("[");
409         tprintf(fmt, num);
410         tprints("]");
411 }
412
413 void
414 printfd(struct tcb *tcp, int fd)
415 {
416         const char *p;
417
418         if (show_fd_path && (p = getfdpath(tcp, fd)))
419                 tprintf("%d<%s>", fd, p);
420         else
421                 tprintf("%d", fd);
422 }
423
424 void
425 printuid(const char *text, unsigned long uid)
426 {
427         tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
428 }
429
430 /*
431  * Quote string `instr' of length `size'
432  * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
433  * If `len' < 0, treat `instr' as a NUL-terminated string
434  * and quote at most (`size' - 1) bytes.
435  */
436 static int
437 string_quote(const char *instr, char *outstr, int len, int size)
438 {
439         const unsigned char *ustr = (const unsigned char *) instr;
440         char *s = outstr;
441         int usehex, c, i, eol;
442
443         eol = 0x100; /* this can never match a char */
444         if (len < 0) {
445                 size--;
446                 eol = '\0';
447         }
448
449         usehex = 0;
450         if (xflag > 1)
451                 usehex = 1;
452         else if (xflag) {
453                 /* Check for presence of symbol which require
454                    to hex-quote the whole string. */
455                 for (i = 0; i < size; ++i) {
456                         c = ustr[i];
457                         /* Check for NUL-terminated string. */
458                         if (c == eol)
459                                 break;
460                         if (!isprint(c) && !isspace(c)) {
461                                 usehex = 1;
462                                 break;
463                         }
464                 }
465         }
466
467         *s++ = '\"';
468
469         if (usehex) {
470                 /* Hex-quote the whole string. */
471                 for (i = 0; i < size; ++i) {
472                         c = ustr[i];
473                         /* Check for NUL-terminated string. */
474                         if (c == eol)
475                                 goto asciz_ended;
476                         *s++ = '\\';
477                         *s++ = 'x';
478                         *s++ = "0123456789abcdef"[c >> 4];
479                         *s++ = "0123456789abcdef"[c & 0xf];
480                 }
481         } else {
482                 for (i = 0; i < size; ++i) {
483                         c = ustr[i];
484                         /* Check for NUL-terminated string. */
485                         if (c == eol)
486                                 goto asciz_ended;
487                         switch (c) {
488                                 case '\"': case '\\':
489                                         *s++ = '\\';
490                                         *s++ = c;
491                                         break;
492                                 case '\f':
493                                         *s++ = '\\';
494                                         *s++ = 'f';
495                                         break;
496                                 case '\n':
497                                         *s++ = '\\';
498                                         *s++ = 'n';
499                                         break;
500                                 case '\r':
501                                         *s++ = '\\';
502                                         *s++ = 'r';
503                                         break;
504                                 case '\t':
505                                         *s++ = '\\';
506                                         *s++ = 't';
507                                         break;
508                                 case '\v':
509                                         *s++ = '\\';
510                                         *s++ = 'v';
511                                         break;
512                                 default:
513                                         if (isprint(c))
514                                                 *s++ = c;
515                                         else {
516                                                 /* Print \octal */
517                                                 *s++ = '\\';
518                                                 if (i + 1 < size
519                                                     && ustr[i + 1] >= '0'
520                                                     && ustr[i + 1] <= '9'
521                                                 ) {
522                                                         /* Print \ooo */
523                                                         *s++ = '0' + (c >> 6);
524                                                         *s++ = '0' + ((c >> 3) & 0x7);
525                                                 } else {
526                                                         /* Print \[[o]o]o */
527                                                         if ((c >> 3) != 0) {
528                                                                 if ((c >> 6) != 0)
529                                                                         *s++ = '0' + (c >> 6);
530                                                                 *s++ = '0' + ((c >> 3) & 0x7);
531                                                         }
532                                                 }
533                                                 *s++ = '0' + (c & 0x7);
534                                         }
535                                         break;
536                         }
537                 }
538         }
539
540         *s++ = '\"';
541         *s = '\0';
542
543         /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
544         if (len < 0 && ustr[i] == '\0') {
545                 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
546                  * but next char is NUL.
547                  */
548                 return 0;
549         }
550
551         return 1;
552
553  asciz_ended:
554         *s++ = '\"';
555         *s = '\0';
556         /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
557         return 0;
558 }
559
560 /*
561  * Print path string specified by address `addr' and length `n'.
562  * If path length exceeds `n', append `...' to the output.
563  */
564 void
565 printpathn(struct tcb *tcp, long addr, int n)
566 {
567         char path[MAXPATHLEN + 1];
568
569         if (!addr) {
570                 tprints("NULL");
571                 return;
572         }
573
574         /* Cap path length to the path buffer size,
575            and NUL-terminate the buffer. */
576         if (n > sizeof path - 1)
577                 n = sizeof path - 1;
578         path[n] = '\0';
579
580         /* Fetch one byte more to find out whether path length > n. */
581         if (umovestr(tcp, addr, n + 1, path) < 0)
582                 tprintf("%#lx", addr);
583         else {
584                 char *outstr;
585                 int trunc = (path[n] != '\0');
586
587                 if (trunc)
588                         path[n] = '\0';
589                 n++;
590                 outstr = alloca(4 * n); /* 4*(n-1) + 2 for quotes */
591                 string_quote(path, outstr, -1, n);
592                 tprints(outstr);
593                 if (trunc)
594                         tprints("...");
595         }
596 }
597
598 void
599 printpath(struct tcb *tcp, long addr)
600 {
601         /* Size must correspond to char path[] size in printpathn */
602         printpathn(tcp, addr, MAXPATHLEN);
603 }
604
605 /*
606  * Print string specified by address `addr' and length `len'.
607  * If `len' < 0, treat the string as a NUL-terminated string.
608  * If string length exceeds `max_strlen', append `...' to the output.
609  */
610 void
611 printstr(struct tcb *tcp, long addr, int len)
612 {
613         static char *str = NULL;
614         static char *outstr;
615         int size;
616         int ellipsis;
617
618         if (!addr) {
619                 tprints("NULL");
620                 return;
621         }
622         /* Allocate static buffers if they are not allocated yet. */
623         if (!str) {
624                 str = malloc(max_strlen + 1);
625                 if (!str)
626                         die_out_of_memory();
627                 outstr = malloc(4 * max_strlen + /*for quotes:*/ 2);
628                 if (!outstr)
629                         die_out_of_memory();
630         }
631
632         if (len < 0) {
633                 /*
634                  * Treat as a NUL-terminated string: fetch one byte more
635                  * because string_quote() quotes one byte less.
636                  */
637                 size = max_strlen + 1;
638                 str[max_strlen] = '\0';
639         /* FIXME! umovestr can overwrite the '\0' stored above??? */
640                 if (umovestr(tcp, addr, size, str) < 0) {
641                         tprintf("%#lx", addr);
642                         return;
643                 }
644         }
645         else {
646                 size = MIN(len, max_strlen);
647                 if (umoven(tcp, addr, size, str) < 0) {
648                         tprintf("%#lx", addr);
649                         return;
650                 }
651         }
652
653         ellipsis = (string_quote(str, outstr, len, size) &&
654                         (len < 0 || len > max_strlen));
655
656         tprints(outstr);
657         if (ellipsis)
658                 tprints("...");
659 }
660
661 #if HAVE_SYS_UIO_H
662 void
663 dumpiov(struct tcb *tcp, int len, long addr)
664 {
665 #if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
666         union {
667                 struct { u_int32_t base; u_int32_t len; } *iov32;
668                 struct { u_int64_t base; u_int64_t len; } *iov64;
669         } iovu;
670 #define iov iovu.iov64
671 #define sizeof_iov \
672   (personality_wordsize[current_personality] == 4 \
673    ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
674 #define iov_iov_base(i) \
675   (personality_wordsize[current_personality] == 4 \
676    ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
677 #define iov_iov_len(i) \
678   (personality_wordsize[current_personality] == 4 \
679    ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
680 #else
681         struct iovec *iov;
682 #define sizeof_iov sizeof(*iov)
683 #define iov_iov_base(i) iov[i].iov_base
684 #define iov_iov_len(i) iov[i].iov_len
685 #endif
686         int i;
687         unsigned size;
688
689         size = sizeof_iov * len;
690         /* Assuming no sane program has millions of iovs */
691         if ((unsigned)len > 1024*1024 /* insane or negative size? */
692             || (iov = malloc(size)) == NULL) {
693                 fprintf(stderr, "Out of memory\n");
694                 return;
695         }
696         if (umoven(tcp, addr, size, (char *) iov) >= 0) {
697                 for (i = 0; i < len; i++) {
698                         /* include the buffer number to make it easy to
699                          * match up the trace with the source */
700                         tprintf(" * %lu bytes in buffer %d\n",
701                                 (unsigned long)iov_iov_len(i), i);
702                         dumpstr(tcp, (long) iov_iov_base(i),
703                                 iov_iov_len(i));
704                 }
705         }
706         free(iov);
707 #undef sizeof_iov
708 #undef iov_iov_base
709 #undef iov_iov_len
710 #undef iov
711 }
712 #endif
713
714 void
715 dumpstr(struct tcb *tcp, long addr, int len)
716 {
717         static int strsize = -1;
718         static unsigned char *str;
719         char *s;
720         int i, j;
721
722         if (strsize < len) {
723                 free(str);
724                 str = malloc(len);
725                 if (!str) {
726                         strsize = -1;
727                         fprintf(stderr, "Out of memory\n");
728                         return;
729                 }
730                 strsize = len;
731         }
732
733         if (umoven(tcp, addr, len, (char *) str) < 0)
734                 return;
735
736         for (i = 0; i < len; i += 16) {
737                 char outstr[80];
738
739                 s = outstr;
740                 sprintf(s, " | %05x ", i);
741                 s += 9;
742                 for (j = 0; j < 16; j++) {
743                         if (j == 8)
744                                 *s++ = ' ';
745                         if (i + j < len) {
746                                 sprintf(s, " %02x", str[i + j]);
747                                 s += 3;
748                         }
749                         else {
750                                 *s++ = ' '; *s++ = ' '; *s++ = ' ';
751                         }
752                 }
753                 *s++ = ' '; *s++ = ' ';
754                 for (j = 0; j < 16; j++) {
755                         if (j == 8)
756                                 *s++ = ' ';
757                         if (i + j < len) {
758                                 if (isprint(str[i + j]))
759                                         *s++ = str[i + j];
760                                 else
761                                         *s++ = '.';
762                         }
763                         else
764                                 *s++ = ' ';
765                 }
766                 tprintf("%s |\n", outstr);
767         }
768 }
769
770 #define PAGMASK (~(PAGSIZ - 1))
771 /*
772  * move `len' bytes of data from process `pid'
773  * at address `addr' to our space at `laddr'
774  */
775 int
776 umoven(struct tcb *tcp, long addr, int len, char *laddr)
777 {
778 #ifdef LINUX
779         int pid = tcp->pid;
780         int n, m;
781         int started = 0;
782         union {
783                 long val;
784                 char x[sizeof(long)];
785         } u;
786
787 #if SUPPORTED_PERSONALITIES > 1
788         if (personality_wordsize[current_personality] < sizeof(addr))
789                 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
790 #endif
791
792         if (addr & (sizeof(long) - 1)) {
793                 /* addr not a multiple of sizeof(long) */
794                 n = addr - (addr & -sizeof(long)); /* residue */
795                 addr &= -sizeof(long); /* residue */
796                 errno = 0;
797                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
798                 if (errno) {
799                         /* But if not started, we had a bogus address. */
800                         if (addr != 0 && errno != EIO && errno != ESRCH)
801                                 perror("ptrace: umoven");
802                         return -1;
803                 }
804                 started = 1;
805                 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
806                 addr += sizeof(long), laddr += m, len -= m;
807         }
808         while (len) {
809                 errno = 0;
810                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
811                 if (errno) {
812                         if (started && (errno==EPERM || errno==EIO)) {
813                                 /* Ran into 'end of memory' - stupid "printpath" */
814                                 return 0;
815                         }
816                         if (addr != 0 && errno != EIO && errno != ESRCH)
817                                 perror("ptrace: umoven");
818                         return -1;
819                 }
820                 started = 1;
821                 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
822                 addr += sizeof(long), laddr += m, len -= m;
823         }
824 #endif /* LINUX */
825
826 #ifdef SUNOS4
827         int pid = tcp->pid;
828         int n;
829
830         while (len) {
831                 n = MIN(len, PAGSIZ);
832                 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
833                 if (ptrace(PTRACE_READDATA, pid,
834                            (char *) addr, len, laddr) < 0) {
835                         if (errno != ESRCH) {
836                                 perror("umoven: ptrace(PTRACE_READDATA, ...)");
837                                 abort();
838                         }
839                         return -1;
840                 }
841                 len -= n;
842                 addr += n;
843                 laddr += n;
844         }
845 #endif /* SUNOS4 */
846
847 #ifdef USE_PROCFS
848 #ifdef HAVE_MP_PROCFS
849         int fd = tcp->pfd_as;
850 #else
851         int fd = tcp->pfd;
852 #endif
853         lseek(fd, addr, SEEK_SET);
854         if (read(fd, laddr, len) == -1)
855                 return -1;
856 #endif /* USE_PROCFS */
857
858         return 0;
859 }
860
861 /*
862  * like `umove' but make the additional effort of looking
863  * for a terminating zero byte.
864  */
865 int
866 umovestr(struct tcb *tcp, long addr, int len, char *laddr)
867 {
868 #ifdef USE_PROCFS
869 #ifdef HAVE_MP_PROCFS
870         int fd = tcp->pfd_as;
871 #else
872         int fd = tcp->pfd;
873 #endif
874         /* Some systems (e.g. FreeBSD) can be upset if we read off the
875            end of valid memory,  avoid this by trying to read up
876            to page boundaries.  But we don't know what a page is (and
877            getpagesize(2) (if it exists) doesn't necessarily return
878            hardware page size).  Assume all pages >= 1024 (a-historical
879            I know) */
880
881         int page = 1024;        /* How to find this? */
882         int move = page - (addr & (page - 1));
883         int left = len;
884
885         lseek(fd, addr, SEEK_SET);
886
887         while (left) {
888                 if (move > left)
889                         move = left;
890                 move = read(fd, laddr, move);
891                 if (move <= 0)
892                         return left != len ? 0 : -1;
893                 if (memchr(laddr, 0, move))
894                         break;
895                 left -= move;
896                 laddr += move;
897                 addr += move;
898                 move = page;
899         }
900 #else /* !USE_PROCFS */
901         int started = 0;
902         int pid = tcp->pid;
903         int i, n, m;
904         union {
905                 long val;
906                 char x[sizeof(long)];
907         } u;
908
909 #if SUPPORTED_PERSONALITIES > 1
910         if (personality_wordsize[current_personality] < sizeof(addr))
911                 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
912 #endif
913
914         if (addr & (sizeof(long) - 1)) {
915                 /* addr not a multiple of sizeof(long) */
916                 n = addr - (addr & -sizeof(long)); /* residue */
917                 addr &= -sizeof(long); /* residue */
918                 errno = 0;
919                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
920                 if (errno) {
921                         if (addr != 0 && errno != EIO && errno != ESRCH)
922                                 perror("umovestr");
923                         return -1;
924                 }
925                 started = 1;
926                 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
927                 while (n & (sizeof(long) - 1))
928                         if (u.x[n++] == '\0')
929                                 return 0;
930                 addr += sizeof(long), laddr += m, len -= m;
931         }
932         while (len) {
933                 errno = 0;
934                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
935                 if (errno) {
936                         if (started && (errno==EPERM || errno==EIO)) {
937                                 /* Ran into 'end of memory' - stupid "printpath" */
938                                 return 0;
939                         }
940                         if (addr != 0 && errno != EIO && errno != ESRCH)
941                                 perror("umovestr");
942                         return -1;
943                 }
944                 started = 1;
945                 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
946                 for (i = 0; i < sizeof(long); i++)
947                         if (u.x[i] == '\0')
948                                 return 0;
949
950                 addr += sizeof(long), laddr += m, len -= m;
951         }
952 #endif /* !USE_PROCFS */
953         return 0;
954 }
955
956 #ifdef LINUX
957 # if !defined (SPARC) && !defined(SPARC64)
958 #  define PTRACE_WRITETEXT      101
959 #  define PTRACE_WRITEDATA      102
960 # endif /* !SPARC && !SPARC64 */
961 #endif /* LINUX */
962
963 #ifdef SUNOS4
964
965 static int
966 uload(int cmd, int pid, long addr, int len, char *laddr)
967 {
968         int peek, poke;
969         int n, m;
970         union {
971                 long val;
972                 char x[sizeof(long)];
973         } u;
974
975         if (cmd == PTRACE_WRITETEXT) {
976                 peek = PTRACE_PEEKTEXT;
977                 poke = PTRACE_POKETEXT;
978         }
979         else {
980                 peek = PTRACE_PEEKDATA;
981                 poke = PTRACE_POKEDATA;
982         }
983         if (addr & (sizeof(long) - 1)) {
984                 /* addr not a multiple of sizeof(long) */
985                 n = addr - (addr & -sizeof(long)); /* residue */
986                 addr &= -sizeof(long);
987                 errno = 0;
988                 u.val = ptrace(peek, pid, (char *) addr, 0);
989                 if (errno) {
990                         perror("uload: POKE");
991                         return -1;
992                 }
993                 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
994                 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
995                         perror("uload: POKE");
996                         return -1;
997                 }
998                 addr += sizeof(long), laddr += m, len -= m;
999         }
1000         while (len) {
1001                 if (len < sizeof(long))
1002                         u.val = ptrace(peek, pid, (char *) addr, 0);
1003                 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
1004                 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1005                         perror("uload: POKE");
1006                         return -1;
1007                 }
1008                 addr += sizeof(long), laddr += m, len -= m;
1009         }
1010         return 0;
1011 }
1012
1013 int
1014 tload(int pid, int addr, int len, char *laddr)
1015 {
1016         return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1017 }
1018
1019 int
1020 dload(int pid, int addr, int len, char *laddr)
1021 {
1022         return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
1023 }
1024
1025 #endif /* SUNOS4 */
1026
1027 #ifndef USE_PROCFS
1028
1029 int
1030 upeek(struct tcb *tcp, long off, long *res)
1031 {
1032         long val;
1033
1034 # ifdef SUNOS4_KERNEL_ARCH_KLUDGE
1035         {
1036                 static int is_sun4m = -1;
1037                 struct utsname name;
1038
1039                 /* Round up the usual suspects. */
1040                 if (is_sun4m == -1) {
1041                         if (uname(&name) < 0) {
1042                                 perror("upeek: uname?");
1043                                 exit(1);
1044                         }
1045                         is_sun4m = strcmp(name.machine, "sun4m") == 0;
1046                         if (is_sun4m) {
1047                                 const struct xlat *x;
1048
1049                                 for (x = struct_user_offsets; x->str; x++)
1050                                         x->val += 1024;
1051                         }
1052                 }
1053                 if (is_sun4m)
1054                         off += 1024;
1055         }
1056 # endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
1057         errno = 0;
1058         val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
1059         if (val == -1 && errno) {
1060                 if (errno != ESRCH) {
1061                         char buf[60];
1062                         sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
1063                         perror(buf);
1064                 }
1065                 return -1;
1066         }
1067         *res = val;
1068         return 0;
1069 }
1070
1071 #endif /* !USE_PROCFS */
1072
1073 void
1074 printcall(struct tcb *tcp)
1075 {
1076 #define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1077                            sizeof(long) == 8 ? "[????????????????] " : \
1078                            NULL /* crash */)
1079
1080 #ifdef LINUX
1081 # ifdef I386
1082         long eip;
1083
1084         if (upeek(tcp, 4*EIP, &eip) < 0) {
1085                 PRINTBADPC;
1086                 return;
1087         }
1088         tprintf("[%08lx] ", eip);
1089
1090 # elif defined(S390) || defined(S390X)
1091         long psw;
1092         if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
1093                 PRINTBADPC;
1094                 return;
1095         }
1096 #  ifdef S390
1097         tprintf("[%08lx] ", psw);
1098 #  elif S390X
1099         tprintf("[%16lx] ", psw);
1100 #  endif
1101
1102 # elif defined(X86_64)
1103         long rip;
1104
1105         if (upeek(tcp, 8*RIP, &rip) < 0) {
1106                 PRINTBADPC;
1107                 return;
1108         }
1109         tprintf("[%16lx] ", rip);
1110 # elif defined(IA64)
1111         long ip;
1112
1113         if (upeek(tcp, PT_B0, &ip) < 0) {
1114                 PRINTBADPC;
1115                 return;
1116         }
1117         tprintf("[%08lx] ", ip);
1118 # elif defined(POWERPC)
1119         long pc;
1120
1121         if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
1122                 PRINTBADPC;
1123                 return;
1124         }
1125 #  ifdef POWERPC64
1126         tprintf("[%016lx] ", pc);
1127 #  else
1128         tprintf("[%08lx] ", pc);
1129 #  endif
1130 # elif defined(M68K)
1131         long pc;
1132
1133         if (upeek(tcp, 4*PT_PC, &pc) < 0) {
1134                 tprints("[????????] ");
1135                 return;
1136         }
1137         tprintf("[%08lx] ", pc);
1138 # elif defined(ALPHA)
1139         long pc;
1140
1141         if (upeek(tcp, REG_PC, &pc) < 0) {
1142                 tprints("[????????????????] ");
1143                 return;
1144         }
1145         tprintf("[%08lx] ", pc);
1146 # elif defined(SPARC) || defined(SPARC64)
1147         struct pt_regs regs;
1148         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1149                 PRINTBADPC;
1150                 return;
1151         }
1152 #  if defined(SPARC64)
1153         tprintf("[%08lx] ", regs.tpc);
1154 #  else
1155         tprintf("[%08lx] ", regs.pc);
1156 #  endif
1157 # elif defined(HPPA)
1158         long pc;
1159
1160         if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
1161                 tprints("[????????] ");
1162                 return;
1163         }
1164         tprintf("[%08lx] ", pc);
1165 # elif defined(MIPS)
1166         long pc;
1167
1168         if (upeek(tcp, REG_EPC, &pc) < 0) {
1169                 tprints("[????????] ");
1170                 return;
1171         }
1172         tprintf("[%08lx] ", pc);
1173 # elif defined(SH)
1174         long pc;
1175
1176         if (upeek(tcp, 4*REG_PC, &pc) < 0) {
1177                 tprints("[????????] ");
1178                 return;
1179         }
1180         tprintf("[%08lx] ", pc);
1181 # elif defined(SH64)
1182         long pc;
1183
1184         if (upeek(tcp, REG_PC, &pc) < 0) {
1185                 tprints("[????????????????] ");
1186                 return;
1187         }
1188         tprintf("[%08lx] ", pc);
1189 # elif defined(ARM)
1190         long pc;
1191
1192         if (upeek(tcp, 4*15, &pc) < 0) {
1193                 PRINTBADPC;
1194                 return;
1195         }
1196         tprintf("[%08lx] ", pc);
1197 # elif defined(AVR32)
1198         long pc;
1199
1200         if (upeek(tcp, REG_PC, &pc) < 0) {
1201                 tprints("[????????] ");
1202                 return;
1203         }
1204         tprintf("[%08lx] ", pc);
1205 # elif defined(BFIN)
1206         long pc;
1207
1208         if (upeek(tcp, PT_PC, &pc) < 0) {
1209                 PRINTBADPC;
1210                 return;
1211         }
1212         tprintf("[%08lx] ", pc);
1213 #elif defined(CRISV10)
1214         long pc;
1215
1216         if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
1217                 PRINTBADPC;
1218                 return;
1219         }
1220         tprintf("[%08lx] ", pc);
1221 #elif defined(CRISV32)
1222         long pc;
1223
1224         if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
1225                 PRINTBADPC;
1226                 return;
1227         }
1228         tprintf("[%08lx] ", pc);
1229 # endif /* architecture */
1230 #endif /* LINUX */
1231
1232 #ifdef SUNOS4
1233         struct regs regs;
1234
1235         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1236                 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
1237                 PRINTBADPC;
1238                 return;
1239         }
1240         tprintf("[%08x] ", regs.r_o7);
1241 #endif /* SUNOS4 */
1242
1243 #ifdef SVR4
1244         /* XXX */
1245         PRINTBADPC;
1246 #endif
1247
1248 #ifdef FREEBSD
1249         struct reg regs;
1250         pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1251         tprintf("[%08x] ", regs.r_eip);
1252 #endif /* FREEBSD */
1253 }
1254
1255
1256 /*
1257  * These #if's are huge, please indent them correctly.
1258  * It's easy to get confused otherwise.
1259  */
1260 #ifndef USE_PROCFS
1261
1262 # ifdef LINUX
1263
1264 #  include "syscall.h"
1265
1266 #  include <sys/syscall.h>
1267 #  ifndef CLONE_PTRACE
1268 #   define CLONE_PTRACE    0x00002000
1269 #  endif
1270 #  ifndef CLONE_VFORK
1271 #   define CLONE_VFORK     0x00004000
1272 #  endif
1273 #  ifndef CLONE_VM
1274 #   define CLONE_VM        0x00000100
1275 #  endif
1276 #  ifndef CLONE_STOPPED
1277 #   define CLONE_STOPPED   0x02000000
1278 #  endif
1279
1280 #  ifdef IA64
1281
1282 /* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1283    subsystem has them for x86... */
1284 #   define SYS_fork     2
1285 #   define SYS_vfork    190
1286
1287 typedef unsigned long *arg_setup_state;
1288
1289 static int
1290 arg_setup(struct tcb *tcp, arg_setup_state *state)
1291 {
1292         unsigned long cfm, sof, sol;
1293         long bsp;
1294
1295         if (ia32) {
1296                 /* Satisfy a false GCC warning.  */
1297                 *state = NULL;
1298                 return 0;
1299         }
1300
1301         if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
1302                 return -1;
1303         if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
1304                 return -1;
1305
1306         sof = (cfm >> 0) & 0x7f;
1307         sol = (cfm >> 7) & 0x7f;
1308         bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
1309
1310         *state = (unsigned long *) bsp;
1311         return 0;
1312 }
1313
1314 #   define arg_finish_change(tcp, state)        0
1315
1316 #   ifdef SYS_fork
1317 static int
1318 get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
1319 {
1320         int ret;
1321
1322         if (ia32)
1323                 ret = upeek(tcp, PT_R11, valp);
1324         else
1325                 ret = umoven(tcp,
1326                               (unsigned long) ia64_rse_skip_regs(*state, 0),
1327                               sizeof(long), (void *) valp);
1328         return ret;
1329 }
1330
1331 static int
1332 get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
1333 {
1334         int ret;
1335
1336         if (ia32)
1337                 ret = upeek(tcp, PT_R9, valp);
1338         else
1339                 ret = umoven(tcp,
1340                               (unsigned long) ia64_rse_skip_regs(*state, 1),
1341                               sizeof(long), (void *) valp);
1342         return ret;
1343 }
1344 #   endif
1345
1346 static int
1347 set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
1348 {
1349         int req = PTRACE_POKEDATA;
1350         void *ap;
1351
1352         if (ia32) {
1353                 ap = (void *) (intptr_t) PT_R11;         /* r11 == EBX */
1354                 req = PTRACE_POKEUSER;
1355         } else
1356                 ap = ia64_rse_skip_regs(*state, 0);
1357         errno = 0;
1358         ptrace(req, tcp->pid, ap, val);
1359         return errno ? -1 : 0;
1360 }
1361
1362 static int
1363 set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
1364 {
1365         int req = PTRACE_POKEDATA;
1366         void *ap;
1367
1368         if (ia32) {
1369                 ap = (void *) (intptr_t) PT_R9;         /* r9 == ECX */
1370                 req = PTRACE_POKEUSER;
1371         } else
1372                 ap = ia64_rse_skip_regs(*state, 1);
1373         errno = 0;
1374         ptrace(req, tcp->pid, ap, val);
1375         return errno ? -1 : 0;
1376 }
1377
1378 /* ia64 does not return the input arguments from functions (and syscalls)
1379    according to ia64 RSE (Register Stack Engine) behavior.  */
1380
1381 #   define restore_arg0(tcp, state, val) ((void) (state), 0)
1382 #   define restore_arg1(tcp, state, val) ((void) (state), 0)
1383
1384 #  elif defined (SPARC) || defined (SPARC64)
1385
1386 typedef struct pt_regs arg_setup_state;
1387
1388 #   define arg_setup(tcp, state) \
1389     (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
1390 #   define arg_finish_change(tcp, state) \
1391     (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
1392
1393 #   define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1394 #   define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1395 #   define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1396 #   define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
1397 #   define restore_arg0(tcp, state, val) 0
1398
1399 #  else /* other architectures */
1400
1401 #   if defined S390 || defined S390X
1402 /* Note: this is only true for the `clone' system call, which handles
1403    arguments specially.  We could as well say that its first two arguments
1404    are swapped relative to other architectures, but that would just be
1405    another #ifdef in the calls.  */
1406 #    define arg0_offset PT_GPR3
1407 #    define arg1_offset PT_ORIGGPR2
1408 #    define restore_arg0(tcp, state, val) ((void) (state), 0)
1409 #    define restore_arg1(tcp, state, val) ((void) (state), 0)
1410 #    define arg0_index  1
1411 #    define arg1_index  0
1412 #   elif defined (ALPHA) || defined (MIPS)
1413 #    define arg0_offset REG_A0
1414 #    define arg1_offset (REG_A0+1)
1415 #   elif defined (AVR32)
1416 #    define arg0_offset (REG_R12)
1417 #    define arg1_offset (REG_R11)
1418 #   elif defined (POWERPC)
1419 #    define arg0_offset (sizeof(unsigned long)*PT_R3)
1420 #    define arg1_offset (sizeof(unsigned long)*PT_R4)
1421 #    define restore_arg0(tcp, state, val) ((void) (state), 0)
1422 #   elif defined (HPPA)
1423 #    define arg0_offset  PT_GR26
1424 #    define arg1_offset  (PT_GR26-4)
1425 #   elif defined (X86_64)
1426 #    define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1427 #    define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1428 #   elif defined (SH)
1429 #    define arg0_offset (4*(REG_REG0+4))
1430 #    define arg1_offset (4*(REG_REG0+5))
1431 #   elif defined (SH64)
1432     /* ABI defines arg0 & 1 in r2 & r3 */
1433 #    define arg0_offset   (REG_OFFSET+16)
1434 #    define arg1_offset   (REG_OFFSET+24)
1435 #    define restore_arg0(tcp, state, val) 0
1436 #   elif defined CRISV10 || defined CRISV32
1437 #    define arg0_offset   (4*PT_R11)
1438 #    define arg1_offset   (4*PT_ORIG_R10)
1439 #    define restore_arg0(tcp, state, val) 0
1440 #    define restore_arg1(tcp, state, val) 0
1441 #    define arg0_index   1
1442 #    define arg1_index   0
1443 #   else
1444 #    define arg0_offset 0
1445 #    define arg1_offset 4
1446 #    if defined ARM
1447 #     define restore_arg0(tcp, state, val) 0
1448 #    endif
1449 #   endif
1450
1451 typedef int arg_setup_state;
1452
1453 #   define arg_setup(tcp, state) (0)
1454 #   define arg_finish_change(tcp, state)        0
1455 #   define get_arg0(tcp, cookie, valp) \
1456     (upeek((tcp), arg0_offset, (valp)))
1457 #   define get_arg1(tcp, cookie, valp) \
1458     (upeek((tcp), arg1_offset, (valp)))
1459
1460 static int
1461 set_arg0(struct tcb *tcp, void *cookie, long val)
1462 {
1463         return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
1464 }
1465
1466 static int
1467 set_arg1(struct tcb *tcp, void *cookie, long val)
1468 {
1469         return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
1470 }
1471
1472 #  endif /* architectures */
1473
1474 #  ifndef restore_arg0
1475 #   define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1476 #  endif
1477 #  ifndef restore_arg1
1478 #   define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1479 #  endif
1480
1481 #  ifndef arg0_index
1482 #   define arg0_index 0
1483 #   define arg1_index 1
1484 #  endif
1485
1486 int
1487 setbpt(struct tcb *tcp)
1488 {
1489         static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
1490         arg_setup_state state;
1491
1492         if (tcp->flags & TCB_BPTSET) {
1493                 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1494                 return -1;
1495         }
1496
1497         /*
1498          * It's a silly kludge to initialize this with a search at runtime.
1499          * But it's better than maintaining another magic thing in the
1500          * godforsaken tables.
1501          */
1502         if (clone_scno[current_personality] == 0) {
1503                 int i;
1504                 for (i = 0; i < nsyscalls; ++i)
1505                         if (sysent[i].sys_func == sys_clone) {
1506                                 clone_scno[current_personality] = i;
1507                                 break;
1508                         }
1509         }
1510
1511         switch (known_scno(tcp)) {
1512 #  ifdef SYS_vfork
1513         case SYS_vfork:
1514 #  endif
1515 #  ifdef SYS_fork
1516         case SYS_fork:
1517 #  endif
1518 #  if defined SYS_fork || defined SYS_vfork
1519                 if (arg_setup(tcp, &state) < 0
1520                     || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1521                     || get_arg1(tcp, &state, &tcp->inst[1]) < 0
1522                     || change_syscall(tcp, clone_scno[current_personality]) < 0
1523                     || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1524                     || set_arg1(tcp, &state, 0) < 0
1525                     || arg_finish_change(tcp, &state) < 0)
1526                         return -1;
1527                 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1528                 tcp->u_arg[arg1_index] = 0;
1529                 tcp->flags |= TCB_BPTSET;
1530                 return 0;
1531 #  endif
1532
1533         case SYS_clone: ;
1534 #  ifdef SYS_clone2
1535         case SYS_clone2: ;
1536 #  endif
1537                 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1538                    contrary to x86 SYS_vfork above.  Even on x86 we turn the
1539                    vfork semantics into plain fork - each application must not
1540                    depend on the vfork specifics according to POSIX.  We would
1541                    hang waiting for the parent resume otherwise.  We need to
1542                    clear also CLONE_VM but only in the CLONE_VFORK case as
1543                    otherwise we would break pthread_create.  */
1544
1545                 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1546                 if (new_arg0 & CLONE_VFORK)
1547                         new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1548                 if (arg_setup(tcp, &state) < 0
1549                  || set_arg0(tcp, &state, new_arg0) < 0
1550                  || arg_finish_change(tcp, &state) < 0)
1551                         return -1;
1552                 tcp->flags |= TCB_BPTSET;
1553                 tcp->inst[0] = tcp->u_arg[arg0_index];
1554                 tcp->inst[1] = tcp->u_arg[arg1_index];
1555                 return 0;
1556
1557         default:
1558                 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1559                         tcp->scno, tcp->pid);
1560                 break;
1561         }
1562
1563         return -1;
1564 }
1565
1566 int
1567 clearbpt(struct tcb *tcp)
1568 {
1569         arg_setup_state state;
1570         if (arg_setup(tcp, &state) < 0
1571             || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1572             || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1573             || arg_finish_change(tcp, &state))
1574                 if (errno != ESRCH)
1575                         return -1;
1576         tcp->flags &= ~TCB_BPTSET;
1577         return 0;
1578 }
1579
1580 # else /* !defined LINUX */
1581
1582 int
1583 setbpt(struct tcb *tcp)
1584 {
1585 #  ifdef SUNOS4
1586 #   ifdef SPARC /* This code is slightly sparc specific */
1587
1588         struct regs regs;
1589 #    define BPT 0x91d02001      /* ta   1 */
1590 #    define LOOP        0x10800000      /* ba   0 */
1591 #    define LOOPA       0x30800000      /* ba,a 0 */
1592 #    define NOP 0x01000000
1593 #    if LOOPA
1594         static int loopdeloop[1] = {LOOPA};
1595 #    else
1596         static int loopdeloop[2] = {LOOP, NOP};
1597 #    endif
1598
1599         if (tcp->flags & TCB_BPTSET) {
1600                 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1601                 return -1;
1602         }
1603         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1604                 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1605                 return -1;
1606         }
1607         tcp->baddr = regs.r_o7 + 8;
1608         if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1609                                 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1610                 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1611                 return -1;
1612         }
1613
1614         /*
1615          * XXX - BRUTAL MODE ON
1616          * We cannot set a real BPT in the child, since it will not be
1617          * traced at the moment it will reach the trap and would probably
1618          * die with a core dump.
1619          * Thus, we are force our way in by taking out two instructions
1620          * and insert an eternal loop in stead, in expectance of the SIGSTOP
1621          * generated by out PTRACE_ATTACH.
1622          * Of cause, if we evaporate ourselves in the middle of all this...
1623          */
1624         if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1625                         sizeof loopdeloop, (char *) loopdeloop) < 0) {
1626                 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1627                 return -1;
1628         }
1629         tcp->flags |= TCB_BPTSET;
1630
1631 #   endif /* SPARC */
1632 #  endif /* SUNOS4 */
1633
1634         return 0;
1635 }
1636
1637 int
1638 clearbpt(struct tcb *tcp)
1639 {
1640 #  ifdef SUNOS4
1641 #   ifdef SPARC
1642
1643 #    if !LOOPA
1644         struct regs regs;
1645 #    endif
1646
1647         if (!(tcp->flags & TCB_BPTSET)) {
1648                 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1649                 return -1;
1650         }
1651         if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1652                                 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1653                 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1654                 return -1;
1655         }
1656         tcp->flags &= ~TCB_BPTSET;
1657
1658 #    if !LOOPA
1659         /*
1660          * Since we don't have a single instruction breakpoint, we may have
1661          * to adjust the program counter after removing our `breakpoint'.
1662          */
1663         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1664                 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1665                 return -1;
1666         }
1667         if ((regs.r_pc < tcp->baddr) ||
1668                                 (regs.r_pc > tcp->baddr + 4)) {
1669                 /* The breakpoint has not been reached yet */
1670                 if (debug)
1671                         fprintf(stderr,
1672                                 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1673                                         regs.r_pc, tcp->baddr);
1674                 return 0;
1675         }
1676         if (regs.r_pc != tcp->baddr)
1677                 if (debug)
1678                         fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1679                                 regs.r_pc, tcp->baddr);
1680
1681         regs.r_pc = tcp->baddr;
1682         if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1683                 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1684                 return -1;
1685         }
1686 #    endif /* LOOPA */
1687 #   endif /* SPARC */
1688 #  endif /* SUNOS4 */
1689
1690         return 0;
1691 }
1692
1693 # endif /* !defined LINUX */
1694
1695 #endif /* !USE_PROCFS */
1696
1697
1698 #ifdef SUNOS4
1699
1700 static int
1701 getex(struct tcb *tcp, struct exec *hdr)
1702 {
1703         int n;
1704
1705         for (n = 0; n < sizeof *hdr; n += 4) {
1706                 long res;
1707                 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
1708                         return -1;
1709                 memcpy(((char *) hdr) + n, &res, 4);
1710         }
1711         if (debug) {
1712                 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1713                         hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1714                 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1715                         hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1716         }
1717         return 0;
1718 }
1719
1720 int
1721 fixvfork(struct tcb *tcp)
1722 {
1723         int pid = tcp->pid;
1724         /*
1725          * Change `vfork' in a freshly exec'ed dynamically linked
1726          * executable's (internal) symbol table to plain old `fork'
1727          */
1728
1729         struct exec hdr;
1730         struct link_dynamic dyn;
1731         struct link_dynamic_2 ld;
1732         char *strtab, *cp;
1733
1734         if (getex(tcp, &hdr) < 0)
1735                 return -1;
1736         if (!hdr.a_dynamic)
1737                 return -1;
1738
1739         if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1740                 fprintf(stderr, "Cannot read DYNAMIC\n");
1741                 return -1;
1742         }
1743         if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1744                 fprintf(stderr, "Cannot read link_dynamic_2\n");
1745                 return -1;
1746         }
1747         strtab = malloc((unsigned)ld.ld_symb_size);
1748         if (!strtab)
1749                 die_out_of_memory();
1750         if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1751                                         (int)ld.ld_symb_size, strtab) < 0)
1752                 goto err;
1753
1754         for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1755                 if (strcmp(cp, "_vfork") == 0) {
1756                         if (debug)
1757                                 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1758                         strcpy(cp, "_fork");
1759                         break;
1760                 }
1761                 cp += strlen(cp)+1;
1762         }
1763         if (cp < strtab + ld.ld_symb_size)
1764                 /*
1765                  * Write entire symbol table back to avoid
1766                  * memory alignment bugs in ptrace
1767                  */
1768                 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1769                                         (int)ld.ld_symb_size, strtab) < 0)
1770                         goto err;
1771
1772         free(strtab);
1773         return 0;
1774
1775 err:
1776         free(strtab);
1777         return -1;
1778 }
1779
1780 #endif /* SUNOS4 */