blob: 31e56cab22d164db6fec9260aa03e4a3a6841bbd [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
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>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * 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>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * 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
Roland McGrathd81f1d92003-01-09 06:53:34 +000038#include <signal.h>
39#include <sys/syscall.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000040#include <sys/user.h>
41#include <sys/param.h>
42#include <fcntl.h>
John Hughes1d08dcf2001-07-10 13:48:44 +000043#if HAVE_SYS_UIO_H
44#include <sys/uio.h>
45#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000046#ifdef SUNOS4
47#include <machine/reg.h>
48#include <a.out.h>
49#include <link.h>
50#endif /* SUNOS4 */
Wichert Akkerman36915a11999-07-13 15:45:02 +000051
Wichert Akkerman43a74822000-06-27 17:33:32 +000052#if defined(linux) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1))
Wichert Akkerman36915a11999-07-13 15:45:02 +000053#include <linux/ptrace.h>
Roland McGrath1e85cf92002-12-16 20:40:54 +000054#endif
Wichert Akkerman36915a11999-07-13 15:45:02 +000055
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000056#if defined(LINUX) && defined(IA64)
Roland McGrathd81f1d92003-01-09 06:53:34 +000057# include <asm/ptrace_offsets.h>
58# include <asm/rse.h>
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000059#endif
60
Wichert Akkerman36915a11999-07-13 15:45:02 +000061#ifdef HAVE_SYS_REG_H
62#include <sys/reg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000063# define PTRACE_PEEKUSR PTRACE_PEEKUSER
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
65#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman2e2553a1999-05-09 00:29:58 +000075#endif
76
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000077#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
78#include <sys/utsname.h>
79#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
80
Roland McGrath6d1a65c2004-07-12 07:44:08 +000081#if defined(LINUXSPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000082
Roland McGrath4db26242003-01-30 20:15:19 +000083# define fpq kernel_fpq
84# define fq kernel_fq
85# define fpu kernel_fpu
86# include <asm/reg.h>
87# undef fpq
88# undef fq
89# undef fpu
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000090
Roland McGrath6d1a65c2004-07-12 07:44:08 +000091#if defined (SPARC64)
92# define r_pc r_tpc
93# undef PTRACE_GETREGS
94# define PTRACE_GETREGS PTRACE_GETREGS64
95# undef PTRACE_SETREGS
96# define PTRACE_SETREGS PTRACE_SETREGS64
97#endif /* SPARC64 */
98
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000099#if !defined(__GLIBC__)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000100
101#include <linux/unistd.h>
102
103#define _hack_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,\
104 type5,arg5,syscall) \
105type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
106{ \
107 long __res; \
108\
109__asm__ volatile ("or %%g0, %1, %%o0\n\t" \
110 "or %%g0, %2, %%o1\n\t" \
111 "or %%g0, %3, %%o2\n\t" \
112 "or %%g0, %4, %%o3\n\t" \
113 "or %%g0, %5, %%o4\n\t" \
114 "or %%g0, %6, %%g1\n\t" \
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000115#if defined (SPARC64)
116 "t 0x6d\n\t" \
117#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000118 "t 0x10\n\t" \
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000119#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120 "bcc 1f\n\t" \
121 "or %%g0, %%o0, %0\n\t" \
122 "sub %%g0, %%o0, %0\n\t" \
123 "1:\n\t" \
124 : "=r" (__res) \
125 : "0" ((long)(arg1)),"1" ((long)(arg2)), \
126 "2" ((long)(arg3)),"3" ((long)(arg4)),"4" ((long)(arg5)), \
127 "i" (__NR_##syscall) \
128 : "g1", "o0", "o1", "o2", "o3", "o4"); \
129if (__res>=0) \
130 return (type) __res; \
131errno = -__res; \
132return -1; \
133}
134
135static _hack_syscall5(int,_ptrace,int,__request,int,__pid,int,__addr,int,__data,int,__addr2,ptrace)
136
137#define _ptrace
138
139#endif
140
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000141#endif
142
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000143/* macros */
144#ifndef MAX
145#define MAX(a,b) (((a) > (b)) ? (a) : (b))
146#endif
147#ifndef MIN
148#define MIN(a,b) (((a) < (b)) ? (a) : (b))
149#endif
150
151void
152tv_tv(tv, a, b)
153struct timeval *tv;
154int a;
155int b;
156{
157 tv->tv_sec = a;
158 tv->tv_usec = b;
159}
160
161int
162tv_nz(a)
163struct timeval *a;
164{
165 return a->tv_sec || a->tv_usec;
166}
167
168int
169tv_cmp(a, b)
170struct timeval *a, *b;
171{
172 if (a->tv_sec < b->tv_sec
173 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
174 return -1;
175 if (a->tv_sec > b->tv_sec
176 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
177 return 1;
178 return 0;
179}
180
181double
182tv_float(tv)
183struct timeval *tv;
184{
185 return tv->tv_sec + tv->tv_usec/1000000.0;
186}
187
188void
189tv_add(tv, a, b)
190struct timeval *tv, *a, *b;
191{
192 tv->tv_sec = a->tv_sec + b->tv_sec;
193 tv->tv_usec = a->tv_usec + b->tv_usec;
194 if (tv->tv_usec > 1000000) {
195 tv->tv_sec++;
196 tv->tv_usec -= 1000000;
197 }
198}
199
200void
201tv_sub(tv, a, b)
202struct timeval *tv, *a, *b;
203{
204 tv->tv_sec = a->tv_sec - b->tv_sec;
205 tv->tv_usec = a->tv_usec - b->tv_usec;
206 if (((long) tv->tv_usec) < 0) {
207 tv->tv_sec--;
208 tv->tv_usec += 1000000;
209 }
210}
211
212void
213tv_div(tv, a, n)
214struct timeval *tv, *a;
215int n;
216{
217 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
218 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
219 tv->tv_usec %= 1000000;
220}
221
222void
223tv_mul(tv, a, n)
224struct timeval *tv, *a;
225int n;
226{
227 tv->tv_usec = a->tv_usec * n;
228 tv->tv_sec = a->tv_sec * n + a->tv_usec / 1000000;
229 tv->tv_usec %= 1000000;
230}
231
232char *
233xlookup(xlat, val)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000234const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000235int val;
236{
237 for (; xlat->str != NULL; xlat++)
238 if (xlat->val == val)
239 return xlat->str;
240 return NULL;
241}
242
243/*
244 * Print entry in struct xlat table, if there.
245 */
246void
247printxval(xlat, val, dflt)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000248const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000249int val;
250char *dflt;
251{
252 char *str = xlookup(xlat, val);
253
254 if (str)
255 tprintf("%s", str);
256 else
257 tprintf("%#x /* %s */", val, dflt);
258}
259
260/*
261 * Interpret `xlat' as an array of flags
262 * print the entries whose bits are on in `flags'
263 * return # of flags printed.
264 */
265int
266addflags(xlat, flags)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000267const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000268int flags;
269{
270 int n;
271
272 for (n = 0; xlat->str; xlat++) {
273 if (xlat->val && (flags & xlat->val) == xlat->val) {
274 tprintf("|%s", xlat->str);
275 flags &= ~xlat->val;
276 n++;
277 }
278 }
279 if (flags) {
280 tprintf("|%#x", flags);
281 n++;
282 }
283 return n;
284}
285
286int
287printflags(xlat, flags)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000288const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000289int flags;
290{
291 int n;
292 char *sep;
293
294 if (flags == 0 && xlat->val == 0) {
295 tprintf("%s", xlat->str);
296 return 1;
297 }
298
299 sep = "";
300 for (n = 0; xlat->str; xlat++) {
301 if (xlat->val && (flags & xlat->val) == xlat->val) {
302 tprintf("%s%s", sep, xlat->str);
303 flags &= ~xlat->val;
304 sep = "|";
305 n++;
306 }
307 }
308 if (flags) {
309 tprintf("%s%#x", sep, flags);
310 n++;
311 }
312 return n;
313}
314
315void
316printnum(tcp, addr, fmt)
317struct tcb *tcp;
318long addr;
319char *fmt;
320{
Roland McGratheb285352003-01-14 09:59:00 +0000321 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000322
323 if (!addr) {
324 tprintf("NULL");
325 return;
326 }
327 if (umove(tcp, addr, &num) < 0) {
328 tprintf("%#lx", addr);
329 return;
330 }
331 tprintf("[");
332 tprintf(fmt, num);
333 tprintf("]");
334}
335
Roland McGrath6bc12202003-11-13 22:32:27 +0000336void
337printuid(text, uid)
338const char *text;
339unsigned long uid;
340{
341 tprintf("%s", text);
342 tprintf((uid == -1) ? "%ld" : "%lu", uid);
343}
344
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000345static char path[MAXPATHLEN + 1];
346
347void
348string_quote(str)
349char *str;
350{
351 char buf[2 * MAXPATHLEN + 1];
352 char *s;
353
354 if (!strpbrk(str, "\"\'\\")) {
355 tprintf("\"%s\"", str);
356 return;
357 }
358 for (s = buf; *str; str++) {
359 switch (*str) {
360 case '\"': case '\'': case '\\':
361 *s++ = '\\'; *s++ = *str; break;
362 default:
363 *s++ = *str; break;
364 }
365 }
366 *s = '\0';
367 tprintf("\"%s\"", buf);
368}
369
370void
371printpath(tcp, addr)
372struct tcb *tcp;
373long addr;
374{
375 if (umovestr(tcp, addr, MAXPATHLEN, path) < 0)
376 tprintf("%#lx", addr);
377 else
378 string_quote(path);
379 return;
380}
381
382void
383printpathn(tcp, addr, n)
384struct tcb *tcp;
385long addr;
386int n;
387{
388 if (umovestr(tcp, addr, n, path) < 0)
389 tprintf("%#lx", addr);
390 else {
391 path[n] = '\0';
392 string_quote(path);
393 }
394}
395
396void
397printstr(tcp, addr, len)
398struct tcb *tcp;
399long addr;
400int len;
401{
402 static unsigned char *str = NULL;
403 static char *outstr;
404 int i, n, c, usehex;
405 char *s, *outend;
406
407 if (!addr) {
408 tprintf("NULL");
409 return;
410 }
411 if (!str) {
412 if ((str = malloc(max_strlen)) == NULL
413 || (outstr = malloc(2*max_strlen)) == NULL) {
414 fprintf(stderr, "printstr: no memory\n");
415 tprintf("%#lx", addr);
416 return;
417 }
418 }
Wichert Akkerman2e2553a1999-05-09 00:29:58 +0000419 outend = outstr + max_strlen * 2 - 10;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000420 if (len < 0) {
421 n = max_strlen;
422 if (umovestr(tcp, addr, n, (char *) str) < 0) {
423 tprintf("%#lx", addr);
424 return;
425 }
426 }
427 else {
428 n = MIN(len, max_strlen);
429 if (umoven(tcp, addr, n, (char *) str) < 0) {
430 tprintf("%#lx", addr);
431 return;
432 }
433 }
434
435 usehex = 0;
436 if (xflag > 1)
437 usehex = 1;
438 else if (xflag) {
439 for (i = 0; i < n; i++) {
440 c = str[i];
441 if (len < 0 && c == '\0')
442 break;
443 if (!isprint(c) && !isspace(c)) {
444 usehex = 1;
445 break;
446 }
447 }
448 }
449
450 s = outstr;
451 *s++ = '\"';
452
453 if (usehex) {
454 for (i = 0; i < n; i++) {
455 c = str[i];
456 if (len < 0 && c == '\0')
457 break;
458 sprintf(s, "\\x%02x", c);
459 s += 4;
460 if (s > outend)
461 break;
462 }
463 }
464 else {
465 for (i = 0; i < n; i++) {
466 c = str[i];
467 if (len < 0 && c == '\0')
468 break;
469 switch (c) {
470 case '\"': case '\'': case '\\':
471 *s++ = '\\'; *s++ = c; break;
472 case '\f':
473 *s++ = '\\'; *s++ = 'f'; break;
474 case '\n':
475 *s++ = '\\'; *s++ = 'n'; break;
476 case '\r':
477 *s++ = '\\'; *s++ = 'r'; break;
478 case '\t':
479 *s++ = '\\'; *s++ = 't'; break;
480 case '\v':
481 *s++ = '\\'; *s++ = 'v'; break;
482 default:
483 if (isprint(c))
484 *s++ = c;
485 else if (i < n - 1 && isdigit(str[i + 1])) {
486 sprintf(s, "\\%03o", c);
487 s += 4;
488 }
489 else {
490 sprintf(s, "\\%o", c);
491 s += strlen(s);
492 }
493 break;
494 }
495 if (s > outend)
496 break;
497 }
498 }
499
500 *s++ = '\"';
501 if (i < len || (len < 0 && (i == n || s > outend))) {
502 *s++ = '.'; *s++ = '.'; *s++ = '.';
503 }
504 *s = '\0';
505 tprintf("%s", outstr);
506}
507
John Hughes1d08dcf2001-07-10 13:48:44 +0000508#if HAVE_SYS_UIO_H
509void
510dumpiov(tcp, len, addr)
511struct tcb * tcp;
512int len;
513long addr;
514{
515 struct iovec *iov;
516 int i;
517
Roland McGrath1e85cf92002-12-16 20:40:54 +0000518
John Hughes1d08dcf2001-07-10 13:48:44 +0000519 if ((iov = (struct iovec *) malloc(len * sizeof *iov)) == NULL) {
520 fprintf(stderr, "dump: No memory");
521 return;
522 }
523 if (umoven(tcp, addr,
524 len * sizeof *iov, (char *) iov) >= 0) {
Roland McGrath1e85cf92002-12-16 20:40:54 +0000525
John Hughes1d08dcf2001-07-10 13:48:44 +0000526 for (i = 0; i < len; i++) {
527 /* include the buffer number to make it easy to
528 * match up the trace with the source */
529 tprintf(" * %lu bytes in buffer %d\n",
530 (unsigned long)iov[i].iov_len, i);
531 dumpstr(tcp, (long) iov[i].iov_base,
532 iov[i].iov_len);
533 }
534 }
535 free((char *) iov);
Roland McGrath1e85cf92002-12-16 20:40:54 +0000536
John Hughes1d08dcf2001-07-10 13:48:44 +0000537}
538#endif
539
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000540void
541dumpstr(tcp, addr, len)
542struct tcb *tcp;
543long addr;
544int len;
545{
546 static int strsize = -1;
547 static unsigned char *str;
548 static char outstr[80];
549 char *s;
550 int i, j;
551
552 if (strsize < len) {
553 if (str)
554 free(str);
555 if ((str = malloc(len)) == NULL) {
556 fprintf(stderr, "dump: no memory\n");
557 return;
558 }
559 strsize = len;
560 }
561
562 if (umoven(tcp, addr, len, (char *) str) < 0)
563 return;
564
565 for (i = 0; i < len; i += 16) {
566 s = outstr;
567 sprintf(s, " | %05x ", i);
568 s += 9;
569 for (j = 0; j < 16; j++) {
570 if (j == 8)
571 *s++ = ' ';
572 if (i + j < len) {
573 sprintf(s, " %02x", str[i + j]);
574 s += 3;
575 }
576 else {
577 *s++ = ' '; *s++ = ' '; *s++ = ' ';
578 }
579 }
580 *s++ = ' '; *s++ = ' ';
581 for (j = 0; j < 16; j++) {
582 if (j == 8)
583 *s++ = ' ';
584 if (i + j < len) {
585 if (isprint(str[i + j]))
586 *s++ = str[i + j];
587 else
588 *s++ = '.';
589 }
590 else
591 *s++ = ' ';
592 }
593 tprintf("%s |\n", outstr);
594 }
595}
596
597#define PAGMASK (~(PAGSIZ - 1))
598/*
599 * move `len' bytes of data from process `pid'
600 * at address `addr' to our space at `laddr'
601 */
602int
603umoven(tcp, addr, len, laddr)
604struct tcb *tcp;
605long addr;
606int len;
607char *laddr;
608{
609
610#ifdef LINUX
611 int pid = tcp->pid;
612 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000613 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000614 union {
615 long val;
616 char x[sizeof(long)];
617 } u;
618
619 if (addr & (sizeof(long) - 1)) {
620 /* addr not a multiple of sizeof(long) */
621 n = addr - (addr & -sizeof(long)); /* residue */
622 addr &= -sizeof(long); /* residue */
623 errno = 0;
624 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
625 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000626 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000627 /* Ran into 'end of memory' - stupid "printpath" */
628 return 0;
629 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000630 /* But if not started, we had a bogus address. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631 perror("ptrace: umoven");
632 return -1;
633 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000634 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000635 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
636 addr += sizeof(long), laddr += m, len -= m;
637 }
638 while (len) {
639 errno = 0;
640 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
641 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000642 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000643 /* Ran into 'end of memory' - stupid "printpath" */
644 return 0;
645 }
Roland McGrath4db26242003-01-30 20:15:19 +0000646 if (addr != 0)
647 perror("ptrace: umoven");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000648 return -1;
649 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000650 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000651 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
652 addr += sizeof(long), laddr += m, len -= m;
653 }
654#endif /* LINUX */
655
656#ifdef SUNOS4
657 int pid = tcp->pid;
658#if 0
659 int n, m;
660 union {
661 long val;
662 char x[sizeof(long)];
663 } u;
664
665 if (addr & (sizeof(long) - 1)) {
666 /* addr not a multiple of sizeof(long) */
667 n = addr - (addr & -sizeof(long)); /* residue */
668 addr &= -sizeof(long); /* residue */
669 errno = 0;
670 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
671 if (errno) {
672 perror("umoven");
673 return -1;
674 }
675 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
676 addr += sizeof(long), laddr += m, len -= m;
677 }
678 while (len) {
679 errno = 0;
680 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
681 if (errno) {
682 perror("umoven");
683 return -1;
684 }
685 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
686 addr += sizeof(long), laddr += m, len -= m;
687 }
688#else /* !oldway */
689 int n;
690
691 while (len) {
692 n = MIN(len, PAGSIZ);
693 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
694 if (ptrace(PTRACE_READDATA, pid,
695 (char *) addr, len, laddr) < 0) {
696 perror("umoven: ptrace(PTRACE_READDATA, ...)");
697 abort();
698 return -1;
699 }
700 len -= n;
701 addr += n;
702 laddr += n;
703 }
704#endif /* !oldway */
705#endif /* SUNOS4 */
706
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000707#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000708#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000709 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000710#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000711 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000712#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000713 lseek(fd, addr, SEEK_SET);
714 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000715 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000716#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000717
718 return 0;
719}
720
721/*
722 * like `umove' but make the additional effort of looking
723 * for a terminating zero byte.
724 */
725int
726umovestr(tcp, addr, len, laddr)
727struct tcb *tcp;
728long addr;
729int len;
730char *laddr;
731{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000732#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000733#ifdef HAVE_MP_PROCFS
734 int fd = tcp->pfd_as;
735#else
736 int fd = tcp->pfd;
737#endif
738 /* Some systems (e.g. FreeBSD) can be upset if we read off the
739 end of valid memory, avoid this by trying to read up
740 to page boundaries. But we don't know what a page is (and
741 getpagesize(2) (if it exists) doesn't necessarily return
742 hardware page size). Assume all pages >= 1024 (a-historical
743 I know) */
744
745 int page = 1024; /* How to find this? */
746 int move = page - (addr & (page - 1));
747 int left = len;
748
749 lseek(fd, addr, SEEK_SET);
750
751 while (left) {
752 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000753 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000754 return left != len ? 0 : -1;
755 if (memchr (laddr, 0, move)) break;
756 left -= move;
757 laddr += move;
758 addr += move;
759 move = page;
760 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000761#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000762 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763 int pid = tcp->pid;
764 int i, n, m;
765 union {
766 long val;
767 char x[sizeof(long)];
768 } u;
769
770 if (addr & (sizeof(long) - 1)) {
771 /* addr not a multiple of sizeof(long) */
772 n = addr - (addr & -sizeof(long)); /* residue */
773 addr &= -sizeof(long); /* residue */
774 errno = 0;
775 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
776 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000777 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778 /* Ran into 'end of memory' - stupid "printpath" */
779 return 0;
780 }
781 perror("umovestr");
782 return -1;
783 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000784 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000785 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
786 while (n & (sizeof(long) - 1))
787 if (u.x[n++] == '\0')
788 return 0;
789 addr += sizeof(long), laddr += m, len -= m;
790 }
791 while (len) {
792 errno = 0;
793 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
794 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000795 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000796 /* Ran into 'end of memory' - stupid "printpath" */
797 return 0;
798 }
799 perror("umovestr");
800 return -1;
801 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000802 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000803 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
804 for (i = 0; i < sizeof(long); i++)
805 if (u.x[i] == '\0')
806 return 0;
807
808 addr += sizeof(long), laddr += m, len -= m;
809 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000810#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000811 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000812}
813
814#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000815#if !defined (SPARC) && !defined(SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000816#define PTRACE_WRITETEXT 101
817#define PTRACE_WRITEDATA 102
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000818#endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000819#endif /* LINUX */
820
821#ifdef SUNOS4
822
823static int
824uload(cmd, pid, addr, len, laddr)
825int cmd;
826int pid;
827long addr;
828int len;
829char *laddr;
830{
831#if 0
832 int n;
833
834 while (len) {
835 n = MIN(len, PAGSIZ);
836 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
837 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
838 perror("uload: ptrace(PTRACE_WRITE, ...)");
839 return -1;
840 }
841 len -= n;
842 addr += n;
843 laddr += n;
844 }
845#else
846 int peek, poke;
847 int n, m;
848 union {
849 long val;
850 char x[sizeof(long)];
851 } u;
852
853 if (cmd == PTRACE_WRITETEXT) {
854 peek = PTRACE_PEEKTEXT;
855 poke = PTRACE_POKETEXT;
856 }
857 else {
858 peek = PTRACE_PEEKDATA;
859 poke = PTRACE_POKEDATA;
860 }
861 if (addr & (sizeof(long) - 1)) {
862 /* addr not a multiple of sizeof(long) */
863 n = addr - (addr & -sizeof(long)); /* residue */
864 addr &= -sizeof(long);
865 errno = 0;
866 u.val = ptrace(peek, pid, (char *) addr, 0);
867 if (errno) {
868 perror("uload: POKE");
869 return -1;
870 }
871 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
872 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
873 perror("uload: POKE");
874 return -1;
875 }
876 addr += sizeof(long), laddr += m, len -= m;
877 }
878 while (len) {
879 if (len < sizeof(long))
880 u.val = ptrace(peek, pid, (char *) addr, 0);
881 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
882 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
883 perror("uload: POKE");
884 return -1;
885 }
886 addr += sizeof(long), laddr += m, len -= m;
887 }
888#endif
889 return 0;
890}
891
892int
893tload(pid, addr, len, laddr)
894int pid;
895int addr, len;
896char *laddr;
897{
898 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
899}
900
901int
902dload(pid, addr, len, laddr)
903int pid;
904int addr;
905int len;
906char *laddr;
907{
908 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
909}
910
911#endif /* SUNOS4 */
912
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000913#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000914
915int
916upeek(pid, off, res)
917int pid;
918long off;
919long *res;
920{
921 long val;
922
923#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
924 {
925 static int is_sun4m = -1;
926 struct utsname name;
927
928 /* Round up the usual suspects. */
929 if (is_sun4m == -1) {
930 if (uname(&name) < 0) {
931 perror("upeek: uname?");
932 exit(1);
933 }
934 is_sun4m = strcmp(name.machine, "sun4m") == 0;
935 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +0000936 extern const struct xlat struct_user_offsets[];
937 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000938
939 for (x = struct_user_offsets; x->str; x++)
940 x->val += 1024;
941 }
942 }
943 if (is_sun4m)
944 off += 1024;
945 }
946#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
947 errno = 0;
948 val = ptrace(PTRACE_PEEKUSER, pid, (char *) off, 0);
949 if (val == -1 && errno) {
Roland McGrath1e85cf92002-12-16 20:40:54 +0000950 char buf[60];
Michal Ludvig0e035502002-09-23 15:41:01 +0000951 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)",pid,off);
Roland McGrath1e85cf92002-12-16 20:40:54 +0000952 perror(buf);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000953 return -1;
954 }
955 *res = val;
956 return 0;
957}
958
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000959#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000960
961long
962getpc(tcp)
963struct tcb *tcp;
964{
965
966#ifdef LINUX
967 long pc;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000968#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000969 if (upeek(tcp->pid, 4*EIP, &pc) < 0)
970 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000971#elif defined(X86_64)
972 if (upeek(tcp->pid, 8*RIP, &pc) < 0)
973 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000974#elif defined(IA64)
975 if (upeek(tcp->pid, PT_B0, &pc) < 0)
976 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000977#elif defined(ARM)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000978 if (upeek(tcp->pid, 4*15, &pc) < 0)
979 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000980#elif defined(POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000981 if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000982 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000983#elif defined(M68k)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000984 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
985 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000986#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000987 if (upeek(tcp->pid, REG_PC, &pc) < 0)
988 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000989#elif defined(MIPS)
990 if (upeek(tcp->pid, REG_EPC, &pc) < 0)
991 return -1;
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000992#elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000993 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000994 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
995 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000996 pc = regs.r_pc;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000997#elif defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000998 if(upeek(tcp->pid,PT_PSWADDR,&pc) < 0)
Michal Ludvig10a88d02002-10-07 14:31:00 +0000999 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001000#elif defined(HPPA)
1001 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0)
1002 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001003#elif defined(SH)
1004 if (upeek(tcp->pid, 4*REG_PC ,&pc) < 0)
1005 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001006#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001007 if (upeek(tcp->pid, REG_PC ,&pc) < 0)
1008 return -1;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +00001009#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001010 return pc;
1011#endif /* LINUX */
1012
1013#ifdef SUNOS4
1014 /*
1015 * Return current program counter for `pid'
1016 * Assumes PC is never 0xffffffff
1017 */
1018 struct regs regs;
1019
1020 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1021 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
1022 return -1;
1023 }
1024 return regs.r_pc;
1025#endif /* SUNOS4 */
1026
1027#ifdef SVR4
1028 /* XXX */
1029 return 0;
1030#endif /* SVR4 */
1031
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001032#ifdef FREEBSD
1033 struct reg regs;
1034 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1035 return regs.r_eip;
1036#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001037}
1038
1039void
1040printcall(tcp)
1041struct tcb *tcp;
1042{
Roland McGrath7a918832005-02-02 20:55:23 +00001043#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1044 sizeof(long) == 8 ? "[????????????????] " : \
1045 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001046
1047#ifdef LINUX
1048#ifdef I386
1049 long eip;
1050
1051 if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001052 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001053 return;
1054 }
1055 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001056
1057#elif defined(S390) || defined(S390X)
1058 long psw;
1059 if(upeek(tcp->pid,PT_PSWADDR,&psw) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001060 PRINTBADPC;
Roland McGratheac26fc2005-02-02 02:48:53 +00001061 return;
1062 }
1063#ifdef S390
1064 tprintf("[%08lx] ", psw);
1065#elif S390X
1066 tprintf("[%16lx] ", psw);
1067#endif
1068
Michal Ludvig0e035502002-09-23 15:41:01 +00001069#elif defined(X86_64)
1070 long rip;
1071
1072 if (upeek(tcp->pid, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001073 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001074 return;
1075 }
1076 tprintf("[%16lx] ", rip);
Roland McGrathef388682003-06-03 23:28:59 +00001077#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001078 long ip;
1079
1080 if (upeek(tcp->pid, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001081 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001082 return;
1083 }
1084 tprintf("[%08lx] ", ip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001085#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086 long pc;
1087
Roland McGratheb285352003-01-14 09:59:00 +00001088 if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089 tprintf ("[????????] ");
1090 return;
1091 }
1092 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001093#elif defined(M68k)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001094 long pc;
1095
1096 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
1097 tprintf ("[????????] ");
1098 return;
1099 }
1100 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001101#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102 long pc;
1103
1104 if (upeek(tcp->pid, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001105 tprintf ("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001106 return;
1107 }
1108 tprintf("[%08lx] ", pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001109#elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001110 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001111 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001112 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001113 return;
1114 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001115 tprintf("[%08lx] ", regs.r_pc);
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001116#elif defined(HPPA)
1117 long pc;
1118
1119 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0) {
1120 tprintf ("[????????] ");
1121 return;
1122 }
1123 tprintf("[%08lx] ", pc);
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001124#elif defined(MIPS)
1125 long pc;
1126
1127 if (upeek(tcp->pid, REG_EPC, &pc) < 0) {
1128 tprintf ("[????????] ");
1129 return;
1130 }
1131 tprintf("[%08lx] ", pc);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001132#elif defined(SH)
1133 long pc;
1134
1135 if (upeek(tcp->pid, 4*REG_PC, &pc) < 0) {
1136 tprintf ("[????????] ");
1137 return;
1138 }
1139 tprintf("[%08lx] ", pc);
Roland McGrathf5a47772003-06-26 22:40:42 +00001140#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001141 long pc;
1142
1143 if (upeek(tcp->pid, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001144 tprintf ("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001145 return;
1146 }
1147 tprintf("[%08lx] ", pc);
Roland McGrathef388682003-06-03 23:28:59 +00001148#elif defined(ARM)
1149 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001150
Roland McGrathef388682003-06-03 23:28:59 +00001151 if (upeek(tcp->pid, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001152 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001153 return;
1154 }
1155 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001156#endif /* !architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001157#endif /* LINUX */
1158
1159#ifdef SUNOS4
1160 struct regs regs;
1161
1162 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1163 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001164 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001165 return;
1166 }
1167 tprintf("[%08x] ", regs.r_o7);
1168#endif /* SUNOS4 */
1169
1170#ifdef SVR4
1171 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001172 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001173#endif
1174
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001175#ifdef FREEBSD
1176 struct reg regs;
1177 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1178 tprintf("[%08x] ", regs.r_eip);
1179#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001180}
1181
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001182#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001183
Roland McGrathd81f1d92003-01-09 06:53:34 +00001184#if defined LINUX
1185
1186#include <sys/syscall.h>
1187#ifndef CLONE_PTRACE
1188# define CLONE_PTRACE 0x00002000
1189#endif
1190
1191#ifdef IA64
1192
Roland McGrath08267b82004-02-20 22:56:43 +00001193/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1194 subsystem has them for x86... */
1195#define SYS_fork 2
1196#define SYS_vfork 190
1197
Roland McGrathd81f1d92003-01-09 06:53:34 +00001198typedef unsigned long *arg_setup_state;
1199
1200static int
1201arg_setup(struct tcb *tcp, arg_setup_state *state)
1202{
1203 unsigned long *bsp, cfm, sof, sol;
1204
Roland McGrath08267b82004-02-20 22:56:43 +00001205 if (ia32)
1206 return 0;
1207
Roland McGrathd81f1d92003-01-09 06:53:34 +00001208 if (upeek(tcp->pid, PT_AR_BSP, (long *) &bsp) < 0)
1209 return -1;
1210 if (upeek(tcp->pid, PT_CFM, (long *) &cfm) < 0)
1211 return -1;
1212
1213 sof = (cfm >> 0) & 0x7f;
1214 sol = (cfm >> 7) & 0x7f;
1215 bsp = ia64_rse_skip_regs(bsp, -sof + sol);
1216
1217 *state = bsp;
1218 return 0;
1219}
1220
1221# define arg_finish_change(tcp, state) 0
1222
1223#ifdef SYS_fork
1224static int
1225get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1226{
Roland McGrath08267b82004-02-20 22:56:43 +00001227 int ret;
1228
1229 if (ia32)
1230 ret = upeek (tcp->pid, PT_R11, valp);
1231 else
1232 ret = umoven (tcp,
1233 (unsigned long) ia64_rse_skip_regs(*state, 0),
1234 sizeof(long), (void *) valp);
1235 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001236}
1237
1238static int
1239get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1240{
Roland McGrath08267b82004-02-20 22:56:43 +00001241 int ret;
1242
1243 if (ia32)
1244 ret = upeek (tcp->pid, PT_R9, valp);
1245 else
1246 ret = umoven (tcp,
1247 (unsigned long) ia64_rse_skip_regs(*state, 1),
1248 sizeof(long), (void *) valp);
1249 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001250}
1251#endif
1252
1253static int
1254set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1255{
Roland McGrath08267b82004-02-20 22:56:43 +00001256 int req = PTRACE_POKEDATA;
1257 void *ap;
1258
1259 if (ia32) {
1260 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1261 req = PTRACE_POKEUSER;
1262 } else
1263 ap = ia64_rse_skip_regs(*state, 0);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001264 errno = 0;
Roland McGrath08267b82004-02-20 22:56:43 +00001265 ptrace(req, tcp->pid, ap, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001266 return errno ? -1 : 0;
1267}
1268
1269static int
1270set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1271{
Roland McGrath08267b82004-02-20 22:56:43 +00001272 int req = PTRACE_POKEDATA;
1273 void *ap;
1274
1275 if (ia32) {
1276 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1277 req = PTRACE_POKEUSER;
1278 } else
1279 ap = ia64_rse_skip_regs(*state, 1);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001280 errno = 0;
Roland McGrath08267b82004-02-20 22:56:43 +00001281 ptrace(req, tcp->pid, ap, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001282 return errno ? -1 : 0;
1283}
1284
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001285#elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001286
1287typedef struct regs arg_setup_state;
1288
1289# define arg_setup(tcp, state) \
1290 (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
1291# define arg_finish_change(tcp, state) \
1292 (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
1293
1294# define get_arg0(tcp, state, valp) (*(valp) = (state)->r_o0, 0)
1295# define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0)
1296# define set_arg0(tcp, state, val) ((state)->r_o0 = (val), 0)
1297# define set_arg1(tcp, state, val) ((state)->r_o1 = (val), 0)
Roland McGrathe1df47f2003-01-14 09:46:15 +00001298# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001299
1300#else
1301
1302# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001303/* Note: this is only true for the `clone' system call, which handles
1304 arguments specially. We could as well say that its first two arguments
1305 are swapped relative to other architectures, but that would just be
1306 another #ifdef in the calls. */
1307# define arg0_offset PT_GPR3
1308# define arg1_offset PT_ORIGGPR2
1309# define restore_arg0(tcp, state, val) ((void) (state), 0)
1310# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001311# define arg0_index 1
1312# define arg1_index 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001313# elif defined (ALPHA) || defined (MIPS)
1314# define arg0_offset REG_A0
1315# define arg1_offset (REG_A0+1)
1316# elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001317# define arg0_offset (sizeof(unsigned long)*PT_R3)
1318# define arg1_offset (sizeof(unsigned long)*PT_R4)
Roland McGrath7b308222003-01-20 09:04:36 +00001319# define restore_arg0(tcp, state, val) ((void) (state), 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001320# elif defined (HPPA)
1321# define arg0_offset PT_GR26
1322# define arg1_offset (PT_GR26-4)
Roland McGrath7f33cc32003-01-10 20:51:00 +00001323# elif defined (X86_64)
1324# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1325# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
Roland McGrathac971c22003-03-31 01:03:33 +00001326# elif defined (SH)
1327# define arg0_offset (4*(REG_REG0+4))
1328# define arg1_offset (4*(REG_REG0+5))
Roland McGrathf5a47772003-06-26 22:40:42 +00001329# elif defined (SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001330 /* ABI defines arg0 & 1 in r2 & r3 */
1331# define arg0_offset (REG_OFFSET+16)
1332# define arg1_offset (REG_OFFSET+24)
1333# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001334# else
1335# define arg0_offset 0
1336# define arg1_offset 4
Roland McGrathac971c22003-03-31 01:03:33 +00001337# if defined ARM
Roland McGrathe1df47f2003-01-14 09:46:15 +00001338# define restore_arg0(tcp, state, val) 0
1339# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001340# endif
1341
1342typedef int arg_setup_state;
1343
1344# define arg_setup(tcp, state) (0)
1345# define arg_finish_change(tcp, state) 0
1346# define get_arg0(tcp, cookie, valp) \
1347 (upeek ((tcp)->pid, arg0_offset, (valp)))
1348# define get_arg1(tcp, cookie, valp) \
1349 (upeek ((tcp)->pid, arg1_offset, (valp)))
1350
1351static int
1352set_arg0 (struct tcb *tcp, void *cookie, long val)
1353{
1354 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
1355}
1356
1357static int
1358set_arg1 (struct tcb *tcp, void *cookie, long val)
1359{
1360 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
1361}
1362
1363#endif
1364
Roland McGrathe1df47f2003-01-14 09:46:15 +00001365#ifndef restore_arg0
1366# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1367#endif
1368#ifndef restore_arg1
1369# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1370#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001371
Roland McGrath90d0afd2004-03-01 21:05:16 +00001372#ifndef arg0_index
1373# define arg0_index 0
1374# define arg1_index 1
1375#endif
1376
Roland McGrathd81f1d92003-01-09 06:53:34 +00001377int
1378setbpt(tcp)
1379struct tcb *tcp;
1380{
1381 extern int change_syscall(struct tcb *, int);
1382 arg_setup_state state;
1383
1384 if (tcp->flags & TCB_BPTSET) {
1385 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1386 return -1;
1387 }
1388
1389 switch (tcp->scno) {
Roland McGrath9383c6c2003-01-18 00:19:31 +00001390#ifdef SYS_vfork
1391 case SYS_vfork:
1392#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001393#ifdef SYS_fork
1394 case SYS_fork:
Roland McGrath9b0982b2003-01-18 00:21:51 +00001395#endif
1396#if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001397 if (arg_setup (tcp, &state) < 0
1398 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1399 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
1400 || change_syscall(tcp, SYS_clone) < 0
1401 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1402 || set_arg1 (tcp, &state, 0) < 0
1403 || arg_finish_change (tcp, &state) < 0)
1404 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001405 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1406 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001407 tcp->flags |= TCB_BPTSET;
1408 return 0;
1409#endif
1410
1411 case SYS_clone:
1412#ifdef SYS_clone2
1413 case SYS_clone2:
1414#endif
Roland McGrath02cee8d2004-03-02 08:50:42 +00001415 if ((tcp->u_arg[arg0_index] & CLONE_PTRACE) == 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001416 && (arg_setup (tcp, &state) < 0
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001417 || set_arg0 (tcp, &state,
1418 tcp->u_arg[arg0_index] | CLONE_PTRACE) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001419 || arg_finish_change (tcp, &state) < 0))
1420 return -1;
1421 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001422 tcp->inst[0] = tcp->u_arg[arg0_index];
1423 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001424 return 0;
1425
1426 default:
1427 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1428 tcp->scno, tcp->pid);
1429 break;
1430 }
1431
1432 return -1;
1433}
1434
1435int
1436clearbpt(tcp)
1437struct tcb *tcp;
1438{
1439 arg_setup_state state;
1440 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001441 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1442 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001443 || arg_finish_change (tcp, &state))
1444 return -1;
1445 tcp->flags &= ~TCB_BPTSET;
1446 return 0;
1447}
1448
1449#else
1450
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001451int
1452setbpt(tcp)
1453struct tcb *tcp;
1454{
1455
1456#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001457#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001458 /* We simply use the SunOS breakpoint code. */
1459
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001460 struct regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001461 unsigned long inst;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001462#define LOOPA 0x30800000 /* ba,a 0 */
1463
1464 if (tcp->flags & TCB_BPTSET) {
1465 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1466 return -1;
1467 }
1468 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1469 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1470 return -1;
1471 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001472 tcp->baddr = regs.r_o7 + 8;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001473 errno = 0;
1474 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1475 if(errno) {
1476 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1477 return -1;
1478 }
1479
1480 /*
1481 * XXX - BRUTAL MODE ON
1482 * We cannot set a real BPT in the child, since it will not be
1483 * traced at the moment it will reach the trap and would probably
1484 * die with a core dump.
1485 * Thus, we are force our way in by taking out two instructions
1486 * and insert an eternal loop instead, in expectance of the SIGSTOP
1487 * generated by out PTRACE_ATTACH.
1488 * Of cause, if we evaporate ourselves in the middle of all this...
1489 */
1490 errno = 0;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001491 inst = LOOPA;
1492#if defined (SPARC64)
1493 inst <<= 32;
1494 inst |= (tcp->inst[0] & 0xffffffffUL);
1495#endif
1496 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, inst);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001497 if(errno) {
1498 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1499 return -1;
1500 }
1501 tcp->flags |= TCB_BPTSET;
1502
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001503#else /* !SPARC && !SPARC64 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001504#ifdef IA64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001505 if (ia32) {
1506# define LOOP 0x0000feeb
1507 if (tcp->flags & TCB_BPTSET) {
1508 fprintf(stderr, "PANIC: bpt already set in pid %u\n",
1509 tcp->pid);
1510 return -1;
1511 }
1512 if (upeek(tcp->pid, PT_CR_IIP, &tcp->baddr) < 0)
1513 return -1;
1514 if (debug)
1515 fprintf(stderr, "[%d] setting bpt at %lx\n",
1516 tcp->pid, tcp->baddr);
1517 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid,
1518 (char *) tcp->baddr, 0);
1519 if (errno) {
1520 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1521 return -1;
1522 }
1523 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1524 if (errno) {
1525 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1526 return -1;
1527 }
1528 tcp->flags |= TCB_BPTSET;
1529 } else {
1530 /*
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001531 * Our strategy here is to replace the bundle that
1532 * contained the clone() syscall with a bundle of the
1533 * form:
1534 *
1535 * { 1: br 1b; br 1b; br 1b }
1536 *
1537 * This ensures that the newly forked child will loop
1538 * endlessly until we've got a chance to attach to it.
1539 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001540# define LOOP0 0x0000100000000017
1541# define LOOP1 0x4000000000200000
1542 unsigned long addr, ipsr;
1543 pid_t pid;
1544
1545 pid = tcp->pid;
1546 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1547 return -1;
1548 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1549 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001550 /* store "ri" in low two bits */
1551 tcp->baddr = addr | ((ipsr >> 41) & 0x3);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001552
1553 errno = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001554 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0,
1555 0);
1556 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8,
1557 0);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001558 if (errno) {
1559 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1560 return -1;
1561 }
1562
1563 errno = 0;
1564 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1565 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1566 if (errno) {
1567 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1568 return -1;
1569 }
1570 tcp->flags |= TCB_BPTSET;
1571 }
1572#else /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001573
Michal Ludvig0e035502002-09-23 15:41:01 +00001574#if defined (I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001575#define LOOP 0x0000feeb
1576#elif defined (M68K)
1577#define LOOP 0x60fe0000
1578#elif defined (ALPHA)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001579#define LOOP 0xc3ffffff
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001580#elif defined (POWERPC)
Roland McGrath1e85cf92002-12-16 20:40:54 +00001581#define LOOP 0x48000000
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001582#elif defined(ARM)
Wichert Akkerman9a8a37f1999-12-24 23:19:31 +00001583#define LOOP 0xEAFFFFFE
Wichert Akkermanf90da011999-10-31 21:15:38 +00001584#elif defined(MIPS)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001585#define LOOP 0x1000ffff
1586#elif defined(S390)
1587#define LOOP 0xa7f40000 /* BRC 15,0 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001588#elif defined(S390X)
1589#define LOOP 0xa7f4000000000000UL /* BRC 15,0 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001590#elif defined(HPPA)
1591#define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001592#elif defined(SH)
1593#ifdef __LITTLE_ENDIAN__
1594#define LOOP 0x0000affe
1595#else
1596#define LOOP 0xfeaf0000
1597#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001598#else
1599#error unknown architecture
1600#endif
1601
1602 if (tcp->flags & TCB_BPTSET) {
1603 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1604 return -1;
1605 }
1606#if defined (I386)
1607 if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1608 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00001609#elif defined (X86_64)
1610 if (upeek(tcp->pid, 8*RIP, &tcp->baddr) < 0)
1611 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001612#elif defined (M68K)
1613 if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1614 return -1;
1615#elif defined (ALPHA)
1616 return -1;
1617#elif defined (ARM)
1618 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001619#elif defined (MIPS)
1620 return -1; /* FIXME: I do not know what i do - Flo */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001622 if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 return -1;
Michal Ludvig10a88d02002-10-07 14:31:00 +00001624#elif defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001625 if (upeek(tcp->pid,PT_PSWADDR, &tcp->baddr) < 0)
1626 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001627#elif defined(HPPA)
1628 if (upeek(tcp->pid, PT_IAOQ0, &tcp->baddr) < 0)
1629 return -1;
1630 tcp->baddr &= ~0x03;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001631#elif defined(SH)
1632 if (upeek(tcp->pid, 4*REG_PC, &tcp->baddr) < 0)
1633 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001634#else
1635#error unknown architecture
1636#endif
1637 if (debug)
1638 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1639 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1640 if (errno) {
1641 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1642 return -1;
1643 }
1644 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1645 if (errno) {
1646 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1647 return -1;
1648 }
1649 tcp->flags |= TCB_BPTSET;
1650
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001651#endif /* !IA64 */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001652#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653#endif /* LINUX */
1654
1655#ifdef SUNOS4
1656#ifdef SPARC /* This code is slightly sparc specific */
1657
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001658 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001659#define BPT 0x91d02001 /* ta 1 */
1660#define LOOP 0x10800000 /* ba 0 */
1661#define LOOPA 0x30800000 /* ba,a 0 */
1662#define NOP 0x01000000
1663#if LOOPA
1664 static int loopdeloop[1] = {LOOPA};
1665#else
1666 static int loopdeloop[2] = {LOOP, NOP};
1667#endif
1668
1669 if (tcp->flags & TCB_BPTSET) {
1670 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1671 return -1;
1672 }
1673 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1674 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1675 return -1;
1676 }
1677 tcp->baddr = regs.r_o7 + 8;
1678 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1679 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1680 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1681 return -1;
1682 }
1683
1684 /*
1685 * XXX - BRUTAL MODE ON
1686 * We cannot set a real BPT in the child, since it will not be
1687 * traced at the moment it will reach the trap and would probably
1688 * die with a core dump.
1689 * Thus, we are force our way in by taking out two instructions
1690 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1691 * generated by out PTRACE_ATTACH.
1692 * Of cause, if we evaporate ourselves in the middle of all this...
1693 */
1694 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1695 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1696 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1697 return -1;
1698 }
1699 tcp->flags |= TCB_BPTSET;
1700
1701#endif /* SPARC */
1702#endif /* SUNOS4 */
1703
1704 return 0;
1705}
1706
1707int
1708clearbpt(tcp)
1709struct tcb *tcp;
1710{
1711
1712#ifdef LINUX
Michal Ludvig0e035502002-09-23 15:41:01 +00001713#if defined(I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001714 long eip;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001715#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001717#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001718 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001719#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001720 long pc;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001721#elif defined(HPPA)
1722 long iaoq;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001723#elif defined(SH)
1724 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001725#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001726
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001727#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728 /* Again, we borrow the SunOS breakpoint code. */
1729 if (!(tcp->flags & TCB_BPTSET)) {
1730 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1731 return -1;
1732 }
1733 errno = 0;
1734 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1735 if(errno) {
1736 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1737 return -1;
1738 }
1739 tcp->flags &= ~TCB_BPTSET;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001740#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001741 if (ia32) {
1742 unsigned long addr;
1743
1744 if (debug)
1745 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1746 if (!(tcp->flags & TCB_BPTSET)) {
1747 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1748 return -1;
1749 }
1750 errno = 0;
1751 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1752 if (errno) {
1753 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1754 return -1;
1755 }
1756 tcp->flags &= ~TCB_BPTSET;
1757
1758 if (upeek(tcp->pid, PT_CR_IIP, &addr) < 0)
1759 return -1;
1760 if (addr != tcp->baddr) {
1761 /* The breakpoint has not been reached yet. */
1762 if (debug)
1763 fprintf(stderr,
1764 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1765 addr, tcp->baddr);
1766 return 0;
1767 }
1768 } else {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001769 unsigned long addr, ipsr;
1770 pid_t pid;
1771
1772 pid = tcp->pid;
1773
1774 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1775 return -1;
1776 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1777 return -1;
1778
1779 /* restore original bundle: */
1780 errno = 0;
1781 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
1782 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
1783 if (errno) {
1784 perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
1785 return -1;
1786 }
1787
1788 /* restore original "ri" in ipsr: */
1789 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
1790 errno = 0;
1791 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
1792 if (errno) {
1793 perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
1794 return -1;
1795 }
1796
1797 tcp->flags &= ~TCB_BPTSET;
1798
1799 if (addr != (tcp->baddr & ~0x3)) {
1800 /* the breakpoint has not been reached yet. */
1801 if (debug)
1802 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1803 addr, tcp->baddr);
1804 return 0;
1805 }
1806 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001807#else /* !IA64 && !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001808
1809 if (debug)
1810 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1811 if (!(tcp->flags & TCB_BPTSET)) {
1812 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1813 return -1;
1814 }
1815 errno = 0;
1816 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1817 if (errno) {
1818 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1819 return -1;
1820 }
1821 tcp->flags &= ~TCB_BPTSET;
1822
1823#ifdef I386
1824 if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1825 return -1;
1826 if (eip != tcp->baddr) {
1827 /* The breakpoint has not been reached yet. */
1828 if (debug)
1829 fprintf(stderr,
1830 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1831 eip, tcp->baddr);
1832 return 0;
1833 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001834#elif defined(X86_64)
1835 if (upeek(tcp->pid, 8*RIP, &eip) < 0)
1836 return -1;
1837 if (eip != tcp->baddr) {
1838 /* The breakpoint has not been reached yet. */
1839 if (debug)
1840 fprintf(stderr,
1841 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1842 eip, tcp->baddr);
1843 return 0;
1844 }
Wichert Akkermanc7926982000-04-10 22:22:31 +00001845#elif defined(POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001846 if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001847 return -1;
1848 if (pc != tcp->baddr) {
1849 /* The breakpoint has not been reached yet. */
1850 if (debug)
1851 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1852 pc, tcp->baddr);
1853 return 0;
1854 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001855#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001856 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1857 return -1;
1858 if (pc != tcp->baddr) {
1859 /* The breakpoint has not been reached yet. */
1860 if (debug)
1861 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1862 pc, tcp->baddr);
1863 return 0;
1864 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001865#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001866 if (upeek(tcp->pid, REG_PC, &pc) < 0)
1867 return -1;
1868 if (pc != tcp->baddr) {
1869 /* The breakpoint has not been reached yet. */
1870 if (debug)
1871 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1872 pc, tcp->baddr);
1873 return 0;
1874 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001875#elif defined(HPPA)
1876 if (upeek(tcp->pid, PT_IAOQ0, &iaoq) < 0)
1877 return -1;
1878 iaoq &= ~0x03;
1879 if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
1880 /* The breakpoint has not been reached yet. */
1881 if (debug)
1882 fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
1883 iaoq, tcp->baddr);
1884 return 0;
1885 }
1886 iaoq = tcp->baddr | 3;
1887 /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
1888 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
1889 * has no significant effect.
1890 */
1891 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
1892 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001893#elif defined(SH)
1894 if (upeek(tcp->pid, 4*REG_PC, &pc) < 0)
1895 return -1;
1896 if (pc != tcp->baddr) {
1897 /* The breakpoint has not been reached yet. */
1898 if (debug)
1899 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1900 pc, tcp->baddr);
1901 return 0;
1902 }
1903
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001904#endif /* arch */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001905#endif /* !SPARC && !SPARC64 && !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001906#endif /* LINUX */
1907
1908#ifdef SUNOS4
1909#ifdef SPARC
1910
1911#if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001912 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001913#endif
1914
1915 if (!(tcp->flags & TCB_BPTSET)) {
1916 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1917 return -1;
1918 }
1919 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1920 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1921 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1922 return -1;
1923 }
1924 tcp->flags &= ~TCB_BPTSET;
1925
1926#if !LOOPA
1927 /*
1928 * Since we don't have a single instruction breakpoint, we may have
1929 * to adjust the program counter after removing the our `breakpoint'.
1930 */
1931 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1932 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1933 return -1;
1934 }
1935 if ((regs.r_pc < tcp->baddr) ||
1936 (regs.r_pc > tcp->baddr + 4)) {
1937 /* The breakpoint has not been reached yet */
1938 if (debug)
1939 fprintf(stderr,
1940 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1941 regs.r_pc, tcp->parent->baddr);
1942 return 0;
1943 }
1944 if (regs.r_pc != tcp->baddr)
1945 if (debug)
1946 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1947 regs.r_pc, tcp->baddr);
1948
1949 regs.r_pc = tcp->baddr;
1950 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1951 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1952 return -1;
1953 }
1954#endif /* LOOPA */
1955#endif /* SPARC */
1956#endif /* SUNOS4 */
1957
1958 return 0;
1959}
1960
Roland McGrathd81f1d92003-01-09 06:53:34 +00001961#endif
1962
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001963#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001964
1965#ifdef SUNOS4
1966
1967static int
1968getex(pid, hdr)
1969int pid;
1970struct exec *hdr;
1971{
1972 int n;
1973
1974 for (n = 0; n < sizeof *hdr; n += 4) {
1975 long res;
1976 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
1977 return -1;
1978 memcpy(((char *) hdr) + n, &res, 4);
1979 }
1980 if (debug) {
1981 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1982 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1983 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1984 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1985 }
1986 return 0;
1987}
1988
1989int
1990fixvfork(tcp)
1991struct tcb *tcp;
1992{
1993 int pid = tcp->pid;
1994 /*
1995 * Change `vfork' in a freshly exec'ed dynamically linked
1996 * executable's (internal) symbol table to plain old `fork'
1997 */
1998
1999 struct exec hdr;
2000 struct link_dynamic dyn;
2001 struct link_dynamic_2 ld;
2002 char *strtab, *cp;
2003
2004 if (getex(pid, &hdr) < 0)
2005 return -1;
2006 if (!hdr.a_dynamic)
2007 return -1;
2008
2009 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
2010 fprintf(stderr, "Cannot read DYNAMIC\n");
2011 return -1;
2012 }
2013 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
2014 fprintf(stderr, "Cannot read link_dynamic_2\n");
2015 return -1;
2016 }
2017 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
2018 fprintf(stderr, "fixvfork: out of memory\n");
2019 return -1;
2020 }
2021 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
2022 (int)ld.ld_symb_size, strtab) < 0)
2023 goto err;
2024
2025#if 0
2026 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2027 fprintf(stderr, "[symbol: %s]\n", cp);
2028 cp += strlen(cp)+1;
2029 }
2030 return 0;
2031#endif
2032 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2033 if (strcmp(cp, "_vfork") == 0) {
2034 if (debug)
2035 fprintf(stderr, "fixvfork: FOUND _vfork\n");
2036 strcpy(cp, "_fork");
2037 break;
2038 }
2039 cp += strlen(cp)+1;
2040 }
2041 if (cp < strtab + ld.ld_symb_size)
2042 /*
2043 * Write entire symbol table back to avoid
2044 * memory alignment bugs in ptrace
2045 */
2046 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
2047 (int)ld.ld_symb_size, strtab) < 0)
2048 goto err;
2049
2050 free(strtab);
2051 return 0;
2052
2053err:
2054 free(strtab);
2055 return -1;
2056}
2057
2058#endif /* SUNOS4 */