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