]> granicus.if.org Git - strace/blob - util.c
529114241e5ca09a2c06cda4ad946b26b0ea9e39
[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         int fd = tcp->pfd_as;
636 #else
637         int fd = tcp->pfd;
638 #endif
639         lseek(fd, addr, SEEK_SET);
640         if (read(fd, laddr, len) == -1)
641                 return -1;
642 #endif /* USE_PROCFS */
643
644         return 0;
645 }
646
647 /*
648  * like `umove' but make the additional effort of looking
649  * for a terminating zero byte.
650  */
651 int
652 umovestr(tcp, addr, len, laddr)
653 struct tcb *tcp;
654 long addr;
655 int len;
656 char *laddr;
657 {
658 #ifdef USE_PROCFS
659 #ifdef HAVE_MP_PROCFS
660         int fd = tcp->pfd_as;
661 #else
662         int fd = tcp->pfd;
663 #endif
664         /* Some systems (e.g. FreeBSD) can be upset if we read off the
665            end of valid memory,  avoid this by trying to read up
666            to page boundaries.  But we don't know what a page is (and
667            getpagesize(2) (if it exists) doesn't necessarily return
668            hardware page size).  Assume all pages >= 1024 (a-historical
669            I know) */
670
671         int page = 1024;        /* How to find this? */
672         int move = page - (addr & (page - 1));
673         int left = len;
674
675         lseek(fd, addr, SEEK_SET);
676
677         while (left) {
678                 if (move > left) move = left;
679                 if ((move = read(fd, laddr, move)) == -1)
680                         return left != len ? 0 : -1;
681                 if (memchr (laddr, 0, move)) break;
682                 left -= move;
683                 laddr += move;
684                 addr += move;
685                 move = page;
686         }
687 #else /* !USE_PROCFS */
688         int started = 0;
689         int pid = tcp->pid;
690         int i, n, m;
691         union {
692                 long val;
693                 char x[sizeof(long)];
694         } u;
695
696         if (addr & (sizeof(long) - 1)) {
697                 /* addr not a multiple of sizeof(long) */
698                 n = addr - (addr & -sizeof(long)); /* residue */
699                 addr &= -sizeof(long); /* residue */
700                 errno = 0;
701                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
702                 if (errno) {
703                         if (started && (errno==EPERM || errno==EIO)) {
704                                 /* Ran into 'end of memory' - stupid "printpath" */
705                                 return 0;
706                         }
707                         perror("umovestr");
708                         return -1;
709                 }
710                 started = 1;
711                 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
712                 while (n & (sizeof(long) - 1))
713                         if (u.x[n++] == '\0')
714                                 return 0;
715                 addr += sizeof(long), laddr += m, len -= m;
716         }
717         while (len) {
718                 errno = 0;
719                 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
720                 if (errno) {
721                         if (started && (errno==EPERM || errno==EIO)) {
722                                 /* Ran into 'end of memory' - stupid "printpath" */
723                                 return 0;
724                         }
725                         perror("umovestr");
726                         return -1;
727                 }
728                 started = 1;
729                 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
730                 for (i = 0; i < sizeof(long); i++)
731                         if (u.x[i] == '\0')
732                                 return 0;
733
734                 addr += sizeof(long), laddr += m, len -= m;
735         }
736 #endif /* !USE_PROCFS */
737         return 0;
738 }
739
740 #ifdef LINUX
741 #ifndef SPARC
742 #define PTRACE_WRITETEXT        101
743 #define PTRACE_WRITEDATA        102
744 #endif /* !SPARC */
745 #endif /* LINUX */
746
747 #ifdef SUNOS4
748
749 static int
750 uload(cmd, pid, addr, len, laddr)
751 int cmd;
752 int pid;
753 long addr;
754 int len;
755 char *laddr;
756 {
757 #if 0
758         int n;
759
760         while (len) {
761                 n = MIN(len, PAGSIZ);
762                 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
763                 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
764                         perror("uload: ptrace(PTRACE_WRITE, ...)");
765                         return -1;
766                 }
767                 len -= n;
768                 addr += n;
769                 laddr += n;
770         }
771 #else
772         int peek, poke;
773         int n, m;
774         union {
775                 long val;
776                 char x[sizeof(long)];
777         } u;
778
779         if (cmd == PTRACE_WRITETEXT) {
780                 peek = PTRACE_PEEKTEXT;
781                 poke = PTRACE_POKETEXT;
782         }
783         else {
784                 peek = PTRACE_PEEKDATA;
785                 poke = PTRACE_POKEDATA;
786         }
787         if (addr & (sizeof(long) - 1)) {
788                 /* addr not a multiple of sizeof(long) */
789                 n = addr - (addr & -sizeof(long)); /* residue */
790                 addr &= -sizeof(long);
791                 errno = 0;
792                 u.val = ptrace(peek, pid, (char *) addr, 0);
793                 if (errno) {
794                         perror("uload: POKE");
795                         return -1;
796                 }
797                 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
798                 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
799                         perror("uload: POKE");
800                         return -1;
801                 }
802                 addr += sizeof(long), laddr += m, len -= m;
803         }
804         while (len) {
805                 if (len < sizeof(long))
806                         u.val = ptrace(peek, pid, (char *) addr, 0);
807                 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
808                 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
809                         perror("uload: POKE");
810                         return -1;
811                 }
812                 addr += sizeof(long), laddr += m, len -= m;
813         }
814 #endif
815         return 0;
816 }
817
818 int
819 tload(pid, addr, len, laddr)
820 int pid;
821 int addr, len;
822 char *laddr;
823 {
824         return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
825 }
826
827 int
828 dload(pid, addr, len, laddr)
829 int pid;
830 int addr;
831 int len;
832 char *laddr;
833 {
834         return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
835 }
836
837 #endif /* SUNOS4 */
838
839 #ifndef USE_PROCFS
840
841 int
842 upeek(pid, off, res)
843 int pid;
844 long off;
845 long *res;
846 {
847         long val;
848
849 #ifdef SUNOS4_KERNEL_ARCH_KLUDGE
850         {
851                 static int is_sun4m = -1;
852                 struct utsname name;
853
854                 /* Round up the usual suspects. */
855                 if (is_sun4m == -1) {
856                         if (uname(&name) < 0) {
857                                 perror("upeek: uname?");
858                                 exit(1);
859                         }
860                         is_sun4m = strcmp(name.machine, "sun4m") == 0;
861                         if (is_sun4m) {
862                                 extern struct xlat struct_user_offsets[];
863                                 struct xlat *x;
864
865                                 for (x = struct_user_offsets; x->str; x++)
866                                         x->val += 1024;
867                         }
868                 }
869                 if (is_sun4m)
870                         off += 1024;
871         }
872 #endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
873         errno = 0;
874         val = ptrace(PTRACE_PEEKUSER, pid, (char *) off, 0);
875         if (val == -1 && errno) {
876                 perror("upeek: ptrace(PTRACE_PEEKUSER, ... )");
877                 return -1;
878         }
879         *res = val;
880         return 0;
881 }
882
883 #endif /* !USE_PROCFS */
884
885 long
886 getpc(tcp)
887 struct tcb *tcp;
888 {
889
890 #ifdef LINUX
891         long pc;
892 #if defined(I386)
893         if (upeek(tcp->pid, 4*EIP, &pc) < 0)
894                 return -1;
895 #elif defined(IA64)
896         if (upeek(tcp->pid, PT_B0, &pc) < 0)
897                 return -1;
898 #elif defined(ARM)
899         if (upeek(tcp->pid, 4*15, &pc) < 0)
900                 return -1;
901 #elif defined(POWERPC)
902         if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
903                 return -1;
904 #elif defined(M68k)
905         if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
906                 return -1;
907 #elif defined(ALPHA)
908         if (upeek(tcp->pid, REG_PC, &pc) < 0)
909                 return -1;
910 #elif defined(MIPS)
911         if (upeek(tcp->pid, REG_EPC, &pc) < 0)
912                 return -1;
913 #elif defined(SPARC)
914         struct regs regs;
915         if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
916                 return -1;
917         pc = regs.r_pc;
918 #elif defined(S390)
919         if(upeek(tcp->pid,PT_PSWADDR,&pc) < 0)
920 #elif defined(HPPA)
921         if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0)
922                 return -1;
923 #endif
924         return pc;
925 #endif /* LINUX */
926
927 #ifdef SUNOS4
928         /*
929          * Return current program counter for `pid'
930          * Assumes PC is never 0xffffffff
931          */
932         struct regs regs;
933
934         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
935                 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
936                 return -1;
937         }
938         return regs.r_pc;
939 #endif /* SUNOS4 */
940
941 #ifdef SVR4
942         /* XXX */
943         return 0;
944 #endif /* SVR4 */
945
946 #ifdef FREEBSD
947         struct reg regs;
948         pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
949         return regs.r_eip;
950 #endif /* FREEBSD */
951 }
952
953 void
954 printcall(tcp)
955 struct tcb *tcp;
956 {
957
958 #ifdef LINUX
959 #ifdef I386
960         long eip;
961
962         if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
963                 tprintf("[????????] ");
964                 return;
965         }
966         tprintf("[%08lx] ", eip);
967 #elif defined(IA62)
968         long ip;
969
970         if (upeek(tcp->pid, PT_B0, &ip) < 0) {
971                 tprintf("[????????] ");
972                 return;
973         }
974         tprintf("[%08lx] ", ip);
975 #elif defined(POWERPC)
976         long pc;
977
978         if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0) {
979                 tprintf ("[????????] ");
980                 return;
981         }
982         tprintf("[%08lx] ", pc);
983 #elif defined(M68k)
984         long pc;
985
986         if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
987                 tprintf ("[????????] ");
988                 return;
989         }
990         tprintf("[%08lx] ", pc);
991 #elif defined(ALPHA)
992         long pc;
993
994         if (upeek(tcp->pid, REG_PC, &pc) < 0) {
995                 tprintf ("[????????] ");
996                 return;
997         }
998         tprintf("[%08lx] ", pc);
999 #elif defined(SPARC)
1000         struct regs regs;
1001         if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
1002                 tprintf("[????????] ");
1003                 return;
1004         }
1005         tprintf("[%08lx] ", regs.r_pc);
1006 #elif defined(HPPA)
1007         long pc;
1008
1009         if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0) {
1010                 tprintf ("[????????] ");
1011                 return;
1012         }
1013         tprintf("[%08lx] ", pc);
1014 #elif defined(MIPS)
1015         long pc;
1016
1017         if (upeek(tcp->pid, REG_EPC, &pc) < 0) {
1018                 tprintf ("[????????] ");
1019                 return;
1020         }
1021         tprintf("[%08lx] ", pc);
1022 #endif /* !architecture */
1023 #endif /* LINUX */
1024
1025 #ifdef SUNOS4
1026         struct regs regs;
1027
1028         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1029                 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
1030                 tprintf("[????????] ");
1031                 return;
1032         }
1033         tprintf("[%08x] ", regs.r_o7);
1034 #endif /* SUNOS4 */
1035
1036 #ifdef SVR4
1037         /* XXX */
1038         tprintf("[????????] ");
1039 #endif
1040
1041 #ifdef FREEBSD
1042         struct reg regs;
1043         pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1044         tprintf("[%08x] ", regs.r_eip);
1045 #endif /* FREEBSD */
1046 }
1047
1048 #ifndef USE_PROCFS
1049
1050 int
1051 setbpt(tcp)
1052 struct tcb *tcp;
1053 {
1054
1055 #ifdef LINUX
1056 #ifdef SPARC
1057         /* We simply use the SunOS breakpoint code. */
1058
1059         struct regs regs;
1060 #define LOOPA   0x30800000      /* ba,a 0 */
1061
1062         if (tcp->flags & TCB_BPTSET) {
1063                 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1064                 return -1;
1065         }
1066         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1067                 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1068                 return -1;
1069         }
1070         tcp->baddr = regs.r_o7 + 8;
1071         errno = 0;
1072         tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1073         if(errno) {
1074                 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1075                 return -1;
1076         }
1077
1078         /*
1079          * XXX - BRUTAL MODE ON
1080          * We cannot set a real BPT in the child, since it will not be
1081          * traced at the moment it will reach the trap and would probably
1082          * die with a core dump.
1083          * Thus, we are force our way in by taking out two instructions
1084          * and insert an eternal loop instead, in expectance of the SIGSTOP
1085          * generated by out PTRACE_ATTACH.
1086          * Of cause, if we evaporate ourselves in the middle of all this...
1087          */
1088         errno = 0;
1089         ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOPA);
1090         if(errno) {
1091                 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1092                 return -1;
1093         }
1094         tcp->flags |= TCB_BPTSET;
1095
1096 #else /* !SPARC */
1097 #ifdef IA64
1098         /*
1099          * Our strategy here is to replace the bundle that contained
1100          * the clone() syscall with a bundle of the form:
1101          *
1102          *      { 1: br 1b; br 1b; br 1b }
1103          *
1104          * This ensures that the newly forked child will loop
1105          * endlessly until we've got a chance to attach to it.
1106          */
1107         {
1108 #               define LOOP0    0x0000100000000017
1109 #               define LOOP1    0x4000000000200000
1110                 unsigned long addr, ipsr;
1111                 pid_t pid;
1112
1113                 pid = tcp->pid;
1114                 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1115                         return -1;
1116                 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1117                         return -1;
1118                 tcp->baddr = addr | ((ipsr >> 41) & 0x3);       /* store "ri" in low two bits */
1119
1120                 errno = 0;
1121                 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0, 0);
1122                 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8, 0);
1123                 if (errno) {
1124                         perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1125                         return -1;
1126                 }
1127
1128                 errno = 0;
1129                 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1130                 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1131                 if (errno) {
1132                         perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1133                         return -1;
1134                 }
1135                 tcp->flags |= TCB_BPTSET;
1136         }
1137 #else /* !IA64 */
1138
1139 #if defined (I386)
1140 #define LOOP    0x0000feeb
1141 #elif defined (M68K)
1142 #define LOOP    0x60fe0000
1143 #elif defined (ALPHA)
1144 #define LOOP    0xc3ffffff
1145 #elif defined (POWERPC)
1146 #define LOOP    0x0000feeb
1147 #elif defined(ARM)
1148 #define LOOP    0xEAFFFFFE
1149 #elif defined(MIPS)
1150 #define LOOP    0x1000ffff
1151 #elif defined(S390)
1152 #define LOOP    0xa7f40000      /* BRC 15,0 */
1153 #elif defined(HPPA)
1154 #define LOOP    0xe81f1ff7      /* b,l,n <loc>,r0 */
1155 #else
1156 #error unknown architecture
1157 #endif
1158
1159         if (tcp->flags & TCB_BPTSET) {
1160                 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1161                 return -1;
1162         }
1163 #if defined (I386)
1164         if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1165                 return -1;
1166 #elif defined (M68K)
1167         if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1168           return -1;
1169 #elif defined (ALPHA)
1170         return -1;
1171 #elif defined (ARM)
1172         return -1;
1173 #elif defined (MIPS)
1174         return -1;              /* FIXME: I do not know what i do - Flo */
1175 #elif defined (POWERPC)
1176         if (upeek(tcp->pid, 4*PT_NIP, &tcp->baddr) < 0)
1177                 return -1;
1178 #elif defined(S390)
1179         if (upeek(tcp->pid,PT_PSWADDR, &tcp->baddr) < 0)
1180                 return -1;
1181 #elif defined(HPPA)
1182         if (upeek(tcp->pid, PT_IAOQ0, &tcp->baddr) < 0)
1183                 return -1;
1184         tcp->baddr &= ~0x03;
1185 #else
1186 #error unknown architecture
1187 #endif
1188         if (debug)
1189                 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1190         tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1191         if (errno) {
1192                 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1193                 return -1;
1194         }
1195         ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1196         if (errno) {
1197                 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1198                 return -1;
1199         }
1200         tcp->flags |= TCB_BPTSET;
1201
1202 #endif /* !IA64 */
1203 #endif /* SPARC */
1204 #endif /* LINUX */
1205
1206 #ifdef SUNOS4
1207 #ifdef SPARC    /* This code is slightly sparc specific */
1208
1209         struct regs regs;
1210 #define BPT     0x91d02001      /* ta   1 */
1211 #define LOOP    0x10800000      /* ba   0 */
1212 #define LOOPA   0x30800000      /* ba,a 0 */
1213 #define NOP     0x01000000
1214 #if LOOPA
1215         static int loopdeloop[1] = {LOOPA};
1216 #else
1217         static int loopdeloop[2] = {LOOP, NOP};
1218 #endif
1219
1220         if (tcp->flags & TCB_BPTSET) {
1221                 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1222                 return -1;
1223         }
1224         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1225                 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1226                 return -1;
1227         }
1228         tcp->baddr = regs.r_o7 + 8;
1229         if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1230                                 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1231                 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1232                 return -1;
1233         }
1234
1235         /*
1236          * XXX - BRUTAL MODE ON
1237          * We cannot set a real BPT in the child, since it will not be
1238          * traced at the moment it will reach the trap and would probably
1239          * die with a core dump.
1240          * Thus, we are force our way in by taking out two instructions
1241          * and insert an eternal loop in stead, in expectance of the SIGSTOP
1242          * generated by out PTRACE_ATTACH.
1243          * Of cause, if we evaporate ourselves in the middle of all this...
1244          */
1245         if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1246                         sizeof loopdeloop, (char *) loopdeloop) < 0) {
1247                 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1248                 return -1;
1249         }
1250         tcp->flags |= TCB_BPTSET;
1251
1252 #endif /* SPARC */
1253 #endif /* SUNOS4 */
1254
1255         return 0;
1256 }
1257
1258 int
1259 clearbpt(tcp)
1260 struct tcb *tcp;
1261 {
1262
1263 #ifdef LINUX
1264 #if defined(I386)
1265         long eip;
1266 #elif defined(POWERPC)
1267         long pc;
1268 #elif defined(M68K)
1269         long pc;
1270 #elif defined(ALPHA)
1271         long pc;
1272 #elif defined(HPPA)
1273         long iaoq;
1274 #endif /* architecture */
1275
1276 #ifdef SPARC
1277         /* Again, we borrow the SunOS breakpoint code. */
1278         if (!(tcp->flags & TCB_BPTSET)) {
1279                 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1280                 return -1;
1281         }
1282         errno = 0;
1283         ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1284         if(errno) {
1285                 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1286                 return -1;
1287         }
1288         tcp->flags &= ~TCB_BPTSET;
1289 #elif defined(IA64)
1290         {
1291                 unsigned long addr, ipsr;
1292                 pid_t pid;
1293
1294                 pid = tcp->pid;
1295
1296                 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1297                         return -1;
1298                 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1299                         return -1;
1300
1301                 /* restore original bundle: */
1302                 errno = 0;
1303                 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
1304                 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
1305                 if (errno) {
1306                         perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
1307                         return -1;
1308                 }
1309
1310                 /* restore original "ri" in ipsr: */
1311                 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
1312                 errno = 0;
1313                 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
1314                 if (errno) {
1315                         perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
1316                         return -1;
1317                 }
1318
1319                 tcp->flags &= ~TCB_BPTSET;
1320
1321                 if (addr != (tcp->baddr & ~0x3)) {
1322                         /* the breakpoint has not been reached yet.  */
1323                         if (debug)
1324                                 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1325                                         addr, tcp->baddr);
1326                         return 0;
1327                 }
1328         }
1329 #else /* !IA64  && ! SPARC */
1330
1331         if (debug)
1332                 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1333         if (!(tcp->flags & TCB_BPTSET)) {
1334                 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1335                 return -1;
1336         }
1337         errno = 0;
1338         ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1339         if (errno) {
1340                 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1341                 return -1;
1342         }
1343         tcp->flags &= ~TCB_BPTSET;
1344
1345 #ifdef I386
1346         if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1347                 return -1;
1348         if (eip != tcp->baddr) {
1349                 /* The breakpoint has not been reached yet.  */
1350                 if (debug)
1351                         fprintf(stderr,
1352                                 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1353                                         eip, tcp->baddr);
1354                 return 0;
1355         }
1356 #elif defined(POWERPC)
1357         if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
1358                 return -1;
1359         if (pc != tcp->baddr) {
1360                 /* The breakpoint has not been reached yet.  */
1361                 if (debug)
1362                         fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1363                                 pc, tcp->baddr);
1364                 return 0;
1365         }
1366 #elif defined(M68K)
1367         if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1368                 return -1;
1369         if (pc != tcp->baddr) {
1370                 /* The breakpoint has not been reached yet.  */
1371                 if (debug)
1372                         fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1373                                 pc, tcp->baddr);
1374                 return 0;
1375         }
1376 #elif defined(ALPHA)
1377         if (upeek(tcp->pid, REG_PC, &pc) < 0)
1378                 return -1;
1379         if (pc != tcp->baddr) {
1380                 /* The breakpoint has not been reached yet.  */
1381                 if (debug)
1382                         fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1383                                 pc, tcp->baddr);
1384                 return 0;
1385         }
1386 #elif defined(HPPA)
1387         if (upeek(tcp->pid, PT_IAOQ0, &iaoq) < 0)
1388                 return -1;
1389         iaoq &= ~0x03;
1390         if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
1391                 /* The breakpoint has not been reached yet.  */
1392                 if (debug)
1393                         fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
1394                                 iaoq, tcp->baddr);
1395                 return 0;
1396         }
1397         iaoq = tcp->baddr | 3;
1398         /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
1399          * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
1400          * has no significant effect.
1401          */
1402         ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
1403         ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
1404 #endif /* arch */
1405 #endif /* !SPARC && !IA64 */
1406 #endif /* LINUX */
1407
1408 #ifdef SUNOS4
1409 #ifdef SPARC
1410
1411 #if !LOOPA
1412         struct regs regs;
1413 #endif
1414
1415         if (!(tcp->flags & TCB_BPTSET)) {
1416                 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1417                 return -1;
1418         }
1419         if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1420                                 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1421                 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1422                 return -1;
1423         }
1424         tcp->flags &= ~TCB_BPTSET;
1425
1426 #if !LOOPA
1427         /*
1428          * Since we don't have a single instruction breakpoint, we may have
1429          * to adjust the program counter after removing the our `breakpoint'.
1430          */
1431         if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1432                 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1433                 return -1;
1434         }
1435         if ((regs.r_pc < tcp->baddr) ||
1436                                 (regs.r_pc > tcp->baddr + 4)) {
1437                 /* The breakpoint has not been reached yet */
1438                 if (debug)
1439                         fprintf(stderr,
1440                                 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1441                                         regs.r_pc, tcp->parent->baddr);
1442                 return 0;
1443         }
1444         if (regs.r_pc != tcp->baddr)
1445                 if (debug)
1446                         fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1447                                 regs.r_pc, tcp->baddr);
1448
1449         regs.r_pc = tcp->baddr;
1450         if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1451                 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1452                 return -1;
1453         }
1454 #endif /* LOOPA */
1455 #endif /* SPARC */
1456 #endif /* SUNOS4 */
1457
1458         return 0;
1459 }
1460
1461 #endif /* !USE_PROCFS */
1462
1463 #ifdef SUNOS4
1464
1465 static int
1466 getex(pid, hdr)
1467 int pid;
1468 struct exec *hdr;
1469 {
1470         int n;
1471
1472         for (n = 0; n < sizeof *hdr; n += 4) {
1473                 long res;
1474                 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
1475                         return -1;
1476                 memcpy(((char *) hdr) + n, &res, 4);
1477         }
1478         if (debug) {
1479                 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1480                         hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1481                 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1482                         hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1483         }
1484         return 0;
1485 }
1486
1487 int
1488 fixvfork(tcp)
1489 struct tcb *tcp;
1490 {
1491         int pid = tcp->pid;
1492         /*
1493          * Change `vfork' in a freshly exec'ed dynamically linked
1494          * executable's (internal) symbol table to plain old `fork'
1495          */
1496
1497         struct exec hdr;
1498         struct link_dynamic dyn;
1499         struct link_dynamic_2 ld;
1500         char *strtab, *cp;
1501
1502         if (getex(pid, &hdr) < 0)
1503                 return -1;
1504         if (!hdr.a_dynamic)
1505                 return -1;
1506
1507         if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1508                 fprintf(stderr, "Cannot read DYNAMIC\n");
1509                 return -1;
1510         }
1511         if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1512                 fprintf(stderr, "Cannot read link_dynamic_2\n");
1513                 return -1;
1514         }
1515         if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
1516                 fprintf(stderr, "fixvfork: out of memory\n");
1517                 return -1;
1518         }
1519         if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1520                                         (int)ld.ld_symb_size, strtab) < 0)
1521                 goto err;
1522
1523 #if 0
1524         for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1525                 fprintf(stderr, "[symbol: %s]\n", cp);
1526                 cp += strlen(cp)+1;
1527         }
1528         return 0;
1529 #endif
1530         for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1531                 if (strcmp(cp, "_vfork") == 0) {
1532                         if (debug)
1533                                 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1534                         strcpy(cp, "_fork");
1535                         break;
1536                 }
1537                 cp += strlen(cp)+1;
1538         }
1539         if (cp < strtab + ld.ld_symb_size)
1540                 /*
1541                  * Write entire symbol table back to avoid
1542                  * memory alignment bugs in ptrace
1543                  */
1544                 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1545                                         (int)ld.ld_symb_size, strtab) < 0)
1546                         goto err;
1547
1548         free(strtab);
1549         return 0;
1550
1551 err:
1552         free(strtab);
1553         return -1;
1554 }
1555
1556 #endif /* SUNOS4 */