]> granicus.if.org Git - strace/blob - util.c
d92c0ea83821749f0f4af177121a26a7e36d2dc3
[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)
82
83 # define fpq kernel_fpq
84 # define fq kernel_fq
85 # define fpu kernel_fpu
86 # include <asm/reg.h>
87 # undef fpq
88 # undef fq
89 # undef fpu
90
91 #if defined (SPARC64)
92 # define r_pc r_tpc
93 # undef PTRACE_GETREGS
94 # define PTRACE_GETREGS PTRACE_GETREGS64
95 # undef PTRACE_SETREGS
96 # define PTRACE_SETREGS PTRACE_SETREGS64
97 #endif /* SPARC64 */
98
99 #if !defined(__GLIBC__)
100
101 #include <linux/unistd.h>
102
103 #define _hack_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,\
104           type5,arg5,syscall) \
105 type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
106 { \
107       long __res; \
108 \
109 __asm__ volatile ("or %%g0, %1, %%o0\n\t" \
110                   "or %%g0, %2, %%o1\n\t" \
111                   "or %%g0, %3, %%o2\n\t" \
112                   "or %%g0, %4, %%o3\n\t" \
113                   "or %%g0, %5, %%o4\n\t" \
114                   "or %%g0, %6, %%g1\n\t" \
115 #if defined (SPARC64)
116                   "t 0x6d\n\t" \
117 #else
118                   "t 0x10\n\t" \
119 #endif
120                   "bcc 1f\n\t" \
121                   "or %%g0, %%o0, %0\n\t" \
122                   "sub %%g0, %%o0, %0\n\t" \
123                   "1:\n\t" \
124                   : "=r" (__res) \
125                   : "0" ((long)(arg1)),"1" ((long)(arg2)), \
126                     "2" ((long)(arg3)),"3" ((long)(arg4)),"4" ((long)(arg5)), \
127                     "i" (__NR_##syscall)  \
128                   : "g1", "o0", "o1", "o2", "o3", "o4"); \
129 if (__res>=0) \
130         return (type) __res; \
131 errno = -__res; \
132 return -1; \
133 }
134
135 static _hack_syscall5(int,_ptrace,int,__request,int,__pid,int,__addr,int,__data,int,__addr2,ptrace)
136
137 #define _ptrace
138
139 #endif
140
141 #endif
142
143 /* macros */
144 #ifndef MAX
145 #define MAX(a,b)                (((a) > (b)) ? (a) : (b))
146 #endif
147 #ifndef MIN
148 #define MIN(a,b)                (((a) < (b)) ? (a) : (b))
149 #endif
150
151 void
152 tv_tv(tv, a, b)
153 struct timeval *tv;
154 int a;
155 int b;
156 {
157         tv->tv_sec = a;
158         tv->tv_usec = b;
159 }
160
161 int
162 tv_nz(a)
163 struct timeval *a;
164 {
165         return a->tv_sec || a->tv_usec;
166 }
167
168 int
169 tv_cmp(a, b)
170 struct timeval *a, *b;
171 {
172         if (a->tv_sec < b->tv_sec
173             || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
174                 return -1;
175         if (a->tv_sec > b->tv_sec
176             || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
177                 return 1;
178         return 0;
179 }
180
181 double
182 tv_float(tv)
183 struct timeval *tv;
184 {
185         return tv->tv_sec + tv->tv_usec/1000000.0;
186 }
187
188 void
189 tv_add(tv, a, b)
190 struct timeval *tv, *a, *b;
191 {
192         tv->tv_sec = a->tv_sec + b->tv_sec;
193         tv->tv_usec = a->tv_usec + b->tv_usec;
194         if (tv->tv_usec > 1000000) {
195                 tv->tv_sec++;
196                 tv->tv_usec -= 1000000;
197         }
198 }
199
200 void
201 tv_sub(tv, a, b)
202 struct timeval *tv, *a, *b;
203 {
204         tv->tv_sec = a->tv_sec - b->tv_sec;
205         tv->tv_usec = a->tv_usec - b->tv_usec;
206         if (((long) tv->tv_usec) < 0) {
207                 tv->tv_sec--;
208                 tv->tv_usec += 1000000;
209         }
210 }
211
212 void
213 tv_div(tv, a, n)
214 struct timeval *tv, *a;
215 int n;
216 {
217         tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
218         tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
219         tv->tv_usec %= 1000000;
220 }
221
222 void
223 tv_mul(tv, a, n)
224 struct timeval *tv, *a;
225 int n;
226 {
227         tv->tv_usec = a->tv_usec * n;
228         tv->tv_sec = a->tv_sec * n + a->tv_usec / 1000000;
229         tv->tv_usec %= 1000000;
230 }
231
232 char *
233 xlookup(xlat, val)
234 const struct xlat *xlat;
235 int val;
236 {
237         for (; xlat->str != NULL; xlat++)
238                 if (xlat->val == val)
239                         return xlat->str;
240         return NULL;
241 }
242
243 /*
244  * Print entry in struct xlat table, if there.
245  */
246 void
247 printxval(xlat, val, dflt)
248 const struct xlat *xlat;
249 int val;
250 const char *dflt;
251 {
252         char *str = xlookup(xlat, val);
253
254         if (str)
255                 tprintf("%s", str);
256         else
257                 tprintf("%#x /* %s */", val, dflt);
258 }
259
260 /*
261  * Interpret `xlat' as an array of flags
262  * print the entries whose bits are on in `flags'
263  * return # of flags printed.
264  */
265 int
266 addflags(xlat, flags)
267 const struct xlat *xlat;
268 int flags;
269 {
270         int n;
271
272         for (n = 0; xlat->str; xlat++) {
273                 if (xlat->val && (flags & xlat->val) == xlat->val) {
274                         tprintf("|%s", xlat->str);
275                         flags &= ~xlat->val;
276                         n++;
277                 }
278         }
279         if (flags) {
280                 tprintf("|%#x", flags);
281                 n++;
282         }
283         return n;
284 }
285
286 int
287 printflags(xlat, flags, dflt)
288 const struct xlat *xlat;
289 int flags;
290 const char *dflt;
291 {
292         int n;
293         char *sep;
294
295         if (flags == 0 && xlat->val == 0) {
296                 tprintf("%s", xlat->str);
297                 return 1;
298         }
299
300         sep = "";
301         for (n = 0; xlat->str; xlat++) {
302                 if (xlat->val && (flags & xlat->val) == xlat->val) {
303                         tprintf("%s%s", sep, xlat->str);
304                         flags &= ~xlat->val;
305                         sep = "|";
306                         n++;
307                 }
308         }
309
310         if (n) {
311                 if (flags) {
312                         tprintf("%s%#x", sep, flags);
313                         n++;
314                 }
315         } else {
316                 if (flags) {
317                         tprintf("%#x", flags);
318                         if (dflt)
319                                 tprintf(" /* %s */", dflt);
320                 } else {
321                         if (dflt)
322                                 tprintf("0");
323                 }
324         }
325
326         return n;
327 }
328
329 void
330 printnum(tcp, addr, fmt)
331 struct tcb *tcp;
332 long addr;
333 char *fmt;
334 {
335         long num;
336
337         if (!addr) {
338                 tprintf("NULL");
339                 return;
340         }
341         if (umove(tcp, addr, &num) < 0) {
342                 tprintf("%#lx", addr);
343                 return;
344         }
345         tprintf("[");
346         tprintf(fmt, num);
347         tprintf("]");
348 }
349
350 void
351 printuid(text, uid)
352 const char *text;
353 unsigned long uid;
354 {
355         tprintf("%s", text);
356         tprintf((uid == -1) ? "%ld" : "%lu", uid);
357 }
358
359 static char path[MAXPATHLEN + 1];
360
361 void
362 string_quote(str)
363 char *str;
364 {
365         char buf[2 * MAXPATHLEN + 1];
366         char *s;
367
368         if (!strpbrk(str, "\"\'\\")) {
369                 tprintf("\"%s\"", str);
370                 return;
371         }
372         for (s = buf; *str; str++) {
373                 switch (*str) {
374                 case '\"': case '\'': case '\\':
375                         *s++ = '\\'; *s++ = *str; break;
376                 default:
377                         *s++ = *str; break;
378                 }
379         }
380         *s = '\0';
381         tprintf("\"%s\"", buf);
382 }
383
384 void
385 printpath(tcp, addr)
386 struct tcb *tcp;
387 long addr;
388 {
389         if (addr == 0)
390                 tprintf("NULL");
391         else if (umovestr(tcp, addr, MAXPATHLEN, path) < 0)
392                 tprintf("%#lx", addr);
393         else
394                 string_quote(path);
395         return;
396 }
397
398 void
399 printpathn(tcp, addr, n)
400 struct tcb *tcp;
401 long addr;
402 int n;
403 {
404         if (addr == 0)
405                 tprintf("NULL");
406         else    if (umovestr(tcp, addr, n, path) < 0)
407                 tprintf("%#lx", addr);
408         else {
409                 path[n] = '\0';
410                 string_quote(path);
411         }
412 }
413
414 void
415 printstr(tcp, addr, len)
416 struct tcb *tcp;
417 long addr;
418 int len;
419 {
420         static unsigned char *str = NULL;
421         static char *outstr;
422         int i, n, c, usehex;
423         char *s, *outend;
424
425         if (!addr) {
426                 tprintf("NULL");
427                 return;
428         }
429         if (!str) {
430                 if ((str = malloc(max_strlen)) == NULL
431                     || (outstr = malloc(2*max_strlen)) == NULL) {
432                         fprintf(stderr, "out of memory\n");
433                         tprintf("%#lx", addr);
434                         return;
435                 }
436         }
437         outend = outstr + max_strlen * 2 - 10;
438         if (len < 0) {
439                 n = max_strlen;
440                 if (umovestr(tcp, addr, n, (char *) str) < 0) {
441                         tprintf("%#lx", addr);
442                         return;
443                 }
444         }
445         else {
446                 n = MIN(len, max_strlen);
447                 if (umoven(tcp, addr, n, (char *) str) < 0) {
448                         tprintf("%#lx", addr);
449                         return;
450                 }
451         }
452
453         usehex = 0;
454         if (xflag > 1)
455                 usehex = 1;
456         else if (xflag) {
457                 for (i = 0; i < n; i++) {
458                         c = str[i];
459                         if (len < 0 && c == '\0')
460                                 break;
461                         if (!isprint(c) && !isspace(c)) {
462                                 usehex = 1;
463                                 break;
464                         }
465                 }
466         }
467
468         s = outstr;
469         *s++ = '\"';
470
471         if (usehex) {
472                 for (i = 0; i < n; i++) {
473                         c = str[i];
474                         if (len < 0 && c == '\0')
475                                 break;
476                         sprintf(s, "\\x%02x", c);
477                         s += 4;
478                         if (s > outend)
479                                 break;
480                 }
481         }
482         else {
483                 for (i = 0; i < n; i++) {
484                         c = str[i];
485                         if (len < 0 && c == '\0')
486                                 break;
487                         switch (c) {
488                         case '\"': case '\'': case '\\':
489                                 *s++ = '\\'; *s++ = c; break;
490                         case '\f':
491                                 *s++ = '\\'; *s++ = 'f'; break;
492                         case '\n':
493                                 *s++ = '\\'; *s++ = 'n'; break;
494                         case '\r':
495                                 *s++ = '\\'; *s++ = 'r'; break;
496                         case '\t':
497                                 *s++ = '\\'; *s++ = 't'; break;
498                         case '\v':
499                                 *s++ = '\\'; *s++ = 'v'; break;
500                         default:
501                                 if (isprint(c))
502                                         *s++ = c;
503                                 else if (i < n - 1 && isdigit(str[i + 1])) {
504                                         sprintf(s, "\\%03o", c);
505                                         s += 4;
506                                 }
507                                 else {
508                                         sprintf(s, "\\%o", c);
509                                         s += strlen(s);
510                                 }
511                                 break;
512                         }
513                         if (s > outend)
514                                 break;
515                 }
516         }
517
518         *s++ = '\"';
519         if (i < len || (len < 0 && (i == n || s > outend))) {
520                 *s++ = '.'; *s++ = '.'; *s++ = '.';
521         }
522         *s = '\0';
523         tprintf("%s", outstr);
524 }
525
526 #if HAVE_SYS_UIO_H
527 void
528 dumpiov(tcp, len, addr)
529 struct tcb * tcp;
530 int len;
531 long addr;
532 {
533         struct iovec *iov;
534         int i;
535
536
537         if ((iov = (struct iovec *) malloc(len * sizeof *iov)) == NULL) {
538                 fprintf(stderr, "dump: No memory");
539                 return;
540         }
541         if (umoven(tcp, addr,
542                    len * sizeof *iov, (char *) iov) >= 0) {
543
544                 for (i = 0; i < len; i++) {
545                         /* include the buffer number to make it easy to
546                          * match up the trace with the source */
547                         tprintf(" * %lu bytes in buffer %d\n",
548                                 (unsigned long)iov[i].iov_len, i);
549                         dumpstr(tcp, (long) iov[i].iov_base,
550                                 iov[i].iov_len);
551                 }
552         }
553         free((char *) iov);
554
555 }
556 #endif
557
558 void
559 dumpstr(tcp, addr, len)
560 struct tcb *tcp;
561 long addr;
562 int len;
563 {
564         static int strsize = -1;
565         static unsigned char *str;
566         static char outstr[80];
567         char *s;
568         int i, j;
569
570         if (strsize < len) {
571                 if (str)
572                         free(str);
573                 if ((str = malloc(len)) == NULL) {
574                         fprintf(stderr, "out of memory\n");
575                         return;
576                 }
577                 strsize = len;
578         }
579
580         if (umoven(tcp, addr, len, (char *) str) < 0)
581                 return;
582
583         for (i = 0; i < len; i += 16) {
584                 s = outstr;
585                 sprintf(s, " | %05x ", i);
586                 s += 9;
587                 for (j = 0; j < 16; j++) {
588                         if (j == 8)
589                                 *s++ = ' ';
590                         if (i + j < len) {
591                                 sprintf(s, " %02x", str[i + j]);
592                                 s += 3;
593                         }
594                         else {
595                                 *s++ = ' '; *s++ = ' '; *s++ = ' ';
596                         }
597                 }
598                 *s++ = ' '; *s++ = ' ';
599                 for (j = 0; j < 16; j++) {
600                         if (j == 8)
601                                 *s++ = ' ';
602                         if (i + j < len) {
603                                 if (isprint(str[i + j]))
604                                         *s++ = str[i + j];
605                                 else
606                                         *s++ = '.';
607                         }
608                         else
609                                 *s++ = ' ';
610                 }
611                 tprintf("%s |\n", outstr);
612         }
613 }
614
615 #define PAGMASK (~(PAGSIZ - 1))
616 /*
617  * move `len' bytes of data from process `pid'
618  * at address `addr' to our space at `laddr'
619  */
620 int
621 umoven(tcp, addr, len, laddr)
622 struct tcb *tcp;
623 long addr;
624 int len;
625 char *laddr;
626 {
627
628 #ifdef LINUX
629         int pid = tcp->pid;
630         int n, m;
631         int started = 0;
632         union {
633                 long val;
634                 char x[sizeof(long)];
635         } u;
636
637         if (addr & (sizeof(long) - 1)) {
638                 /* addr not a multiple of sizeof(long) */
639                 n = addr - (addr & -sizeof(long)); /* residue */
640                 addr &= -sizeof(long); /* residue */
641                 errno = 0;
642                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
643                 if (errno) {
644                         if (started && (errno==EPERM || errno==EIO)) {
645                                 /* Ran into 'end of memory' - stupid "printpath" */
646                                 return 0;
647                         }
648                         /* But if not started, we had a bogus address. */
649                         perror("ptrace: umoven");
650                         return -1;
651                 }
652                 started = 1;
653                 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
654                 addr += sizeof(long), laddr += m, len -= m;
655         }
656         while (len) {
657                 errno = 0;
658                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
659                 if (errno) {
660                         if (started && (errno==EPERM || errno==EIO)) {
661                                 /* Ran into 'end of memory' - stupid "printpath" */
662                                 return 0;
663                         }
664                         if (addr != 0)
665                                 perror("ptrace: umoven");
666                         return -1;
667                 }
668                 started = 1;
669                 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
670                 addr += sizeof(long), laddr += m, len -= m;
671         }
672 #endif /* LINUX */
673
674 #ifdef SUNOS4
675         int pid = tcp->pid;
676 #if 0
677         int n, m;
678         union {
679                 long val;
680                 char x[sizeof(long)];
681         } u;
682
683         if (addr & (sizeof(long) - 1)) {
684                 /* addr not a multiple of sizeof(long) */
685                 n = addr - (addr & -sizeof(long)); /* residue */
686                 addr &= -sizeof(long); /* residue */
687                 errno = 0;
688                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
689                 if (errno) {
690                         perror("umoven");
691                         return -1;
692                 }
693                 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
694                 addr += sizeof(long), laddr += m, len -= m;
695         }
696         while (len) {
697                 errno = 0;
698                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
699                 if (errno) {
700                         perror("umoven");
701                         return -1;
702                 }
703                 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
704                 addr += sizeof(long), laddr += m, len -= m;
705         }
706 #else /* !oldway */
707         int n;
708
709         while (len) {
710                 n = MIN(len, PAGSIZ);
711                 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
712                 if (ptrace(PTRACE_READDATA, pid,
713                            (char *) addr, len, laddr) < 0) {
714                         perror("umoven: ptrace(PTRACE_READDATA, ...)");
715                         abort();
716                         return -1;
717                 }
718                 len -= n;
719                 addr += n;
720                 laddr += n;
721         }
722 #endif /* !oldway */
723 #endif /* SUNOS4 */
724
725 #ifdef USE_PROCFS
726 #ifdef HAVE_MP_PROCFS
727         int fd = tcp->pfd_as;
728 #else
729         int fd = tcp->pfd;
730 #endif
731         lseek(fd, addr, SEEK_SET);
732         if (read(fd, laddr, len) == -1)
733                 return -1;
734 #endif /* USE_PROCFS */
735
736         return 0;
737 }
738
739 /*
740  * like `umove' but make the additional effort of looking
741  * for a terminating zero byte.
742  */
743 int
744 umovestr(tcp, addr, len, laddr)
745 struct tcb *tcp;
746 long addr;
747 int len;
748 char *laddr;
749 {
750 #ifdef USE_PROCFS
751 #ifdef HAVE_MP_PROCFS
752         int fd = tcp->pfd_as;
753 #else
754         int fd = tcp->pfd;
755 #endif
756         /* Some systems (e.g. FreeBSD) can be upset if we read off the
757            end of valid memory,  avoid this by trying to read up
758            to page boundaries.  But we don't know what a page is (and
759            getpagesize(2) (if it exists) doesn't necessarily return
760            hardware page size).  Assume all pages >= 1024 (a-historical
761            I know) */
762
763         int page = 1024;        /* How to find this? */
764         int move = page - (addr & (page - 1));
765         int left = len;
766
767         lseek(fd, addr, SEEK_SET);
768
769         while (left) {
770                 if (move > left) move = left;
771                 if ((move = read(fd, laddr, move)) <= 0)
772                         return left != len ? 0 : -1;
773                 if (memchr (laddr, 0, move)) break;
774                 left -= move;
775                 laddr += move;
776                 addr += move;
777                 move = page;
778         }
779 #else /* !USE_PROCFS */
780         int started = 0;
781         int pid = tcp->pid;
782         int i, n, m;
783         union {
784                 long val;
785                 char x[sizeof(long)];
786         } u;
787
788         if (addr & (sizeof(long) - 1)) {
789                 /* addr not a multiple of sizeof(long) */
790                 n = addr - (addr & -sizeof(long)); /* residue */
791                 addr &= -sizeof(long); /* residue */
792                 errno = 0;
793                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
794                 if (errno) {
795                         if (started && (errno==EPERM || errno==EIO)) {
796                                 /* Ran into 'end of memory' - stupid "printpath" */
797                                 return 0;
798                         }
799                         perror("umovestr");
800                         return -1;
801                 }
802                 started = 1;
803                 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
804                 while (n & (sizeof(long) - 1))
805                         if (u.x[n++] == '\0')
806                                 return 0;
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                         perror("umovestr");
818                         return -1;
819                 }
820                 started = 1;
821                 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
822                 for (i = 0; i < sizeof(long); i++)
823                         if (u.x[i] == '\0')
824                                 return 0;
825
826                 addr += sizeof(long), laddr += m, len -= m;
827         }
828 #endif /* !USE_PROCFS */
829         return 0;
830 }
831
832 #ifdef LINUX
833 #if !defined (SPARC) && !defined(SPARC64)
834 #define PTRACE_WRITETEXT        101
835 #define PTRACE_WRITEDATA        102
836 #endif /* !SPARC && !SPARC64 */
837 #endif /* LINUX */
838
839 #ifdef SUNOS4
840
841 static int
842 uload(cmd, pid, addr, len, laddr)
843 int cmd;
844 int pid;
845 long addr;
846 int len;
847 char *laddr;
848 {
849 #if 0
850         int n;
851
852         while (len) {
853                 n = MIN(len, PAGSIZ);
854                 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
855                 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
856                         perror("uload: ptrace(PTRACE_WRITE, ...)");
857                         return -1;
858                 }
859                 len -= n;
860                 addr += n;
861                 laddr += n;
862         }
863 #else
864         int peek, poke;
865         int n, m;
866         union {
867                 long val;
868                 char x[sizeof(long)];
869         } u;
870
871         if (cmd == PTRACE_WRITETEXT) {
872                 peek = PTRACE_PEEKTEXT;
873                 poke = PTRACE_POKETEXT;
874         }
875         else {
876                 peek = PTRACE_PEEKDATA;
877                 poke = PTRACE_POKEDATA;
878         }
879         if (addr & (sizeof(long) - 1)) {
880                 /* addr not a multiple of sizeof(long) */
881                 n = addr - (addr & -sizeof(long)); /* residue */
882                 addr &= -sizeof(long);
883                 errno = 0;
884                 u.val = ptrace(peek, pid, (char *) addr, 0);
885                 if (errno) {
886                         perror("uload: POKE");
887                         return -1;
888                 }
889                 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
890                 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
891                         perror("uload: POKE");
892                         return -1;
893                 }
894                 addr += sizeof(long), laddr += m, len -= m;
895         }
896         while (len) {
897                 if (len < sizeof(long))
898                         u.val = ptrace(peek, pid, (char *) addr, 0);
899                 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
900                 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
901                         perror("uload: POKE");
902                         return -1;
903                 }
904                 addr += sizeof(long), laddr += m, len -= m;
905         }
906 #endif
907         return 0;
908 }
909
910 int
911 tload(pid, addr, len, laddr)
912 int pid;
913 int addr, len;
914 char *laddr;
915 {
916         return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
917 }
918
919 int
920 dload(pid, addr, len, laddr)
921 int pid;
922 int addr;
923 int len;
924 char *laddr;
925 {
926         return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
927 }
928
929 #endif /* SUNOS4 */
930
931 #ifndef USE_PROCFS
932
933 int
934 upeek(pid, off, res)
935 int pid;
936 long off;
937 long *res;
938 {
939         long val;
940
941 #ifdef SUNOS4_KERNEL_ARCH_KLUDGE
942         {
943                 static int is_sun4m = -1;
944                 struct utsname name;
945
946                 /* Round up the usual suspects. */
947                 if (is_sun4m == -1) {
948                         if (uname(&name) < 0) {
949                                 perror("upeek: uname?");
950                                 exit(1);
951                         }
952                         is_sun4m = strcmp(name.machine, "sun4m") == 0;
953                         if (is_sun4m) {
954                                 extern const struct xlat struct_user_offsets[];
955                                 const struct xlat *x;
956
957                                 for (x = struct_user_offsets; x->str; x++)
958                                         x->val += 1024;
959                         }
960                 }
961                 if (is_sun4m)
962                         off += 1024;
963         }
964 #endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
965         errno = 0;
966         val = ptrace(PTRACE_PEEKUSER, pid, (char *) off, 0);
967         if (val == -1 && errno) {
968                 char buf[60];
969                 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)",pid,off);
970                 perror(buf);
971                 return -1;
972         }
973         *res = val;
974         return 0;
975 }
976
977 #endif /* !USE_PROCFS */
978
979 long
980 getpc(tcp)
981 struct tcb *tcp;
982 {
983
984 #ifdef LINUX
985         long pc;
986 #if defined(I386)
987         if (upeek(tcp->pid, 4*EIP, &pc) < 0)
988                 return -1;
989 #elif defined(X86_64)
990         if (upeek(tcp->pid, 8*RIP, &pc) < 0)
991                 return -1;
992 #elif defined(IA64)
993         if (upeek(tcp->pid, PT_B0, &pc) < 0)
994                 return -1;
995 #elif defined(ARM)
996         if (upeek(tcp->pid, 4*15, &pc) < 0)
997                 return -1;
998 #elif defined(POWERPC)
999         if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0)
1000                 return -1;
1001 #elif defined(M68k)
1002         if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1003                 return -1;
1004 #elif defined(ALPHA)
1005         if (upeek(tcp->pid, REG_PC, &pc) < 0)
1006                 return -1;
1007 #elif defined(MIPS)
1008         if (upeek(tcp->pid, REG_EPC, &pc) < 0)
1009                 return -1;
1010 #elif defined(SPARC) || defined(SPARC64)
1011         struct regs regs;
1012         if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
1013                 return -1;
1014         pc = regs.r_pc;
1015 #elif defined(S390) || defined(S390X)
1016         if(upeek(tcp->pid,PT_PSWADDR,&pc) < 0)
1017                 return -1;
1018 #elif defined(HPPA)
1019         if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0)
1020                 return -1;
1021 #elif defined(SH)
1022        if (upeek(tcp->pid, 4*REG_PC ,&pc) < 0)
1023                return -1;
1024 #elif defined(SH64)
1025        if (upeek(tcp->pid, REG_PC ,&pc) < 0)
1026                return -1;
1027 #endif
1028         return pc;
1029 #endif /* LINUX */
1030
1031 #ifdef SUNOS4
1032         /*
1033          * Return current program counter for `pid'
1034          * Assumes PC is never 0xffffffff
1035          */
1036         struct regs regs;
1037
1038         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1039                 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
1040                 return -1;
1041         }
1042         return regs.r_pc;
1043 #endif /* SUNOS4 */
1044
1045 #ifdef SVR4
1046         /* XXX */
1047         return 0;
1048 #endif /* SVR4 */
1049
1050 #ifdef FREEBSD
1051         struct reg regs;
1052         pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1053         return regs.r_eip;
1054 #endif /* FREEBSD */
1055 }
1056
1057 void
1058 printcall(tcp)
1059 struct tcb *tcp;
1060 {
1061 #define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1062                            sizeof(long) == 8 ? "[????????????????] " : \
1063                            NULL /* crash */)
1064
1065 #ifdef LINUX
1066 #ifdef I386
1067         long eip;
1068
1069         if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
1070                 PRINTBADPC;
1071                 return;
1072         }
1073         tprintf("[%08lx] ", eip);
1074
1075 #elif defined(S390) || defined(S390X)
1076          long psw;
1077          if(upeek(tcp->pid,PT_PSWADDR,&psw) < 0) {
1078                  PRINTBADPC;
1079                  return;
1080          }
1081 #ifdef S390
1082          tprintf("[%08lx] ", psw);
1083 #elif S390X
1084        tprintf("[%16lx] ", psw);
1085 #endif
1086
1087 #elif defined(X86_64)
1088         long rip;
1089
1090         if (upeek(tcp->pid, 8*RIP, &rip) < 0) {
1091                 PRINTBADPC;
1092                 return;
1093         }
1094         tprintf("[%16lx] ", rip);
1095 #elif defined(IA64)
1096         long ip;
1097
1098         if (upeek(tcp->pid, PT_B0, &ip) < 0) {
1099                 PRINTBADPC;
1100                 return;
1101         }
1102         tprintf("[%08lx] ", ip);
1103 #elif defined(POWERPC)
1104         long pc;
1105
1106         if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
1107                 tprintf ("[????????] ");
1108                 return;
1109         }
1110         tprintf("[%08lx] ", pc);
1111 #elif defined(M68k)
1112         long pc;
1113
1114         if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
1115                 tprintf ("[????????] ");
1116                 return;
1117         }
1118         tprintf("[%08lx] ", pc);
1119 #elif defined(ALPHA)
1120         long pc;
1121
1122         if (upeek(tcp->pid, REG_PC, &pc) < 0) {
1123                 tprintf ("[????????????????] ");
1124                 return;
1125         }
1126         tprintf("[%08lx] ", pc);
1127 #elif defined(SPARC) || defined(SPARC64)
1128         struct regs regs;
1129         if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
1130                 PRINTBADPC;
1131                 return;
1132         }
1133         tprintf("[%08lx] ", regs.r_pc);
1134 #elif defined(HPPA)
1135         long pc;
1136
1137         if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0) {
1138                 tprintf ("[????????] ");
1139                 return;
1140         }
1141         tprintf("[%08lx] ", pc);
1142 #elif defined(MIPS)
1143         long pc;
1144
1145         if (upeek(tcp->pid, REG_EPC, &pc) < 0) {
1146                 tprintf ("[????????] ");
1147                 return;
1148         }
1149         tprintf("[%08lx] ", pc);
1150 #elif defined(SH)
1151        long pc;
1152
1153        if (upeek(tcp->pid, 4*REG_PC, &pc) < 0) {
1154                tprintf ("[????????] ");
1155                return;
1156        }
1157        tprintf("[%08lx] ", pc);
1158 #elif defined(SH64)
1159         long pc;
1160
1161         if (upeek(tcp->pid, REG_PC, &pc) < 0) {
1162                 tprintf ("[????????????????] ");
1163                 return;
1164         }
1165         tprintf("[%08lx] ", pc);
1166 #elif defined(ARM)
1167         long pc;
1168
1169         if (upeek(tcp->pid, 4*15, &pc) < 0) {
1170                 PRINTBADPC;
1171                 return;
1172         }
1173         tprintf("[%08lx] ", pc);
1174 #endif /* !architecture */
1175 #endif /* LINUX */
1176
1177 #ifdef SUNOS4
1178         struct regs regs;
1179
1180         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1181                 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
1182                 PRINTBADPC;
1183                 return;
1184         }
1185         tprintf("[%08x] ", regs.r_o7);
1186 #endif /* SUNOS4 */
1187
1188 #ifdef SVR4
1189         /* XXX */
1190         PRINTBADPC;
1191 #endif
1192
1193 #ifdef FREEBSD
1194         struct reg regs;
1195         pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1196         tprintf("[%08x] ", regs.r_eip);
1197 #endif /* FREEBSD */
1198 }
1199
1200 #ifndef USE_PROCFS
1201
1202 #if defined LINUX
1203
1204 #include <sys/syscall.h>
1205 #ifndef CLONE_PTRACE
1206 # define CLONE_PTRACE    0x00002000
1207 #endif
1208
1209 #ifdef IA64
1210
1211 /* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1212    subsystem has them for x86... */
1213 #define SYS_fork        2
1214 #define SYS_vfork       190
1215
1216 typedef unsigned long *arg_setup_state;
1217
1218 static int
1219 arg_setup(struct tcb *tcp, arg_setup_state *state)
1220 {
1221         unsigned long *bsp, cfm, sof, sol;
1222
1223         if (ia32)
1224                 return 0;
1225
1226         if (upeek(tcp->pid, PT_AR_BSP, (long *) &bsp) < 0)
1227                 return -1;
1228         if (upeek(tcp->pid, PT_CFM, (long *) &cfm) < 0)
1229                 return -1;
1230
1231         sof = (cfm >> 0) & 0x7f;
1232         sol = (cfm >> 7) & 0x7f;
1233         bsp = ia64_rse_skip_regs(bsp, -sof + sol);
1234
1235         *state = bsp;
1236         return 0;
1237 }
1238
1239 # define arg_finish_change(tcp, state)  0
1240
1241 #ifdef SYS_fork
1242 static int
1243 get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1244 {
1245         int ret;
1246
1247         if (ia32)
1248                 ret = upeek (tcp->pid, PT_R11, valp);
1249         else
1250                 ret = umoven (tcp,
1251                               (unsigned long) ia64_rse_skip_regs(*state, 0),
1252                               sizeof(long), (void *) valp);
1253         return ret;
1254 }
1255
1256 static int
1257 get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1258 {
1259         int ret;
1260
1261         if (ia32)
1262                 ret = upeek (tcp->pid, PT_R9, valp);
1263         else
1264                 ret = umoven (tcp,
1265                               (unsigned long) ia64_rse_skip_regs(*state, 1),
1266                               sizeof(long), (void *) valp);
1267         return ret;
1268 }
1269 #endif
1270
1271 static int
1272 set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1273 {
1274         int req = PTRACE_POKEDATA;
1275         void *ap;
1276
1277         if (ia32) {
1278                 ap = (void *) (intptr_t) PT_R11;         /* r11 == EBX */
1279                 req = PTRACE_POKEUSER;
1280         } else
1281                 ap = ia64_rse_skip_regs(*state, 0);
1282         errno = 0;
1283         ptrace(req, tcp->pid, ap, val);
1284         return errno ? -1 : 0;
1285 }
1286
1287 static int
1288 set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1289 {
1290         int req = PTRACE_POKEDATA;
1291         void *ap;
1292
1293         if (ia32) {
1294                 ap = (void *) (intptr_t) PT_R9;         /* r9 == ECX */
1295                 req = PTRACE_POKEUSER;
1296         } else
1297                 ap = ia64_rse_skip_regs(*state, 1);
1298         errno = 0;
1299         ptrace(req, tcp->pid, ap, val);
1300         return errno ? -1 : 0;
1301 }
1302
1303 #elif defined (SPARC) || defined (SPARC64)
1304
1305 typedef struct regs arg_setup_state;
1306
1307 # define arg_setup(tcp, state) \
1308   (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
1309 # define arg_finish_change(tcp, state) \
1310   (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
1311
1312 # define get_arg0(tcp, state, valp) (*(valp) = (state)->r_o0, 0)
1313 # define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0)
1314 # define set_arg0(tcp, state, val) ((state)->r_o0 = (val), 0)
1315 # define set_arg1(tcp, state, val) ((state)->r_o1 = (val), 0)
1316 # define restore_arg0(tcp, state, val) 0
1317
1318 #else
1319
1320 # if defined S390 || defined S390X
1321 /* Note: this is only true for the `clone' system call, which handles
1322    arguments specially.  We could as well say that its first two arguments
1323    are swapped relative to other architectures, but that would just be
1324    another #ifdef in the calls.  */
1325 #  define arg0_offset   PT_GPR3
1326 #  define arg1_offset   PT_ORIGGPR2
1327 #  define restore_arg0(tcp, state, val) ((void) (state), 0)
1328 #  define restore_arg1(tcp, state, val) ((void) (state), 0)
1329 #  define arg0_index    1
1330 #  define arg1_index    0
1331 # elif defined (ALPHA) || defined (MIPS)
1332 #  define arg0_offset   REG_A0
1333 #  define arg1_offset   (REG_A0+1)
1334 # elif defined (POWERPC)
1335 #  define arg0_offset   (sizeof(unsigned long)*PT_R3)
1336 #  define arg1_offset   (sizeof(unsigned long)*PT_R4)
1337 #  define restore_arg0(tcp, state, val) ((void) (state), 0)
1338 # elif defined (HPPA)
1339 #  define arg0_offset    PT_GR26
1340 #  define arg1_offset    (PT_GR26-4)
1341 # elif defined (X86_64)
1342 #  define arg0_offset   ((long)(8*(current_personality ? RBX : RDI)))
1343 #  define arg1_offset   ((long)(8*(current_personality ? RCX : RSI)))
1344 # elif defined (SH)
1345 #  define arg0_offset   (4*(REG_REG0+4))
1346 #  define arg1_offset   (4*(REG_REG0+5))
1347 # elif defined (SH64)
1348    /* ABI defines arg0 & 1 in r2 & r3 */
1349 #  define arg0_offset   (REG_OFFSET+16)
1350 #  define arg1_offset   (REG_OFFSET+24)
1351 #  define restore_arg0(tcp, state, val) 0
1352 # else
1353 #  define arg0_offset   0
1354 #  define arg1_offset   4
1355 #  if defined ARM
1356 #   define restore_arg0(tcp, state, val) 0
1357 #  endif
1358 # endif
1359
1360 typedef int arg_setup_state;
1361
1362 # define arg_setup(tcp, state) (0)
1363 # define arg_finish_change(tcp, state)  0
1364 # define get_arg0(tcp, cookie, valp) \
1365   (upeek ((tcp)->pid, arg0_offset, (valp)))
1366 # define get_arg1(tcp, cookie, valp) \
1367   (upeek ((tcp)->pid, arg1_offset, (valp)))
1368
1369 static int
1370 set_arg0 (struct tcb *tcp, void *cookie, long val)
1371 {
1372         return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
1373 }
1374
1375 static int
1376 set_arg1 (struct tcb *tcp, void *cookie, long val)
1377 {
1378         return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
1379 }
1380
1381 #endif
1382
1383 #ifndef restore_arg0
1384 # define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1385 #endif
1386 #ifndef restore_arg1
1387 # define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1388 #endif
1389
1390 #ifndef arg0_index
1391 # define arg0_index 0
1392 # define arg1_index 1
1393 #endif
1394
1395 int
1396 setbpt(tcp)
1397 struct tcb *tcp;
1398 {
1399         extern int change_syscall(struct tcb *, int);
1400         arg_setup_state state;
1401
1402         if (tcp->flags & TCB_BPTSET) {
1403                 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1404                 return -1;
1405         }
1406
1407         switch (tcp->scno) {
1408 #ifdef SYS_vfork
1409         case SYS_vfork:
1410 #endif
1411 #ifdef SYS_fork
1412         case SYS_fork:
1413 #endif
1414 #if defined SYS_fork || defined SYS_vfork
1415                 if (arg_setup (tcp, &state) < 0
1416                     || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1417                     || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
1418                     || change_syscall(tcp, SYS_clone) < 0
1419                     || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1420                     || set_arg1 (tcp, &state, 0) < 0
1421                     || arg_finish_change (tcp, &state) < 0)
1422                         return -1;
1423                 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1424                 tcp->u_arg[arg1_index] = 0;
1425                 tcp->flags |= TCB_BPTSET;
1426                 return 0;
1427 #endif
1428
1429         case SYS_clone:
1430 #ifdef SYS_clone2
1431         case SYS_clone2:
1432 #endif
1433                 if ((tcp->u_arg[arg0_index] & CLONE_PTRACE) == 0
1434                     && (arg_setup (tcp, &state) < 0
1435                         || set_arg0 (tcp, &state,
1436                                      tcp->u_arg[arg0_index] | CLONE_PTRACE) < 0
1437                         || arg_finish_change (tcp, &state) < 0))
1438                         return -1;
1439                 tcp->flags |= TCB_BPTSET;
1440                 tcp->inst[0] = tcp->u_arg[arg0_index];
1441                 tcp->inst[1] = tcp->u_arg[arg1_index];
1442                 return 0;
1443
1444         default:
1445                 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1446                         tcp->scno, tcp->pid);
1447                 break;
1448         }
1449
1450         return -1;
1451 }
1452
1453 int
1454 clearbpt(tcp)
1455 struct tcb *tcp;
1456 {
1457         arg_setup_state state;
1458         if (arg_setup (tcp, &state) < 0
1459             || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1460             || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
1461             || arg_finish_change (tcp, &state))
1462                 return -1;
1463         tcp->flags &= ~TCB_BPTSET;
1464         return 0;
1465 }
1466
1467 #else
1468
1469 int
1470 setbpt(tcp)
1471 struct tcb *tcp;
1472 {
1473
1474 #ifdef LINUX
1475 #if defined (SPARC) || defined (SPARC64)
1476         /* We simply use the SunOS breakpoint code. */
1477
1478         struct regs regs;
1479         unsigned long inst;
1480 #define LOOPA   0x30800000      /* ba,a 0 */
1481
1482         if (tcp->flags & TCB_BPTSET) {
1483                 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1484                 return -1;
1485         }
1486         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1487                 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1488                 return -1;
1489         }
1490         tcp->baddr = regs.r_o7 + 8;
1491         errno = 0;
1492         tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1493         if(errno) {
1494                 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1495                 return -1;
1496         }
1497
1498         /*
1499          * XXX - BRUTAL MODE ON
1500          * We cannot set a real BPT in the child, since it will not be
1501          * traced at the moment it will reach the trap and would probably
1502          * die with a core dump.
1503          * Thus, we are force our way in by taking out two instructions
1504          * and insert an eternal loop instead, in expectance of the SIGSTOP
1505          * generated by out PTRACE_ATTACH.
1506          * Of cause, if we evaporate ourselves in the middle of all this...
1507          */
1508         errno = 0;
1509         inst = LOOPA;
1510 #if defined (SPARC64)
1511         inst <<= 32;
1512         inst |= (tcp->inst[0] & 0xffffffffUL);
1513 #endif
1514         ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, inst);
1515         if(errno) {
1516                 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1517                 return -1;
1518         }
1519         tcp->flags |= TCB_BPTSET;
1520
1521 #else /* !SPARC && !SPARC64 */
1522 #ifdef IA64
1523         if (ia32) {
1524 #               define LOOP     0x0000feeb
1525                 if (tcp->flags & TCB_BPTSET) {
1526                         fprintf(stderr, "PANIC: bpt already set in pid %u\n",
1527                                 tcp->pid);
1528                         return -1;
1529                 }
1530                 if (upeek(tcp->pid, PT_CR_IIP, &tcp->baddr) < 0)
1531                         return -1;
1532                 if (debug)
1533                         fprintf(stderr, "[%d] setting bpt at %lx\n",
1534                                 tcp->pid, tcp->baddr);
1535                 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid,
1536                                       (char *) tcp->baddr, 0);
1537                 if (errno) {
1538                         perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1539                         return -1;
1540                 }
1541                 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1542                 if (errno) {
1543                         perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1544                         return -1;
1545                 }
1546                 tcp->flags |= TCB_BPTSET;
1547         } else {
1548                 /*
1549                  * Our strategy here is to replace the bundle that
1550                  * contained the clone() syscall with a bundle of the
1551                  * form:
1552                  *
1553                  *      { 1: br 1b; br 1b; br 1b }
1554                  *
1555                  * This ensures that the newly forked child will loop
1556                  * endlessly until we've got a chance to attach to it.
1557                  */
1558 #               define LOOP0    0x0000100000000017
1559 #               define LOOP1    0x4000000000200000
1560                 unsigned long addr, ipsr;
1561                 pid_t pid;
1562
1563                 pid = tcp->pid;
1564                 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1565                         return -1;
1566                 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1567                         return -1;
1568                 /* store "ri" in low two bits */
1569                 tcp->baddr = addr | ((ipsr >> 41) & 0x3);
1570
1571                 errno = 0;
1572                 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0,
1573                                       0);
1574                 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8,
1575                                       0);
1576                 if (errno) {
1577                         perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1578                         return -1;
1579                 }
1580
1581                 errno = 0;
1582                 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1583                 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1584                 if (errno) {
1585                         perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1586                         return -1;
1587                 }
1588                 tcp->flags |= TCB_BPTSET;
1589         }
1590 #else /* !IA64 */
1591
1592 #if defined (I386) || defined(X86_64)
1593 #define LOOP    0x0000feeb
1594 #elif defined (M68K)
1595 #define LOOP    0x60fe0000
1596 #elif defined (ALPHA)
1597 #define LOOP    0xc3ffffff
1598 #elif defined (POWERPC)
1599 #define LOOP    0x48000000
1600 #elif defined(ARM)
1601 #define LOOP    0xEAFFFFFE
1602 #elif defined(MIPS)
1603 #define LOOP    0x1000ffff
1604 #elif defined(S390)
1605 #define LOOP    0xa7f40000      /* BRC 15,0 */
1606 #elif defined(S390X)
1607 #define LOOP   0xa7f4000000000000UL /* BRC 15,0 */
1608 #elif defined(HPPA)
1609 #define LOOP    0xe81f1ff7      /* b,l,n <loc>,r0 */
1610 #elif defined(SH)
1611 #ifdef __LITTLE_ENDIAN__
1612 #define LOOP   0x0000affe
1613 #else
1614 #define LOOP   0xfeaf0000
1615 #endif
1616 #else
1617 #error unknown architecture
1618 #endif
1619
1620         if (tcp->flags & TCB_BPTSET) {
1621                 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1622                 return -1;
1623         }
1624 #if defined (I386)
1625         if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1626                 return -1;
1627 #elif defined (X86_64)
1628         if (upeek(tcp->pid, 8*RIP, &tcp->baddr) < 0)
1629                 return -1;
1630 #elif defined (M68K)
1631         if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1632           return -1;
1633 #elif defined (ALPHA)
1634         return -1;
1635 #elif defined (ARM)
1636         return -1;
1637 #elif defined (MIPS)
1638         return -1;              /* FIXME: I do not know what i do - Flo */
1639 #elif defined (POWERPC)
1640         if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &tcp->baddr) < 0)
1641                 return -1;
1642 #elif defined(S390) || defined(S390X)
1643         if (upeek(tcp->pid,PT_PSWADDR, &tcp->baddr) < 0)
1644                 return -1;
1645 #elif defined(HPPA)
1646         if (upeek(tcp->pid, PT_IAOQ0, &tcp->baddr) < 0)
1647                 return -1;
1648         tcp->baddr &= ~0x03;
1649 #elif defined(SH)
1650        if (upeek(tcp->pid, 4*REG_PC, &tcp->baddr) < 0)
1651                return -1;
1652 #else
1653 #error unknown architecture
1654 #endif
1655         if (debug)
1656                 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1657         tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1658         if (errno) {
1659                 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1660                 return -1;
1661         }
1662         ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1663         if (errno) {
1664                 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1665                 return -1;
1666         }
1667         tcp->flags |= TCB_BPTSET;
1668
1669 #endif /* !IA64 */
1670 #endif /* SPARC || SPARC64 */
1671 #endif /* LINUX */
1672
1673 #ifdef SUNOS4
1674 #ifdef SPARC    /* This code is slightly sparc specific */
1675
1676         struct regs regs;
1677 #define BPT     0x91d02001      /* ta   1 */
1678 #define LOOP    0x10800000      /* ba   0 */
1679 #define LOOPA   0x30800000      /* ba,a 0 */
1680 #define NOP     0x01000000
1681 #if LOOPA
1682         static int loopdeloop[1] = {LOOPA};
1683 #else
1684         static int loopdeloop[2] = {LOOP, NOP};
1685 #endif
1686
1687         if (tcp->flags & TCB_BPTSET) {
1688                 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1689                 return -1;
1690         }
1691         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1692                 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1693                 return -1;
1694         }
1695         tcp->baddr = regs.r_o7 + 8;
1696         if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1697                                 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1698                 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1699                 return -1;
1700         }
1701
1702         /*
1703          * XXX - BRUTAL MODE ON
1704          * We cannot set a real BPT in the child, since it will not be
1705          * traced at the moment it will reach the trap and would probably
1706          * die with a core dump.
1707          * Thus, we are force our way in by taking out two instructions
1708          * and insert an eternal loop in stead, in expectance of the SIGSTOP
1709          * generated by out PTRACE_ATTACH.
1710          * Of cause, if we evaporate ourselves in the middle of all this...
1711          */
1712         if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1713                         sizeof loopdeloop, (char *) loopdeloop) < 0) {
1714                 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1715                 return -1;
1716         }
1717         tcp->flags |= TCB_BPTSET;
1718
1719 #endif /* SPARC */
1720 #endif /* SUNOS4 */
1721
1722         return 0;
1723 }
1724
1725 int
1726 clearbpt(tcp)
1727 struct tcb *tcp;
1728 {
1729
1730 #ifdef LINUX
1731 #if defined(I386) || defined(X86_64)
1732         long eip;
1733 #elif defined(POWERPC)
1734         long pc;
1735 #elif defined(M68K)
1736         long pc;
1737 #elif defined(ALPHA)
1738         long pc;
1739 #elif defined(HPPA)
1740         long iaoq;
1741 #elif defined(SH)
1742        long pc;
1743 #endif /* architecture */
1744
1745 #if defined (SPARC) || defined (SPARC64)
1746         /* Again, we borrow the SunOS breakpoint code. */
1747         if (!(tcp->flags & TCB_BPTSET)) {
1748                 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1749                 return -1;
1750         }
1751         errno = 0;
1752         ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1753         if(errno) {
1754                 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1755                 return -1;
1756         }
1757         tcp->flags &= ~TCB_BPTSET;
1758 #elif defined(IA64)
1759         if (ia32) {
1760                 unsigned long addr;
1761
1762                 if (debug)
1763                         fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1764                 if (!(tcp->flags & TCB_BPTSET)) {
1765                         fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1766                         return -1;
1767                 }
1768                 errno = 0;
1769                 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1770                 if (errno) {
1771                         perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1772                         return -1;
1773                 }
1774                 tcp->flags &= ~TCB_BPTSET;
1775
1776                 if (upeek(tcp->pid, PT_CR_IIP, &addr) < 0)
1777                         return -1;
1778                 if (addr != tcp->baddr) {
1779                         /* The breakpoint has not been reached yet.  */
1780                         if (debug)
1781                                 fprintf(stderr,
1782                                         "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1783                                                 addr, tcp->baddr);
1784                         return 0;
1785                 }
1786         } else {
1787                 unsigned long addr, ipsr;
1788                 pid_t pid;
1789
1790                 pid = tcp->pid;
1791
1792                 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1793                         return -1;
1794                 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1795                         return -1;
1796
1797                 /* restore original bundle: */
1798                 errno = 0;
1799                 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
1800                 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
1801                 if (errno) {
1802                         perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
1803                         return -1;
1804                 }
1805
1806                 /* restore original "ri" in ipsr: */
1807                 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
1808                 errno = 0;
1809                 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
1810                 if (errno) {
1811                         perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
1812                         return -1;
1813                 }
1814
1815                 tcp->flags &= ~TCB_BPTSET;
1816
1817                 if (addr != (tcp->baddr & ~0x3)) {
1818                         /* the breakpoint has not been reached yet.  */
1819                         if (debug)
1820                                 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1821                                         addr, tcp->baddr);
1822                         return 0;
1823                 }
1824         }
1825 #else /* !IA64  && !SPARC && !SPARC64 */
1826
1827         if (debug)
1828                 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1829         if (!(tcp->flags & TCB_BPTSET)) {
1830                 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1831                 return -1;
1832         }
1833         errno = 0;
1834         ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1835         if (errno) {
1836                 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1837                 return -1;
1838         }
1839         tcp->flags &= ~TCB_BPTSET;
1840
1841 #ifdef I386
1842         if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1843                 return -1;
1844         if (eip != tcp->baddr) {
1845                 /* The breakpoint has not been reached yet.  */
1846                 if (debug)
1847                         fprintf(stderr,
1848                                 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1849                                         eip, tcp->baddr);
1850                 return 0;
1851         }
1852 #elif defined(X86_64)
1853         if (upeek(tcp->pid, 8*RIP, &eip) < 0)
1854                 return -1;
1855         if (eip != tcp->baddr) {
1856                 /* The breakpoint has not been reached yet.  */
1857                 if (debug)
1858                         fprintf(stderr,
1859                                 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1860                                         eip, tcp->baddr);
1861                 return 0;
1862         }
1863 #elif defined(POWERPC)
1864         if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0)
1865                 return -1;
1866         if (pc != tcp->baddr) {
1867                 /* The breakpoint has not been reached yet.  */
1868                 if (debug)
1869                         fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1870                                 pc, tcp->baddr);
1871                 return 0;
1872         }
1873 #elif defined(M68K)
1874         if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1875                 return -1;
1876         if (pc != tcp->baddr) {
1877                 /* The breakpoint has not been reached yet.  */
1878                 if (debug)
1879                         fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1880                                 pc, tcp->baddr);
1881                 return 0;
1882         }
1883 #elif defined(ALPHA)
1884         if (upeek(tcp->pid, REG_PC, &pc) < 0)
1885                 return -1;
1886         if (pc != tcp->baddr) {
1887                 /* The breakpoint has not been reached yet.  */
1888                 if (debug)
1889                         fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1890                                 pc, tcp->baddr);
1891                 return 0;
1892         }
1893 #elif defined(HPPA)
1894         if (upeek(tcp->pid, PT_IAOQ0, &iaoq) < 0)
1895                 return -1;
1896         iaoq &= ~0x03;
1897         if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
1898                 /* The breakpoint has not been reached yet.  */
1899                 if (debug)
1900                         fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
1901                                 iaoq, tcp->baddr);
1902                 return 0;
1903         }
1904         iaoq = tcp->baddr | 3;
1905         /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
1906          * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
1907          * has no significant effect.
1908          */
1909         ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
1910         ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
1911 #elif defined(SH)
1912        if (upeek(tcp->pid, 4*REG_PC, &pc) < 0)
1913                return -1;
1914         if (pc != tcp->baddr) {
1915                 /* The breakpoint has not been reached yet.  */
1916                 if (debug)
1917                         fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1918                                 pc, tcp->baddr);
1919                 return 0;
1920         }
1921
1922 #endif /* arch */
1923 #endif /* !SPARC && !SPARC64 && !IA64 */
1924 #endif /* LINUX */
1925
1926 #ifdef SUNOS4
1927 #ifdef SPARC
1928
1929 #if !LOOPA
1930         struct regs regs;
1931 #endif
1932
1933         if (!(tcp->flags & TCB_BPTSET)) {
1934                 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1935                 return -1;
1936         }
1937         if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1938                                 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1939                 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1940                 return -1;
1941         }
1942         tcp->flags &= ~TCB_BPTSET;
1943
1944 #if !LOOPA
1945         /*
1946          * Since we don't have a single instruction breakpoint, we may have
1947          * to adjust the program counter after removing the our `breakpoint'.
1948          */
1949         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1950                 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1951                 return -1;
1952         }
1953         if ((regs.r_pc < tcp->baddr) ||
1954                                 (regs.r_pc > tcp->baddr + 4)) {
1955                 /* The breakpoint has not been reached yet */
1956                 if (debug)
1957                         fprintf(stderr,
1958                                 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1959                                         regs.r_pc, tcp->parent->baddr);
1960                 return 0;
1961         }
1962         if (regs.r_pc != tcp->baddr)
1963                 if (debug)
1964                         fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1965                                 regs.r_pc, tcp->baddr);
1966
1967         regs.r_pc = tcp->baddr;
1968         if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1969                 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1970                 return -1;
1971         }
1972 #endif /* LOOPA */
1973 #endif /* SPARC */
1974 #endif /* SUNOS4 */
1975
1976         return 0;
1977 }
1978
1979 #endif
1980
1981 #endif /* !USE_PROCFS */
1982
1983 #ifdef SUNOS4
1984
1985 static int
1986 getex(pid, hdr)
1987 int pid;
1988 struct exec *hdr;
1989 {
1990         int n;
1991
1992         for (n = 0; n < sizeof *hdr; n += 4) {
1993                 long res;
1994                 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
1995                         return -1;
1996                 memcpy(((char *) hdr) + n, &res, 4);
1997         }
1998         if (debug) {
1999                 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
2000                         hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
2001                 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
2002                         hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
2003         }
2004         return 0;
2005 }
2006
2007 int
2008 fixvfork(tcp)
2009 struct tcb *tcp;
2010 {
2011         int pid = tcp->pid;
2012         /*
2013          * Change `vfork' in a freshly exec'ed dynamically linked
2014          * executable's (internal) symbol table to plain old `fork'
2015          */
2016
2017         struct exec hdr;
2018         struct link_dynamic dyn;
2019         struct link_dynamic_2 ld;
2020         char *strtab, *cp;
2021
2022         if (getex(pid, &hdr) < 0)
2023                 return -1;
2024         if (!hdr.a_dynamic)
2025                 return -1;
2026
2027         if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
2028                 fprintf(stderr, "Cannot read DYNAMIC\n");
2029                 return -1;
2030         }
2031         if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
2032                 fprintf(stderr, "Cannot read link_dynamic_2\n");
2033                 return -1;
2034         }
2035         if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
2036                 fprintf(stderr, "out of memory\n");
2037                 return -1;
2038         }
2039         if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
2040                                         (int)ld.ld_symb_size, strtab) < 0)
2041                 goto err;
2042
2043 #if 0
2044         for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2045                 fprintf(stderr, "[symbol: %s]\n", cp);
2046                 cp += strlen(cp)+1;
2047         }
2048         return 0;
2049 #endif
2050         for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2051                 if (strcmp(cp, "_vfork") == 0) {
2052                         if (debug)
2053                                 fprintf(stderr, "fixvfork: FOUND _vfork\n");
2054                         strcpy(cp, "_fork");
2055                         break;
2056                 }
2057                 cp += strlen(cp)+1;
2058         }
2059         if (cp < strtab + ld.ld_symb_size)
2060                 /*
2061                  * Write entire symbol table back to avoid
2062                  * memory alignment bugs in ptrace
2063                  */
2064                 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
2065                                         (int)ld.ld_symb_size, strtab) < 0)
2066                         goto err;
2067
2068         free(strtab);
2069         return 0;
2070
2071 err:
2072         free(strtab);
2073         return -1;
2074 }
2075
2076 #endif /* SUNOS4 */