]> granicus.if.org Git - strace/blob - util.c
Fix struct pt_regs declaration on i386 and x86-64
[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 static char path[MAXPATHLEN + 1];
431
432 /*
433  * Quote string `instr' of length `size'
434  * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
435  * If `len' < 0, treat `instr' as a NUL-terminated string
436  * and quote at most (`size' - 1) bytes.
437  */
438 static int
439 string_quote(const char *instr, char *outstr, int len, int size)
440 {
441         const unsigned char *ustr = (const unsigned char *) instr;
442         char *s = outstr;
443         int usehex, c, i, eol;
444
445         eol = 0x100; /* this can never match a char */
446         if (len < 0) {
447                 size--;
448                 eol = '\0';
449         }
450
451         usehex = 0;
452         if (xflag > 1)
453                 usehex = 1;
454         else if (xflag) {
455                 /* Check for presence of symbol which require
456                    to hex-quote the whole string. */
457                 for (i = 0; i < size; ++i) {
458                         c = ustr[i];
459                         /* Check for NUL-terminated string. */
460                         if (c == eol)
461                                 break;
462                         if (!isprint(c) && !isspace(c)) {
463                                 usehex = 1;
464                                 break;
465                         }
466                 }
467         }
468
469         *s++ = '\"';
470
471         if (usehex) {
472                 /* Hex-quote the whole string. */
473                 for (i = 0; i < size; ++i) {
474                         c = ustr[i];
475                         /* Check for NUL-terminated string. */
476                         if (c == eol)
477                                 goto asciz_ended;
478                         *s++ = '\\';
479                         *s++ = 'x';
480                         *s++ = "0123456789abcdef"[c >> 4];
481                         *s++ = "0123456789abcdef"[c & 0xf];
482                 }
483         } else {
484                 for (i = 0; i < size; ++i) {
485                         c = ustr[i];
486                         /* Check for NUL-terminated string. */
487                         if (c == eol)
488                                 goto asciz_ended;
489                         switch (c) {
490                                 case '\"': case '\\':
491                                         *s++ = '\\';
492                                         *s++ = c;
493                                         break;
494                                 case '\f':
495                                         *s++ = '\\';
496                                         *s++ = 'f';
497                                         break;
498                                 case '\n':
499                                         *s++ = '\\';
500                                         *s++ = 'n';
501                                         break;
502                                 case '\r':
503                                         *s++ = '\\';
504                                         *s++ = 'r';
505                                         break;
506                                 case '\t':
507                                         *s++ = '\\';
508                                         *s++ = 't';
509                                         break;
510                                 case '\v':
511                                         *s++ = '\\';
512                                         *s++ = 'v';
513                                         break;
514                                 default:
515                                         if (isprint(c))
516                                                 *s++ = c;
517                                         else {
518                                                 /* Print \octal */
519                                                 *s++ = '\\';
520                                                 if (i + 1 < size
521                                                     && ustr[i + 1] >= '0'
522                                                     && ustr[i + 1] <= '9'
523                                                 ) {
524                                                         /* Print \ooo */
525                                                         *s++ = '0' + (c >> 6);
526                                                         *s++ = '0' + ((c >> 3) & 0x7);
527                                                 } else {
528                                                         /* Print \[[o]o]o */
529                                                         if ((c >> 3) != 0) {
530                                                                 if ((c >> 6) != 0)
531                                                                         *s++ = '0' + (c >> 6);
532                                                                 *s++ = '0' + ((c >> 3) & 0x7);
533                                                         }
534                                                 }
535                                                 *s++ = '0' + (c & 0x7);
536                                         }
537                                         break;
538                         }
539                 }
540         }
541
542         *s++ = '\"';
543         *s = '\0';
544
545         /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
546         if (len < 0 && ustr[i] == '\0') {
547                 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
548                  * but next char is NUL.
549                  */
550                 return 0;
551         }
552
553         return 1;
554
555  asciz_ended:
556         *s++ = '\"';
557         *s = '\0';
558         /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
559         return 0;
560 }
561
562 /*
563  * Print path string specified by address `addr' and length `n'.
564  * If path length exceeds `n', append `...' to the output.
565  */
566 void
567 printpathn(struct tcb *tcp, long addr, int n)
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                 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
585                 const char *fmt;
586                 int trunc = (path[n] != '\0');
587
588                 if (trunc)
589                         path[n] = '\0';
590                 string_quote(path, outstr, -1, n + 1);
591                 fmt = "%s";
592                 if (trunc)
593                         fmt = "%s...";
594                 tprintf(fmt, outstr);
595         }
596 }
597
598 void
599 printpath(struct tcb *tcp, long addr)
600 {
601         printpathn(tcp, addr, sizeof path - 1);
602 }
603
604 /*
605  * Print string specified by address `addr' and length `len'.
606  * If `len' < 0, treat the string as a NUL-terminated string.
607  * If string length exceeds `max_strlen', append `...' to the output.
608  */
609 void
610 printstr(struct tcb *tcp, long addr, int len)
611 {
612         static char *str = NULL;
613         static char *outstr;
614         int size;
615         const char *fmt;
616
617         if (!addr) {
618                 tprints("NULL");
619                 return;
620         }
621         /* Allocate static buffers if they are not allocated yet. */
622         if (!str) {
623                 str = malloc(max_strlen + 1);
624                 if (!str)
625                         die_out_of_memory();
626         }
627         if (!outstr) {
628                 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
629                 if (!outstr)
630                         die_out_of_memory();
631         }
632
633         if (len < 0) {
634                 /*
635                  * Treat as a NUL-terminated string: fetch one byte more
636                  * because string_quote() quotes one byte less.
637                  */
638                 size = max_strlen + 1;
639                 str[max_strlen] = '\0';
640         /* FIXME! umovestr can overwrite the '\0' stored above??? */
641                 if (umovestr(tcp, addr, size, str) < 0) {
642                         tprintf("%#lx", addr);
643                         return;
644                 }
645         }
646         else {
647                 size = MIN(len, max_strlen);
648                 if (umoven(tcp, addr, size, str) < 0) {
649                         tprintf("%#lx", addr);
650                         return;
651                 }
652         }
653
654         fmt = "%s";
655         if (string_quote(str, outstr, len, size) &&
656             (len < 0 || len > max_strlen))
657                 fmt = "%s...";
658
659         tprintf(fmt, outstr);
660 }
661
662 #if HAVE_SYS_UIO_H
663 void
664 dumpiov(struct tcb *tcp, int len, long addr)
665 {
666 #if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
667         union {
668                 struct { u_int32_t base; u_int32_t len; } *iov32;
669                 struct { u_int64_t base; u_int64_t len; } *iov64;
670         } iovu;
671 #define iov iovu.iov64
672 #define sizeof_iov \
673   (personality_wordsize[current_personality] == 4 \
674    ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
675 #define iov_iov_base(i) \
676   (personality_wordsize[current_personality] == 4 \
677    ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
678 #define iov_iov_len(i) \
679   (personality_wordsize[current_personality] == 4 \
680    ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
681 #else
682         struct iovec *iov;
683 #define sizeof_iov sizeof(*iov)
684 #define iov_iov_base(i) iov[i].iov_base
685 #define iov_iov_len(i) iov[i].iov_len
686 #endif
687         int i;
688         unsigned size;
689
690         size = sizeof_iov * len;
691         /* Assuming no sane program has millions of iovs */
692         if ((unsigned)len > 1024*1024 /* insane or negative size? */
693             || (iov = malloc(size)) == NULL) {
694                 fprintf(stderr, "Out of memory\n");
695                 return;
696         }
697         if (umoven(tcp, addr, size, (char *) iov) >= 0) {
698                 for (i = 0; i < len; i++) {
699                         /* include the buffer number to make it easy to
700                          * match up the trace with the source */
701                         tprintf(" * %lu bytes in buffer %d\n",
702                                 (unsigned long)iov_iov_len(i), i);
703                         dumpstr(tcp, (long) iov_iov_base(i),
704                                 iov_iov_len(i));
705                 }
706         }
707         free(iov);
708 #undef sizeof_iov
709 #undef iov_iov_base
710 #undef iov_iov_len
711 #undef iov
712 }
713 #endif
714
715 void
716 dumpstr(struct tcb *tcp, long addr, int len)
717 {
718         static int strsize = -1;
719         static unsigned char *str;
720         char *s;
721         int i, j;
722
723         if (strsize < len) {
724                 free(str);
725                 str = malloc(len);
726                 if (!str) {
727                         strsize = -1;
728                         fprintf(stderr, "Out of memory\n");
729                         return;
730                 }
731                 strsize = len;
732         }
733
734         if (umoven(tcp, addr, len, (char *) str) < 0)
735                 return;
736
737         for (i = 0; i < len; i += 16) {
738                 char outstr[80];
739
740                 s = outstr;
741                 sprintf(s, " | %05x ", i);
742                 s += 9;
743                 for (j = 0; j < 16; j++) {
744                         if (j == 8)
745                                 *s++ = ' ';
746                         if (i + j < len) {
747                                 sprintf(s, " %02x", str[i + j]);
748                                 s += 3;
749                         }
750                         else {
751                                 *s++ = ' '; *s++ = ' '; *s++ = ' ';
752                         }
753                 }
754                 *s++ = ' '; *s++ = ' ';
755                 for (j = 0; j < 16; j++) {
756                         if (j == 8)
757                                 *s++ = ' ';
758                         if (i + j < len) {
759                                 if (isprint(str[i + j]))
760                                         *s++ = str[i + j];
761                                 else
762                                         *s++ = '.';
763                         }
764                         else
765                                 *s++ = ' ';
766                 }
767                 tprintf("%s |\n", outstr);
768         }
769 }
770
771 #define PAGMASK (~(PAGSIZ - 1))
772 /*
773  * move `len' bytes of data from process `pid'
774  * at address `addr' to our space at `laddr'
775  */
776 int
777 umoven(struct tcb *tcp, long addr, int len, char *laddr)
778 {
779 #ifdef LINUX
780         int pid = tcp->pid;
781         int n, m;
782         int started = 0;
783         union {
784                 long val;
785                 char x[sizeof(long)];
786         } u;
787
788 #if SUPPORTED_PERSONALITIES > 1
789         if (personality_wordsize[current_personality] < sizeof(addr))
790                 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
791 #endif
792
793         if (addr & (sizeof(long) - 1)) {
794                 /* addr not a multiple of sizeof(long) */
795                 n = addr - (addr & -sizeof(long)); /* residue */
796                 addr &= -sizeof(long); /* residue */
797                 errno = 0;
798                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
799                 if (errno) {
800                         /* But if not started, we had a bogus address. */
801                         if (addr != 0 && errno != EIO && errno != ESRCH)
802                                 perror("ptrace: umoven");
803                         return -1;
804                 }
805                 started = 1;
806                 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
807                 addr += sizeof(long), laddr += m, len -= m;
808         }
809         while (len) {
810                 errno = 0;
811                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
812                 if (errno) {
813                         if (started && (errno==EPERM || errno==EIO)) {
814                                 /* Ran into 'end of memory' - stupid "printpath" */
815                                 return 0;
816                         }
817                         if (addr != 0 && errno != EIO && errno != ESRCH)
818                                 perror("ptrace: umoven");
819                         return -1;
820                 }
821                 started = 1;
822                 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
823                 addr += sizeof(long), laddr += m, len -= m;
824         }
825 #endif /* LINUX */
826
827 #ifdef SUNOS4
828         int pid = tcp->pid;
829         int n;
830
831         while (len) {
832                 n = MIN(len, PAGSIZ);
833                 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
834                 if (ptrace(PTRACE_READDATA, pid,
835                            (char *) addr, len, laddr) < 0) {
836                         if (errno != ESRCH) {
837                                 perror("umoven: ptrace(PTRACE_READDATA, ...)");
838                                 abort();
839                         }
840                         return -1;
841                 }
842                 len -= n;
843                 addr += n;
844                 laddr += n;
845         }
846 #endif /* SUNOS4 */
847
848 #ifdef USE_PROCFS
849 #ifdef HAVE_MP_PROCFS
850         int fd = tcp->pfd_as;
851 #else
852         int fd = tcp->pfd;
853 #endif
854         lseek(fd, addr, SEEK_SET);
855         if (read(fd, laddr, len) == -1)
856                 return -1;
857 #endif /* USE_PROCFS */
858
859         return 0;
860 }
861
862 /*
863  * like `umove' but make the additional effort of looking
864  * for a terminating zero byte.
865  */
866 int
867 umovestr(struct tcb *tcp, long addr, int len, char *laddr)
868 {
869 #ifdef USE_PROCFS
870 #ifdef HAVE_MP_PROCFS
871         int fd = tcp->pfd_as;
872 #else
873         int fd = tcp->pfd;
874 #endif
875         /* Some systems (e.g. FreeBSD) can be upset if we read off the
876            end of valid memory,  avoid this by trying to read up
877            to page boundaries.  But we don't know what a page is (and
878            getpagesize(2) (if it exists) doesn't necessarily return
879            hardware page size).  Assume all pages >= 1024 (a-historical
880            I know) */
881
882         int page = 1024;        /* How to find this? */
883         int move = page - (addr & (page - 1));
884         int left = len;
885
886         lseek(fd, addr, SEEK_SET);
887
888         while (left) {
889                 if (move > left)
890                         move = left;
891                 move = read(fd, laddr, move);
892                 if (move <= 0)
893                         return left != len ? 0 : -1;
894                 if (memchr(laddr, 0, move))
895                         break;
896                 left -= move;
897                 laddr += move;
898                 addr += move;
899                 move = page;
900         }
901 #else /* !USE_PROCFS */
902         int started = 0;
903         int pid = tcp->pid;
904         int i, n, m;
905         union {
906                 long val;
907                 char x[sizeof(long)];
908         } u;
909
910 #if SUPPORTED_PERSONALITIES > 1
911         if (personality_wordsize[current_personality] < sizeof(addr))
912                 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
913 #endif
914
915         if (addr & (sizeof(long) - 1)) {
916                 /* addr not a multiple of sizeof(long) */
917                 n = addr - (addr & -sizeof(long)); /* residue */
918                 addr &= -sizeof(long); /* residue */
919                 errno = 0;
920                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
921                 if (errno) {
922                         if (addr != 0 && errno != EIO && errno != ESRCH)
923                                 perror("umovestr");
924                         return -1;
925                 }
926                 started = 1;
927                 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
928                 while (n & (sizeof(long) - 1))
929                         if (u.x[n++] == '\0')
930                                 return 0;
931                 addr += sizeof(long), laddr += m, len -= m;
932         }
933         while (len) {
934                 errno = 0;
935                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
936                 if (errno) {
937                         if (started && (errno==EPERM || errno==EIO)) {
938                                 /* Ran into 'end of memory' - stupid "printpath" */
939                                 return 0;
940                         }
941                         if (addr != 0 && errno != EIO && errno != ESRCH)
942                                 perror("umovestr");
943                         return -1;
944                 }
945                 started = 1;
946                 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
947                 for (i = 0; i < sizeof(long); i++)
948                         if (u.x[i] == '\0')
949                                 return 0;
950
951                 addr += sizeof(long), laddr += m, len -= m;
952         }
953 #endif /* !USE_PROCFS */
954         return 0;
955 }
956
957 #ifdef LINUX
958 # if !defined (SPARC) && !defined(SPARC64)
959 #  define PTRACE_WRITETEXT      101
960 #  define PTRACE_WRITEDATA      102
961 # endif /* !SPARC && !SPARC64 */
962 #endif /* LINUX */
963
964 #ifdef SUNOS4
965
966 static int
967 uload(int cmd, int pid, long addr, int len, char *laddr)
968 {
969         int peek, poke;
970         int n, m;
971         union {
972                 long val;
973                 char x[sizeof(long)];
974         } u;
975
976         if (cmd == PTRACE_WRITETEXT) {
977                 peek = PTRACE_PEEKTEXT;
978                 poke = PTRACE_POKETEXT;
979         }
980         else {
981                 peek = PTRACE_PEEKDATA;
982                 poke = PTRACE_POKEDATA;
983         }
984         if (addr & (sizeof(long) - 1)) {
985                 /* addr not a multiple of sizeof(long) */
986                 n = addr - (addr & -sizeof(long)); /* residue */
987                 addr &= -sizeof(long);
988                 errno = 0;
989                 u.val = ptrace(peek, pid, (char *) addr, 0);
990                 if (errno) {
991                         perror("uload: POKE");
992                         return -1;
993                 }
994                 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
995                 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
996                         perror("uload: POKE");
997                         return -1;
998                 }
999                 addr += sizeof(long), laddr += m, len -= m;
1000         }
1001         while (len) {
1002                 if (len < sizeof(long))
1003                         u.val = ptrace(peek, pid, (char *) addr, 0);
1004                 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
1005                 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1006                         perror("uload: POKE");
1007                         return -1;
1008                 }
1009                 addr += sizeof(long), laddr += m, len -= m;
1010         }
1011         return 0;
1012 }
1013
1014 int
1015 tload(int pid, int addr, int len, char *laddr)
1016 {
1017         return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1018 }
1019
1020 int
1021 dload(int pid, int addr, int len, char *laddr)
1022 {
1023         return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
1024 }
1025
1026 #endif /* SUNOS4 */
1027
1028 #ifndef USE_PROCFS
1029
1030 int
1031 upeek(struct tcb *tcp, long off, long *res)
1032 {
1033         long val;
1034
1035 # ifdef SUNOS4_KERNEL_ARCH_KLUDGE
1036         {
1037                 static int is_sun4m = -1;
1038                 struct utsname name;
1039
1040                 /* Round up the usual suspects. */
1041                 if (is_sun4m == -1) {
1042                         if (uname(&name) < 0) {
1043                                 perror("upeek: uname?");
1044                                 exit(1);
1045                         }
1046                         is_sun4m = strcmp(name.machine, "sun4m") == 0;
1047                         if (is_sun4m) {
1048                                 const struct xlat *x;
1049
1050                                 for (x = struct_user_offsets; x->str; x++)
1051                                         x->val += 1024;
1052                         }
1053                 }
1054                 if (is_sun4m)
1055                         off += 1024;
1056         }
1057 # endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
1058         errno = 0;
1059         val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
1060         if (val == -1 && errno) {
1061                 if (errno != ESRCH) {
1062                         char buf[60];
1063                         sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
1064                         perror(buf);
1065                 }
1066                 return -1;
1067         }
1068         *res = val;
1069         return 0;
1070 }
1071
1072 #endif /* !USE_PROCFS */
1073
1074 void
1075 printcall(struct tcb *tcp)
1076 {
1077 #define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1078                            sizeof(long) == 8 ? "[????????????????] " : \
1079                            NULL /* crash */)
1080
1081 #ifdef LINUX
1082 # ifdef I386
1083         long eip;
1084
1085         if (upeek(tcp, 4*EIP, &eip) < 0) {
1086                 PRINTBADPC;
1087                 return;
1088         }
1089         tprintf("[%08lx] ", eip);
1090
1091 # elif defined(S390) || defined(S390X)
1092         long psw;
1093         if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
1094                 PRINTBADPC;
1095                 return;
1096         }
1097 #  ifdef S390
1098         tprintf("[%08lx] ", psw);
1099 #  elif S390X
1100         tprintf("[%16lx] ", psw);
1101 #  endif
1102
1103 # elif defined(X86_64)
1104         long rip;
1105
1106         if (upeek(tcp, 8*RIP, &rip) < 0) {
1107                 PRINTBADPC;
1108                 return;
1109         }
1110         tprintf("[%16lx] ", rip);
1111 # elif defined(IA64)
1112         long ip;
1113
1114         if (upeek(tcp, PT_B0, &ip) < 0) {
1115                 PRINTBADPC;
1116                 return;
1117         }
1118         tprintf("[%08lx] ", ip);
1119 # elif defined(POWERPC)
1120         long pc;
1121
1122         if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
1123                 PRINTBADPC;
1124                 return;
1125         }
1126 #  ifdef POWERPC64
1127         tprintf("[%016lx] ", pc);
1128 #  else
1129         tprintf("[%08lx] ", pc);
1130 #  endif
1131 # elif defined(M68K)
1132         long pc;
1133
1134         if (upeek(tcp, 4*PT_PC, &pc) < 0) {
1135                 tprints("[????????] ");
1136                 return;
1137         }
1138         tprintf("[%08lx] ", pc);
1139 # elif defined(ALPHA)
1140         long pc;
1141
1142         if (upeek(tcp, REG_PC, &pc) < 0) {
1143                 tprints("[????????????????] ");
1144                 return;
1145         }
1146         tprintf("[%08lx] ", pc);
1147 # elif defined(SPARC) || defined(SPARC64)
1148         struct pt_regs regs;
1149         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1150                 PRINTBADPC;
1151                 return;
1152         }
1153 #  if defined(SPARC64)
1154         tprintf("[%08lx] ", regs.tpc);
1155 #  else
1156         tprintf("[%08lx] ", regs.pc);
1157 #  endif
1158 # elif defined(HPPA)
1159         long pc;
1160
1161         if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
1162                 tprints("[????????] ");
1163                 return;
1164         }
1165         tprintf("[%08lx] ", pc);
1166 # elif defined(MIPS)
1167         long pc;
1168
1169         if (upeek(tcp, REG_EPC, &pc) < 0) {
1170                 tprints("[????????] ");
1171                 return;
1172         }
1173         tprintf("[%08lx] ", pc);
1174 # elif defined(SH)
1175         long pc;
1176
1177         if (upeek(tcp, 4*REG_PC, &pc) < 0) {
1178                 tprints("[????????] ");
1179                 return;
1180         }
1181         tprintf("[%08lx] ", pc);
1182 # elif defined(SH64)
1183         long pc;
1184
1185         if (upeek(tcp, REG_PC, &pc) < 0) {
1186                 tprints("[????????????????] ");
1187                 return;
1188         }
1189         tprintf("[%08lx] ", pc);
1190 # elif defined(ARM)
1191         long pc;
1192
1193         if (upeek(tcp, 4*15, &pc) < 0) {
1194                 PRINTBADPC;
1195                 return;
1196         }
1197         tprintf("[%08lx] ", pc);
1198 # elif defined(AVR32)
1199         long pc;
1200
1201         if (upeek(tcp, REG_PC, &pc) < 0) {
1202                 tprints("[????????] ");
1203                 return;
1204         }
1205         tprintf("[%08lx] ", pc);
1206 # elif defined(BFIN)
1207         long pc;
1208
1209         if (upeek(tcp, PT_PC, &pc) < 0) {
1210                 PRINTBADPC;
1211                 return;
1212         }
1213         tprintf("[%08lx] ", pc);
1214 #elif defined(CRISV10)
1215         long pc;
1216
1217         if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
1218                 PRINTBADPC;
1219                 return;
1220         }
1221         tprintf("[%08lx] ", pc);
1222 #elif defined(CRISV32)
1223         long pc;
1224
1225         if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
1226                 PRINTBADPC;
1227                 return;
1228         }
1229         tprintf("[%08lx] ", pc);
1230 # endif /* architecture */
1231 #endif /* LINUX */
1232
1233 #ifdef SUNOS4
1234         struct regs regs;
1235
1236         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1237                 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
1238                 PRINTBADPC;
1239                 return;
1240         }
1241         tprintf("[%08x] ", regs.r_o7);
1242 #endif /* SUNOS4 */
1243
1244 #ifdef SVR4
1245         /* XXX */
1246         PRINTBADPC;
1247 #endif
1248
1249 #ifdef FREEBSD
1250         struct reg regs;
1251         pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1252         tprintf("[%08x] ", regs.r_eip);
1253 #endif /* FREEBSD */
1254 }
1255
1256
1257 /*
1258  * These #if's are huge, please indent them correctly.
1259  * It's easy to get confused otherwise.
1260  */
1261 #ifndef USE_PROCFS
1262
1263 # ifdef LINUX
1264
1265 #  include "syscall.h"
1266
1267 #  include <sys/syscall.h>
1268 #  ifndef CLONE_PTRACE
1269 #   define CLONE_PTRACE    0x00002000
1270 #  endif
1271 #  ifndef CLONE_VFORK
1272 #   define CLONE_VFORK     0x00004000
1273 #  endif
1274 #  ifndef CLONE_VM
1275 #   define CLONE_VM        0x00000100
1276 #  endif
1277 #  ifndef CLONE_STOPPED
1278 #   define CLONE_STOPPED   0x02000000
1279 #  endif
1280
1281 #  ifdef IA64
1282
1283 /* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1284    subsystem has them for x86... */
1285 #   define SYS_fork     2
1286 #   define SYS_vfork    190
1287
1288 typedef unsigned long *arg_setup_state;
1289
1290 static int
1291 arg_setup(struct tcb *tcp, arg_setup_state *state)
1292 {
1293         unsigned long cfm, sof, sol;
1294         long bsp;
1295
1296         if (ia32) {
1297                 /* Satisfy a false GCC warning.  */
1298                 *state = NULL;
1299                 return 0;
1300         }
1301
1302         if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
1303                 return -1;
1304         if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
1305                 return -1;
1306
1307         sof = (cfm >> 0) & 0x7f;
1308         sol = (cfm >> 7) & 0x7f;
1309         bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
1310
1311         *state = (unsigned long *) bsp;
1312         return 0;
1313 }
1314
1315 #   define arg_finish_change(tcp, state)        0
1316
1317 #   ifdef SYS_fork
1318 static int
1319 get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
1320 {
1321         int ret;
1322
1323         if (ia32)
1324                 ret = upeek(tcp, PT_R11, valp);
1325         else
1326                 ret = umoven(tcp,
1327                               (unsigned long) ia64_rse_skip_regs(*state, 0),
1328                               sizeof(long), (void *) valp);
1329         return ret;
1330 }
1331
1332 static int
1333 get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
1334 {
1335         int ret;
1336
1337         if (ia32)
1338                 ret = upeek(tcp, PT_R9, valp);
1339         else
1340                 ret = umoven(tcp,
1341                               (unsigned long) ia64_rse_skip_regs(*state, 1),
1342                               sizeof(long), (void *) valp);
1343         return ret;
1344 }
1345 #   endif
1346
1347 static int
1348 set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
1349 {
1350         int req = PTRACE_POKEDATA;
1351         void *ap;
1352
1353         if (ia32) {
1354                 ap = (void *) (intptr_t) PT_R11;         /* r11 == EBX */
1355                 req = PTRACE_POKEUSER;
1356         } else
1357                 ap = ia64_rse_skip_regs(*state, 0);
1358         errno = 0;
1359         ptrace(req, tcp->pid, ap, val);
1360         return errno ? -1 : 0;
1361 }
1362
1363 static int
1364 set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
1365 {
1366         int req = PTRACE_POKEDATA;
1367         void *ap;
1368
1369         if (ia32) {
1370                 ap = (void *) (intptr_t) PT_R9;         /* r9 == ECX */
1371                 req = PTRACE_POKEUSER;
1372         } else
1373                 ap = ia64_rse_skip_regs(*state, 1);
1374         errno = 0;
1375         ptrace(req, tcp->pid, ap, val);
1376         return errno ? -1 : 0;
1377 }
1378
1379 /* ia64 does not return the input arguments from functions (and syscalls)
1380    according to ia64 RSE (Register Stack Engine) behavior.  */
1381
1382 #   define restore_arg0(tcp, state, val) ((void) (state), 0)
1383 #   define restore_arg1(tcp, state, val) ((void) (state), 0)
1384
1385 #  elif defined (SPARC) || defined (SPARC64)
1386
1387 typedef struct pt_regs arg_setup_state;
1388
1389 #   define arg_setup(tcp, state) \
1390     (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
1391 #   define arg_finish_change(tcp, state) \
1392     (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
1393
1394 #   define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1395 #   define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1396 #   define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1397 #   define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
1398 #   define restore_arg0(tcp, state, val) 0
1399
1400 #  else /* other architectures */
1401
1402 #   if defined S390 || defined S390X
1403 /* Note: this is only true for the `clone' system call, which handles
1404    arguments specially.  We could as well say that its first two arguments
1405    are swapped relative to other architectures, but that would just be
1406    another #ifdef in the calls.  */
1407 #    define arg0_offset PT_GPR3
1408 #    define arg1_offset PT_ORIGGPR2
1409 #    define restore_arg0(tcp, state, val) ((void) (state), 0)
1410 #    define restore_arg1(tcp, state, val) ((void) (state), 0)
1411 #    define arg0_index  1
1412 #    define arg1_index  0
1413 #   elif defined (ALPHA) || defined (MIPS)
1414 #    define arg0_offset REG_A0
1415 #    define arg1_offset (REG_A0+1)
1416 #   elif defined (AVR32)
1417 #    define arg0_offset (REG_R12)
1418 #    define arg1_offset (REG_R11)
1419 #   elif defined (POWERPC)
1420 #    define arg0_offset (sizeof(unsigned long)*PT_R3)
1421 #    define arg1_offset (sizeof(unsigned long)*PT_R4)
1422 #    define restore_arg0(tcp, state, val) ((void) (state), 0)
1423 #   elif defined (HPPA)
1424 #    define arg0_offset  PT_GR26
1425 #    define arg1_offset  (PT_GR26-4)
1426 #   elif defined (X86_64)
1427 #    define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1428 #    define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1429 #   elif defined (SH)
1430 #    define arg0_offset (4*(REG_REG0+4))
1431 #    define arg1_offset (4*(REG_REG0+5))
1432 #   elif defined (SH64)
1433     /* ABI defines arg0 & 1 in r2 & r3 */
1434 #    define arg0_offset   (REG_OFFSET+16)
1435 #    define arg1_offset   (REG_OFFSET+24)
1436 #    define restore_arg0(tcp, state, val) 0
1437 #   elif defined CRISV10 || defined CRISV32
1438 #    define arg0_offset   (4*PT_R11)
1439 #    define arg1_offset   (4*PT_ORIG_R10)
1440 #    define restore_arg0(tcp, state, val) 0
1441 #    define restore_arg1(tcp, state, val) 0
1442 #    define arg0_index   1
1443 #    define arg1_index   0
1444 #   else
1445 #    define arg0_offset 0
1446 #    define arg1_offset 4
1447 #    if defined ARM
1448 #     define restore_arg0(tcp, state, val) 0
1449 #    endif
1450 #   endif
1451
1452 typedef int arg_setup_state;
1453
1454 #   define arg_setup(tcp, state) (0)
1455 #   define arg_finish_change(tcp, state)        0
1456 #   define get_arg0(tcp, cookie, valp) \
1457     (upeek((tcp), arg0_offset, (valp)))
1458 #   define get_arg1(tcp, cookie, valp) \
1459     (upeek((tcp), arg1_offset, (valp)))
1460
1461 static int
1462 set_arg0(struct tcb *tcp, void *cookie, long val)
1463 {
1464         return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
1465 }
1466
1467 static int
1468 set_arg1(struct tcb *tcp, void *cookie, long val)
1469 {
1470         return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
1471 }
1472
1473 #  endif /* architectures */
1474
1475 #  ifndef restore_arg0
1476 #   define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1477 #  endif
1478 #  ifndef restore_arg1
1479 #   define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1480 #  endif
1481
1482 #  ifndef arg0_index
1483 #   define arg0_index 0
1484 #   define arg1_index 1
1485 #  endif
1486
1487 int
1488 setbpt(struct tcb *tcp)
1489 {
1490         static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
1491         arg_setup_state state;
1492
1493         if (tcp->flags & TCB_BPTSET) {
1494                 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1495                 return -1;
1496         }
1497
1498         /*
1499          * It's a silly kludge to initialize this with a search at runtime.
1500          * But it's better than maintaining another magic thing in the
1501          * godforsaken tables.
1502          */
1503         if (clone_scno[current_personality] == 0) {
1504                 int i;
1505                 for (i = 0; i < nsyscalls; ++i)
1506                         if (sysent[i].sys_func == sys_clone) {
1507                                 clone_scno[current_personality] = i;
1508                                 break;
1509                         }
1510         }
1511
1512         switch (known_scno(tcp)) {
1513 #  ifdef SYS_vfork
1514         case SYS_vfork:
1515 #  endif
1516 #  ifdef SYS_fork
1517         case SYS_fork:
1518 #  endif
1519 #  if defined SYS_fork || defined SYS_vfork
1520                 if (arg_setup(tcp, &state) < 0
1521                     || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1522                     || get_arg1(tcp, &state, &tcp->inst[1]) < 0
1523                     || change_syscall(tcp, clone_scno[current_personality]) < 0
1524                     || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1525                     || set_arg1(tcp, &state, 0) < 0
1526                     || arg_finish_change(tcp, &state) < 0)
1527                         return -1;
1528                 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1529                 tcp->u_arg[arg1_index] = 0;
1530                 tcp->flags |= TCB_BPTSET;
1531                 return 0;
1532 #  endif
1533
1534         case SYS_clone: ;
1535 #  ifdef SYS_clone2
1536         case SYS_clone2: ;
1537 #  endif
1538                 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1539                    contrary to x86 SYS_vfork above.  Even on x86 we turn the
1540                    vfork semantics into plain fork - each application must not
1541                    depend on the vfork specifics according to POSIX.  We would
1542                    hang waiting for the parent resume otherwise.  We need to
1543                    clear also CLONE_VM but only in the CLONE_VFORK case as
1544                    otherwise we would break pthread_create.  */
1545
1546                 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1547                 if (new_arg0 & CLONE_VFORK)
1548                         new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1549                 if (arg_setup(tcp, &state) < 0
1550                  || set_arg0(tcp, &state, new_arg0) < 0
1551                  || arg_finish_change(tcp, &state) < 0)
1552                         return -1;
1553                 tcp->flags |= TCB_BPTSET;
1554                 tcp->inst[0] = tcp->u_arg[arg0_index];
1555                 tcp->inst[1] = tcp->u_arg[arg1_index];
1556                 return 0;
1557
1558         default:
1559                 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1560                         tcp->scno, tcp->pid);
1561                 break;
1562         }
1563
1564         return -1;
1565 }
1566
1567 int
1568 clearbpt(struct tcb *tcp)
1569 {
1570         arg_setup_state state;
1571         if (arg_setup(tcp, &state) < 0
1572             || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1573             || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1574             || arg_finish_change(tcp, &state))
1575                 if (errno != ESRCH)
1576                         return -1;
1577         tcp->flags &= ~TCB_BPTSET;
1578         return 0;
1579 }
1580
1581 # else /* !defined LINUX */
1582
1583 int
1584 setbpt(struct tcb *tcp)
1585 {
1586 #  ifdef SUNOS4
1587 #   ifdef SPARC /* This code is slightly sparc specific */
1588
1589         struct regs regs;
1590 #    define BPT 0x91d02001      /* ta   1 */
1591 #    define LOOP        0x10800000      /* ba   0 */
1592 #    define LOOPA       0x30800000      /* ba,a 0 */
1593 #    define NOP 0x01000000
1594 #    if LOOPA
1595         static int loopdeloop[1] = {LOOPA};
1596 #    else
1597         static int loopdeloop[2] = {LOOP, NOP};
1598 #    endif
1599
1600         if (tcp->flags & TCB_BPTSET) {
1601                 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1602                 return -1;
1603         }
1604         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1605                 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1606                 return -1;
1607         }
1608         tcp->baddr = regs.r_o7 + 8;
1609         if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1610                                 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1611                 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1612                 return -1;
1613         }
1614
1615         /*
1616          * XXX - BRUTAL MODE ON
1617          * We cannot set a real BPT in the child, since it will not be
1618          * traced at the moment it will reach the trap and would probably
1619          * die with a core dump.
1620          * Thus, we are force our way in by taking out two instructions
1621          * and insert an eternal loop in stead, in expectance of the SIGSTOP
1622          * generated by out PTRACE_ATTACH.
1623          * Of cause, if we evaporate ourselves in the middle of all this...
1624          */
1625         if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1626                         sizeof loopdeloop, (char *) loopdeloop) < 0) {
1627                 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1628                 return -1;
1629         }
1630         tcp->flags |= TCB_BPTSET;
1631
1632 #   endif /* SPARC */
1633 #  endif /* SUNOS4 */
1634
1635         return 0;
1636 }
1637
1638 int
1639 clearbpt(struct tcb *tcp)
1640 {
1641 #  ifdef SUNOS4
1642 #   ifdef SPARC
1643
1644 #    if !LOOPA
1645         struct regs regs;
1646 #    endif
1647
1648         if (!(tcp->flags & TCB_BPTSET)) {
1649                 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1650                 return -1;
1651         }
1652         if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1653                                 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1654                 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1655                 return -1;
1656         }
1657         tcp->flags &= ~TCB_BPTSET;
1658
1659 #    if !LOOPA
1660         /*
1661          * Since we don't have a single instruction breakpoint, we may have
1662          * to adjust the program counter after removing our `breakpoint'.
1663          */
1664         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1665                 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1666                 return -1;
1667         }
1668         if ((regs.r_pc < tcp->baddr) ||
1669                                 (regs.r_pc > tcp->baddr + 4)) {
1670                 /* The breakpoint has not been reached yet */
1671                 if (debug)
1672                         fprintf(stderr,
1673                                 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1674                                         regs.r_pc, tcp->baddr);
1675                 return 0;
1676         }
1677         if (regs.r_pc != tcp->baddr)
1678                 if (debug)
1679                         fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1680                                 regs.r_pc, tcp->baddr);
1681
1682         regs.r_pc = tcp->baddr;
1683         if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1684                 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1685                 return -1;
1686         }
1687 #    endif /* LOOPA */
1688 #   endif /* SPARC */
1689 #  endif /* SUNOS4 */
1690
1691         return 0;
1692 }
1693
1694 # endif /* !defined LINUX */
1695
1696 #endif /* !USE_PROCFS */
1697
1698
1699 #ifdef SUNOS4
1700
1701 static int
1702 getex(struct tcb *tcp, struct exec *hdr)
1703 {
1704         int n;
1705
1706         for (n = 0; n < sizeof *hdr; n += 4) {
1707                 long res;
1708                 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
1709                         return -1;
1710                 memcpy(((char *) hdr) + n, &res, 4);
1711         }
1712         if (debug) {
1713                 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1714                         hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1715                 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1716                         hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1717         }
1718         return 0;
1719 }
1720
1721 int
1722 fixvfork(struct tcb *tcp)
1723 {
1724         int pid = tcp->pid;
1725         /*
1726          * Change `vfork' in a freshly exec'ed dynamically linked
1727          * executable's (internal) symbol table to plain old `fork'
1728          */
1729
1730         struct exec hdr;
1731         struct link_dynamic dyn;
1732         struct link_dynamic_2 ld;
1733         char *strtab, *cp;
1734
1735         if (getex(tcp, &hdr) < 0)
1736                 return -1;
1737         if (!hdr.a_dynamic)
1738                 return -1;
1739
1740         if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1741                 fprintf(stderr, "Cannot read DYNAMIC\n");
1742                 return -1;
1743         }
1744         if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1745                 fprintf(stderr, "Cannot read link_dynamic_2\n");
1746                 return -1;
1747         }
1748         strtab = malloc((unsigned)ld.ld_symb_size);
1749         if (!strtab)
1750                 die_out_of_memory();
1751         if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1752                                         (int)ld.ld_symb_size, strtab) < 0)
1753                 goto err;
1754
1755         for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1756                 if (strcmp(cp, "_vfork") == 0) {
1757                         if (debug)
1758                                 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1759                         strcpy(cp, "_fork");
1760                         break;
1761                 }
1762                 cp += strlen(cp)+1;
1763         }
1764         if (cp < strtab + ld.ld_symb_size)
1765                 /*
1766                  * Write entire symbol table back to avoid
1767                  * memory alignment bugs in ptrace
1768                  */
1769                 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1770                                         (int)ld.ld_symb_size, strtab) < 0)
1771                         goto err;
1772
1773         free(strtab);
1774         return 0;
1775
1776 err:
1777         free(strtab);
1778         return -1;
1779 }
1780
1781 #endif /* SUNOS4 */