blob: d64dd840f1337f335e6cc6aabb36dd93b41e1a33 [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
Roland McGratha4d48532005-06-08 20:45:28 +0000151#if 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152void
153tv_tv(tv, a, b)
154struct timeval *tv;
155int a;
156int b;
157{
158 tv->tv_sec = a;
159 tv->tv_usec = b;
160}
Roland McGratha4d48532005-06-08 20:45:28 +0000161#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000162
163int
164tv_nz(a)
165struct timeval *a;
166{
167 return a->tv_sec || a->tv_usec;
168}
169
170int
171tv_cmp(a, b)
172struct timeval *a, *b;
173{
174 if (a->tv_sec < b->tv_sec
175 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
176 return -1;
177 if (a->tv_sec > b->tv_sec
178 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
179 return 1;
180 return 0;
181}
182
183double
184tv_float(tv)
185struct timeval *tv;
186{
187 return tv->tv_sec + tv->tv_usec/1000000.0;
188}
189
190void
191tv_add(tv, a, b)
192struct timeval *tv, *a, *b;
193{
194 tv->tv_sec = a->tv_sec + b->tv_sec;
195 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000196 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000197 tv->tv_sec++;
198 tv->tv_usec -= 1000000;
199 }
200}
201
202void
203tv_sub(tv, a, b)
204struct timeval *tv, *a, *b;
205{
206 tv->tv_sec = a->tv_sec - b->tv_sec;
207 tv->tv_usec = a->tv_usec - b->tv_usec;
208 if (((long) tv->tv_usec) < 0) {
209 tv->tv_sec--;
210 tv->tv_usec += 1000000;
211 }
212}
213
214void
215tv_div(tv, a, n)
216struct timeval *tv, *a;
217int n;
218{
219 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
220 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
221 tv->tv_usec %= 1000000;
222}
223
224void
225tv_mul(tv, a, n)
226struct timeval *tv, *a;
227int n;
228{
229 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000230 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000231 tv->tv_usec %= 1000000;
232}
233
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000234const char *
235xlookup(const struct xlat *xlat, int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000236{
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
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000247printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000248{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000249 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000250
251 if (str)
252 tprintf("%s", str);
253 else
254 tprintf("%#x /* %s */", val, dflt);
255}
256
257/*
258 * Interpret `xlat' as an array of flags
259 * print the entries whose bits are on in `flags'
260 * return # of flags printed.
261 */
262int
263addflags(xlat, flags)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000264const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000265int flags;
266{
267 int n;
268
269 for (n = 0; xlat->str; xlat++) {
270 if (xlat->val && (flags & xlat->val) == xlat->val) {
271 tprintf("|%s", xlat->str);
272 flags &= ~xlat->val;
273 n++;
274 }
275 }
276 if (flags) {
277 tprintf("|%#x", flags);
278 n++;
279 }
280 return n;
281}
282
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000283/*
284 * Interpret `xlat' as an array of flags/
285 * Print to static string the entries whose bits are on in `flags'
286 * Return static string.
287 */
288const char *
289sprintflags(const char *prefix, const struct xlat *xlat, int flags)
290{
291 static char outstr[1024];
292 int found = 0;
293
294 strcpy(outstr, prefix);
295
296 for (; xlat->str; xlat++) {
297 if ((flags & xlat->val) == xlat->val) {
298 if (found)
299 strcat(outstr, "|");
300 strcat(outstr, xlat->str);
301 flags &= ~xlat->val;
302 found = 1;
303 }
304 }
305 if (flags) {
306 if (found)
307 strcat(outstr, "|");
308 sprintf(outstr + strlen(outstr), "%#x", flags);
309 }
310
311 return outstr;
312}
313
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000314int
Roland McGrathb2dee132005-06-01 19:02:36 +0000315printflags(xlat, flags, dflt)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000316const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000317int flags;
Roland McGrathb2dee132005-06-01 19:02:36 +0000318const char *dflt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000319{
320 int n;
321 char *sep;
322
323 if (flags == 0 && xlat->val == 0) {
324 tprintf("%s", xlat->str);
325 return 1;
326 }
327
328 sep = "";
329 for (n = 0; xlat->str; xlat++) {
330 if (xlat->val && (flags & xlat->val) == xlat->val) {
331 tprintf("%s%s", sep, xlat->str);
332 flags &= ~xlat->val;
333 sep = "|";
334 n++;
335 }
336 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000337
338 if (n) {
339 if (flags) {
340 tprintf("%s%#x", sep, flags);
341 n++;
342 }
343 } else {
344 if (flags) {
345 tprintf("%#x", flags);
346 if (dflt)
347 tprintf(" /* %s */", dflt);
348 } else {
349 if (dflt)
350 tprintf("0");
351 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000352 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000353
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000354 return n;
355}
356
357void
358printnum(tcp, addr, fmt)
359struct tcb *tcp;
360long addr;
361char *fmt;
362{
Roland McGratheb285352003-01-14 09:59:00 +0000363 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000364
365 if (!addr) {
366 tprintf("NULL");
367 return;
368 }
369 if (umove(tcp, addr, &num) < 0) {
370 tprintf("%#lx", addr);
371 return;
372 }
373 tprintf("[");
374 tprintf(fmt, num);
375 tprintf("]");
376}
377
Roland McGrath6bc12202003-11-13 22:32:27 +0000378void
Roland McGrath9814a942005-07-04 23:28:10 +0000379printnum_int(tcp, addr, fmt)
380struct tcb *tcp;
381long addr;
382char *fmt;
383{
384 int num;
385
386 if (!addr) {
387 tprintf("NULL");
388 return;
389 }
390 if (umove(tcp, addr, &num) < 0) {
391 tprintf("%#lx", addr);
392 return;
393 }
394 tprintf("[");
395 tprintf(fmt, num);
396 tprintf("]");
397}
398
399void
Roland McGrath6bc12202003-11-13 22:32:27 +0000400printuid(text, uid)
401const char *text;
402unsigned long uid;
403{
404 tprintf("%s", text);
405 tprintf((uid == -1) ? "%ld" : "%lu", uid);
406}
407
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000408static char path[MAXPATHLEN + 1];
409
Dmitry V. Levina501f142008-11-10 23:19:13 +0000410/*
411 * Quote string `instr' of length `size'
412 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
413 * If `len' < 0, treat `instr' as a NUL-terminated string
414 * and quote at most (`size' - 1) bytes.
415 */
Roland McGrath6d970322007-11-01 23:53:59 +0000416static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000417string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000418{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000419 const unsigned char *ustr = (const unsigned char *) instr;
420 char *s = outstr;
421 int usehex = 0, c, i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000422
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000423 if (xflag > 1)
424 usehex = 1;
425 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000426 /* Check for presence of symbol which require
427 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000428 for (i = 0; i < size; ++i) {
429 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000430 /* Check for NUL-terminated string. */
431 if (len < 0) {
432 if (c == '\0')
433 break;
434 /* Quote at most size - 1 bytes. */
435 if (i == size - 1)
436 continue;
437 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000438 if (!isprint(c) && !isspace(c)) {
439 usehex = 1;
440 break;
441 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000442 }
443 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000444
445 *s++ = '\"';
446
447 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000448 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000449 for (i = 0; i < size; ++i) {
450 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000451 /* Check for NUL-terminated string. */
452 if (len < 0) {
453 if (c == '\0')
454 break;
455 /* Quote at most size - 1 bytes. */
456 if (i == size - 1)
457 continue;
458 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000459 sprintf(s, "\\x%02x", c);
460 s += 4;
461 }
462 } else {
463 for (i = 0; i < size; ++i) {
464 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000465 /* Check for NUL-terminated string. */
466 if (len < 0) {
467 if (c == '\0')
468 break;
469 /* Quote at most size - 1 bytes. */
470 if (i == size - 1)
471 continue;
472 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000473 switch (c) {
474 case '\"': case '\\':
475 *s++ = '\\';
476 *s++ = c;
477 break;
478 case '\f':
479 *s++ = '\\';
480 *s++ = 'f';
481 break;
482 case '\n':
483 *s++ = '\\';
484 *s++ = 'n';
485 break;
486 case '\r':
487 *s++ = '\\';
488 *s++ = 'r';
489 break;
490 case '\t':
491 *s++ = '\\';
492 *s++ = 't';
493 break;
494 case '\v':
495 *s++ = '\\';
496 *s++ = 'v';
497 break;
498 default:
499 if (isprint(c))
500 *s++ = c;
501 else if (i + 1 < size
502 && isdigit(ustr[i + 1])) {
503 sprintf(s, "\\%03o", c);
504 s += 4;
505 } else {
506 sprintf(s, "\\%o", c);
507 s += strlen(s);
508 }
509 break;
510 }
511 }
512 }
513
514 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000515 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000516
517 /* Return nonzero if the string was unterminated. */
518 return i == size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000519}
520
Dmitry V. Levina501f142008-11-10 23:19:13 +0000521/*
522 * Print path string specified by address `addr' and length `n'.
523 * If path length exceeds `n', append `...' to the output.
524 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000525void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000526printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000527{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000528 if (!addr) {
Roland McGrath371ed8f2005-02-06 01:55:07 +0000529 tprintf("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000530 return;
531 }
532
Dmitry V. Levina501f142008-11-10 23:19:13 +0000533 /* Cap path length to the path buffer size,
534 and NUL-terminate the buffer. */
535 if (n > sizeof path - 1)
536 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000537 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000538
539 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000540 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000541 tprintf("%#lx", addr);
542 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000543 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
544 int trunc = (path[n] != '\0');
545
546 if (trunc)
547 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000548 (void) string_quote(path, outstr, -1, n + 1);
549 if (trunc)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000550 strcat(outstr, "...");
551 tprintf("%s", outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000552 }
553}
554
555void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000556printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000557{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000558 printpathn(tcp, addr, sizeof path - 1);
559}
560
Dmitry V. Levina501f142008-11-10 23:19:13 +0000561/*
562 * Print string specified by address `addr' and length `len'.
563 * If `len' < 0, treat the string as a NUL-terminated string.
564 * If string length exceeds `max_strlen', append `...' to the output.
565 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000566void
567printstr(struct tcb *tcp, long addr, int len)
568{
569 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000570 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000571 int size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000572
573 if (!addr) {
574 tprintf("NULL");
575 return;
576 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000577 /* Allocate static buffers if they are not allocated yet. */
578 if (!str)
579 str = malloc(max_strlen + 1);
580 if (!outstr)
581 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
582 if (!str || !outstr) {
583 fprintf(stderr, "out of memory\n");
584 tprintf("%#lx", addr);
585 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000586 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000587
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000588 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000589 /*
590 * Treat as a NUL-terminated string: fetch one byte more
591 * because string_quote() quotes one byte less.
592 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000593 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000594 str[max_strlen] = '\0';
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000595 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000596 tprintf("%#lx", addr);
597 return;
598 }
599 }
600 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000601 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000602 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000603 tprintf("%#lx", addr);
604 return;
605 }
606 }
607
Dmitry V. Levina501f142008-11-10 23:19:13 +0000608 if (string_quote(str, outstr, len, size) &&
609 (len < 0 || len > max_strlen))
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000610 strcat(outstr, "...");
Roland McGratha503dcf2007-08-02 02:06:26 +0000611
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612 tprintf("%s", outstr);
613}
614
John Hughes1d08dcf2001-07-10 13:48:44 +0000615#if HAVE_SYS_UIO_H
616void
617dumpiov(tcp, len, addr)
618struct tcb * tcp;
619int len;
620long addr;
621{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000622#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
623 union {
624 struct { u_int32_t base; u_int32_t len; } *iov32;
625 struct { u_int64_t base; u_int64_t len; } *iov64;
626 } iovu;
627#define iov iovu.iov64
628#define sizeof_iov \
629 (personality_wordsize[current_personality] == 4 \
630 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
631#define iov_iov_base(i) \
632 (personality_wordsize[current_personality] == 4 \
633 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
634#define iov_iov_len(i) \
635 (personality_wordsize[current_personality] == 4 \
636 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
637#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000638 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000639#define sizeof_iov sizeof(*iov)
640#define iov_iov_base(i) iov[i].iov_base
641#define iov_iov_len(i) iov[i].iov_len
642#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000643 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000644 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000645
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000646 size = sizeof_iov * (unsigned long) len;
647 if (size / sizeof_iov != len
648 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000649 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000650 return;
651 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000652 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000653 for (i = 0; i < len; i++) {
654 /* include the buffer number to make it easy to
655 * match up the trace with the source */
656 tprintf(" * %lu bytes in buffer %d\n",
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000657 (unsigned long)iov_iov_len(i), i);
658 dumpstr(tcp, (long) iov_iov_base(i),
659 iov_iov_len(i));
John Hughes1d08dcf2001-07-10 13:48:44 +0000660 }
661 }
662 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000663#undef sizeof_iov
664#undef iov_iov_base
665#undef iov_iov_len
666#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000667}
668#endif
669
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000670void
671dumpstr(tcp, addr, len)
672struct tcb *tcp;
673long addr;
674int len;
675{
676 static int strsize = -1;
677 static unsigned char *str;
678 static char outstr[80];
679 char *s;
680 int i, j;
681
682 if (strsize < len) {
683 if (str)
684 free(str);
685 if ((str = malloc(len)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000686 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000687 return;
688 }
689 strsize = len;
690 }
691
692 if (umoven(tcp, addr, len, (char *) str) < 0)
693 return;
694
695 for (i = 0; i < len; i += 16) {
696 s = outstr;
697 sprintf(s, " | %05x ", i);
698 s += 9;
699 for (j = 0; j < 16; j++) {
700 if (j == 8)
701 *s++ = ' ';
702 if (i + j < len) {
703 sprintf(s, " %02x", str[i + j]);
704 s += 3;
705 }
706 else {
707 *s++ = ' '; *s++ = ' '; *s++ = ' ';
708 }
709 }
710 *s++ = ' '; *s++ = ' ';
711 for (j = 0; j < 16; j++) {
712 if (j == 8)
713 *s++ = ' ';
714 if (i + j < len) {
715 if (isprint(str[i + j]))
716 *s++ = str[i + j];
717 else
718 *s++ = '.';
719 }
720 else
721 *s++ = ' ';
722 }
723 tprintf("%s |\n", outstr);
724 }
725}
726
727#define PAGMASK (~(PAGSIZ - 1))
728/*
729 * move `len' bytes of data from process `pid'
730 * at address `addr' to our space at `laddr'
731 */
732int
733umoven(tcp, addr, len, laddr)
734struct tcb *tcp;
735long addr;
736int len;
737char *laddr;
738{
739
740#ifdef LINUX
741 int pid = tcp->pid;
742 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000743 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000744 union {
745 long val;
746 char x[sizeof(long)];
747 } u;
748
749 if (addr & (sizeof(long) - 1)) {
750 /* addr not a multiple of sizeof(long) */
751 n = addr - (addr & -sizeof(long)); /* residue */
752 addr &= -sizeof(long); /* residue */
753 errno = 0;
754 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
755 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000756 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000757 /* Ran into 'end of memory' - stupid "printpath" */
758 return 0;
759 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000760 /* But if not started, we had a bogus address. */
Roland McGrath1c459762007-08-02 02:22:06 +0000761 if (addr != 0 && errno != EIO)
762 perror("ptrace: umoven");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763 return -1;
764 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000765 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000766 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
767 addr += sizeof(long), laddr += m, len -= m;
768 }
769 while (len) {
770 errno = 0;
771 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
772 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000773 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000774 /* Ran into 'end of memory' - stupid "printpath" */
775 return 0;
776 }
Roland McGrath1c459762007-08-02 02:22:06 +0000777 if (addr != 0 && errno != EIO)
Roland McGrath4db26242003-01-30 20:15:19 +0000778 perror("ptrace: umoven");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000779 return -1;
780 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000781 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000782 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
783 addr += sizeof(long), laddr += m, len -= m;
784 }
785#endif /* LINUX */
786
787#ifdef SUNOS4
788 int pid = tcp->pid;
789#if 0
790 int n, m;
791 union {
792 long val;
793 char x[sizeof(long)];
794 } u;
795
796 if (addr & (sizeof(long) - 1)) {
797 /* addr not a multiple of sizeof(long) */
798 n = addr - (addr & -sizeof(long)); /* residue */
799 addr &= -sizeof(long); /* residue */
800 errno = 0;
801 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
802 if (errno) {
803 perror("umoven");
804 return -1;
805 }
806 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
807 addr += sizeof(long), laddr += m, len -= m;
808 }
809 while (len) {
810 errno = 0;
811 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
812 if (errno) {
813 perror("umoven");
814 return -1;
815 }
816 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
817 addr += sizeof(long), laddr += m, len -= m;
818 }
819#else /* !oldway */
820 int n;
821
822 while (len) {
823 n = MIN(len, PAGSIZ);
824 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
825 if (ptrace(PTRACE_READDATA, pid,
826 (char *) addr, len, laddr) < 0) {
827 perror("umoven: ptrace(PTRACE_READDATA, ...)");
828 abort();
829 return -1;
830 }
831 len -= n;
832 addr += n;
833 laddr += n;
834 }
835#endif /* !oldway */
836#endif /* SUNOS4 */
837
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000838#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000839#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000840 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000841#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000842 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000843#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000844 lseek(fd, addr, SEEK_SET);
845 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000846 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000847#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000848
849 return 0;
850}
851
852/*
853 * like `umove' but make the additional effort of looking
854 * for a terminating zero byte.
855 */
856int
857umovestr(tcp, addr, len, laddr)
858struct tcb *tcp;
859long addr;
860int len;
861char *laddr;
862{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000863#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000864#ifdef HAVE_MP_PROCFS
865 int fd = tcp->pfd_as;
866#else
867 int fd = tcp->pfd;
868#endif
869 /* Some systems (e.g. FreeBSD) can be upset if we read off the
870 end of valid memory, avoid this by trying to read up
871 to page boundaries. But we don't know what a page is (and
872 getpagesize(2) (if it exists) doesn't necessarily return
873 hardware page size). Assume all pages >= 1024 (a-historical
874 I know) */
875
876 int page = 1024; /* How to find this? */
877 int move = page - (addr & (page - 1));
878 int left = len;
879
880 lseek(fd, addr, SEEK_SET);
881
882 while (left) {
883 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000884 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000885 return left != len ? 0 : -1;
886 if (memchr (laddr, 0, move)) break;
887 left -= move;
888 laddr += move;
889 addr += move;
890 move = page;
891 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000892#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000893 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894 int pid = tcp->pid;
895 int i, n, m;
896 union {
897 long val;
898 char x[sizeof(long)];
899 } u;
900
901 if (addr & (sizeof(long) - 1)) {
902 /* addr not a multiple of sizeof(long) */
903 n = addr - (addr & -sizeof(long)); /* residue */
904 addr &= -sizeof(long); /* residue */
905 errno = 0;
906 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
907 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000908 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000909 /* Ran into 'end of memory' - stupid "printpath" */
910 return 0;
911 }
Roland McGrath1c459762007-08-02 02:22:06 +0000912 if (addr != 0 && errno != EIO)
913 perror("umovestr");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000914 return -1;
915 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000916 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000917 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
918 while (n & (sizeof(long) - 1))
919 if (u.x[n++] == '\0')
920 return 0;
921 addr += sizeof(long), laddr += m, len -= m;
922 }
923 while (len) {
924 errno = 0;
925 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
926 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000927 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000928 /* Ran into 'end of memory' - stupid "printpath" */
929 return 0;
930 }
Roland McGrath1c459762007-08-02 02:22:06 +0000931 if (addr != 0 && errno != EIO)
932 perror("umovestr");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000933 return -1;
934 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000935 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000936 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
937 for (i = 0; i < sizeof(long); i++)
938 if (u.x[i] == '\0')
939 return 0;
940
941 addr += sizeof(long), laddr += m, len -= m;
942 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000943#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000944 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000945}
946
947#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000948#if !defined (SPARC) && !defined(SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000949#define PTRACE_WRITETEXT 101
950#define PTRACE_WRITEDATA 102
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000951#endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000952#endif /* LINUX */
953
954#ifdef SUNOS4
955
956static int
957uload(cmd, pid, addr, len, laddr)
958int cmd;
959int pid;
960long addr;
961int len;
962char *laddr;
963{
964#if 0
965 int n;
966
967 while (len) {
968 n = MIN(len, PAGSIZ);
969 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
970 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
971 perror("uload: ptrace(PTRACE_WRITE, ...)");
972 return -1;
973 }
974 len -= n;
975 addr += n;
976 laddr += n;
977 }
978#else
979 int peek, poke;
980 int n, m;
981 union {
982 long val;
983 char x[sizeof(long)];
984 } u;
985
986 if (cmd == PTRACE_WRITETEXT) {
987 peek = PTRACE_PEEKTEXT;
988 poke = PTRACE_POKETEXT;
989 }
990 else {
991 peek = PTRACE_PEEKDATA;
992 poke = PTRACE_POKEDATA;
993 }
994 if (addr & (sizeof(long) - 1)) {
995 /* addr not a multiple of sizeof(long) */
996 n = addr - (addr & -sizeof(long)); /* residue */
997 addr &= -sizeof(long);
998 errno = 0;
999 u.val = ptrace(peek, pid, (char *) addr, 0);
1000 if (errno) {
1001 perror("uload: POKE");
1002 return -1;
1003 }
1004 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
1005 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
1006 perror("uload: POKE");
1007 return -1;
1008 }
1009 addr += sizeof(long), laddr += m, len -= m;
1010 }
1011 while (len) {
1012 if (len < sizeof(long))
1013 u.val = ptrace(peek, pid, (char *) addr, 0);
1014 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
1015 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1016 perror("uload: POKE");
1017 return -1;
1018 }
1019 addr += sizeof(long), laddr += m, len -= m;
1020 }
1021#endif
1022 return 0;
1023}
1024
1025int
1026tload(pid, addr, len, laddr)
1027int pid;
1028int addr, len;
1029char *laddr;
1030{
1031 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1032}
1033
1034int
1035dload(pid, addr, len, laddr)
1036int pid;
1037int addr;
1038int len;
1039char *laddr;
1040{
1041 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
1042}
1043
1044#endif /* SUNOS4 */
1045
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001046#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001047
1048int
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001049upeek(tcp, off, res)
1050struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001051long off;
1052long *res;
1053{
1054 long val;
1055
1056#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
1057 {
1058 static int is_sun4m = -1;
1059 struct utsname name;
1060
1061 /* Round up the usual suspects. */
1062 if (is_sun4m == -1) {
1063 if (uname(&name) < 0) {
1064 perror("upeek: uname?");
1065 exit(1);
1066 }
1067 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1068 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001069 extern const struct xlat struct_user_offsets[];
1070 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001071
1072 for (x = struct_user_offsets; x->str; x++)
1073 x->val += 1024;
1074 }
1075 }
1076 if (is_sun4m)
1077 off += 1024;
1078 }
1079#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
1080 errno = 0;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001081 val = ptrace(PTRACE_PEEKUSER, tcp->pid, (char *) off, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082 if (val == -1 && errno) {
Roland McGrath1e85cf92002-12-16 20:40:54 +00001083 char buf[60];
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001084 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGrath1e85cf92002-12-16 20:40:54 +00001085 perror(buf);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086 return -1;
1087 }
1088 *res = val;
1089 return 0;
1090}
1091
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001092#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001093
Roland McGratha4d48532005-06-08 20:45:28 +00001094#if 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001095long
1096getpc(tcp)
1097struct tcb *tcp;
1098{
1099
1100#ifdef LINUX
1101 long pc;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001102#if defined(I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001103 if (upeek(tcp, 4*EIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001104 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00001105#elif defined(X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001106 if (upeek(tcp, 8*RIP, &pc) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001107 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001108#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001109 if (upeek(tcp, PT_B0, &pc) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001110 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001111#elif defined(ARM)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001112 if (upeek(tcp, 4*15, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001113 return -1;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001114#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001115 if (upeek(tcp, REG_PC, &pc) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001116 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001117#elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001118 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001119 return -1;
Roland McGrath84fa9232005-06-08 18:06:22 +00001120#elif defined(M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001121 if (upeek(tcp, 4*PT_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001123#elif defined(ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001124 if (upeek(tcp, REG_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001125 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001126#elif defined(MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001127 if (upeek(tcp, REG_EPC, &pc) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001128 return -1;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001129#elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001130 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
1132 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001133 pc = regs.r_pc;
Michal Ludvig10a88d02002-10-07 14:31:00 +00001134#elif defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001135 if(upeek(tcp,PT_PSWADDR,&pc) < 0)
Michal Ludvig10a88d02002-10-07 14:31:00 +00001136 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001137#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001138 if(upeek(tcp,PT_IAOQ0,&pc) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001139 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001140#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001141 if (upeek(tcp, 4*REG_PC ,&pc) < 0)
Wichert Akkermanccef6372002-05-01 16:39:22 +00001142 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001143#elif defined(SH64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001144 if (upeek(tcp, REG_PC ,&pc) < 0)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001145 return -1;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +00001146#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001147 return pc;
1148#endif /* LINUX */
1149
1150#ifdef SUNOS4
1151 /*
1152 * Return current program counter for `pid'
1153 * Assumes PC is never 0xffffffff
1154 */
1155 struct regs regs;
1156
1157 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1158 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
1159 return -1;
1160 }
1161 return regs.r_pc;
1162#endif /* SUNOS4 */
1163
1164#ifdef SVR4
1165 /* XXX */
1166 return 0;
1167#endif /* SVR4 */
1168
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001169#ifdef FREEBSD
1170 struct reg regs;
1171 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1172 return regs.r_eip;
1173#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001174}
Roland McGratha4d48532005-06-08 20:45:28 +00001175#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176
1177void
1178printcall(tcp)
1179struct tcb *tcp;
1180{
Roland McGrath7a918832005-02-02 20:55:23 +00001181#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1182 sizeof(long) == 8 ? "[????????????????] " : \
1183 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184
1185#ifdef LINUX
1186#ifdef I386
1187 long eip;
1188
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001189 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001190 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191 return;
1192 }
1193 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001194
1195#elif defined(S390) || defined(S390X)
1196 long psw;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001197 if(upeek(tcp,PT_PSWADDR,&psw) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001198 PRINTBADPC;
Roland McGratheac26fc2005-02-02 02:48:53 +00001199 return;
1200 }
1201#ifdef S390
1202 tprintf("[%08lx] ", psw);
1203#elif S390X
1204 tprintf("[%16lx] ", psw);
1205#endif
1206
Michal Ludvig0e035502002-09-23 15:41:01 +00001207#elif defined(X86_64)
1208 long rip;
1209
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001210 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001211 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001212 return;
1213 }
1214 tprintf("[%16lx] ", rip);
Roland McGrathef388682003-06-03 23:28:59 +00001215#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001216 long ip;
1217
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001218 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001219 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001220 return;
1221 }
1222 tprintf("[%08lx] ", ip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001223#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224 long pc;
1225
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001226 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001227 tprintf ("[????????] ");
1228 return;
1229 }
1230 tprintf("[%08lx] ", pc);
Roland McGrath84fa9232005-06-08 18:06:22 +00001231#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001232 long pc;
1233
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001234 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235 tprintf ("[????????] ");
1236 return;
1237 }
1238 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001239#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001240 long pc;
1241
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001242 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001243 tprintf ("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001244 return;
1245 }
1246 tprintf("[%08lx] ", pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001247#elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001248 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001249 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001250 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251 return;
1252 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001253 tprintf("[%08lx] ", regs.r_pc);
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001254#elif defined(HPPA)
1255 long pc;
1256
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001257 if(upeek(tcp,PT_IAOQ0,&pc) < 0) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001258 tprintf ("[????????] ");
1259 return;
1260 }
1261 tprintf("[%08lx] ", pc);
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001262#elif defined(MIPS)
1263 long pc;
1264
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001265 if (upeek(tcp, REG_EPC, &pc) < 0) {
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001266 tprintf ("[????????] ");
1267 return;
1268 }
1269 tprintf("[%08lx] ", pc);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001270#elif defined(SH)
1271 long pc;
1272
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001273 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Wichert Akkermanccef6372002-05-01 16:39:22 +00001274 tprintf ("[????????] ");
1275 return;
1276 }
1277 tprintf("[%08lx] ", pc);
Roland McGrathf5a47772003-06-26 22:40:42 +00001278#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001279 long pc;
1280
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001281 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001282 tprintf ("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001283 return;
1284 }
1285 tprintf("[%08lx] ", pc);
Roland McGrathef388682003-06-03 23:28:59 +00001286#elif defined(ARM)
1287 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001288
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001289 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001290 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001291 return;
1292 }
1293 tprintf("[%08lx] ", pc);
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001294#elif defined(BFIN)
1295 long pc;
1296
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001297 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001298 PRINTBADPC;
1299 return;
1300 }
1301 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001302#endif /* !architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001303#endif /* LINUX */
1304
1305#ifdef SUNOS4
1306 struct regs regs;
1307
1308 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1309 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001310 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001311 return;
1312 }
1313 tprintf("[%08x] ", regs.r_o7);
1314#endif /* SUNOS4 */
1315
1316#ifdef SVR4
1317 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001318 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001319#endif
1320
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001321#ifdef FREEBSD
1322 struct reg regs;
1323 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1324 tprintf("[%08x] ", regs.r_eip);
1325#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001326}
1327
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001328#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329
Roland McGrathd81f1d92003-01-09 06:53:34 +00001330#if defined LINUX
1331
Roland McGrath3291ef22008-05-20 00:34:34 +00001332#include "syscall.h"
1333
Roland McGrathd81f1d92003-01-09 06:53:34 +00001334#include <sys/syscall.h>
1335#ifndef CLONE_PTRACE
1336# define CLONE_PTRACE 0x00002000
1337#endif
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001338#ifndef CLONE_VFORK
1339# define CLONE_VFORK 0x00004000
1340#endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001341#ifndef CLONE_VM
1342# define CLONE_VM 0x00000100
1343#endif
Roland McGrath76989d72005-06-07 23:21:31 +00001344#ifndef CLONE_STOPPED
1345# define CLONE_STOPPED 0x02000000
1346#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001347
1348#ifdef IA64
1349
Roland McGrath08267b82004-02-20 22:56:43 +00001350/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1351 subsystem has them for x86... */
1352#define SYS_fork 2
1353#define SYS_vfork 190
1354
Roland McGrathd81f1d92003-01-09 06:53:34 +00001355typedef unsigned long *arg_setup_state;
1356
1357static int
1358arg_setup(struct tcb *tcp, arg_setup_state *state)
1359{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001360 unsigned long cfm, sof, sol;
1361 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001362
Jan Kratochvil1f942712008-08-06 21:38:52 +00001363 if (ia32) {
1364 /* Satisfy a false GCC warning. */
1365 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001366 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001367 }
Roland McGrath08267b82004-02-20 22:56:43 +00001368
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001369 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001370 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001371 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001372 return -1;
1373
1374 sof = (cfm >> 0) & 0x7f;
1375 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001376 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001377
Jan Kratochvil1f942712008-08-06 21:38:52 +00001378 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001379 return 0;
1380}
1381
1382# define arg_finish_change(tcp, state) 0
1383
1384#ifdef SYS_fork
1385static int
1386get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1387{
Roland McGrath08267b82004-02-20 22:56:43 +00001388 int ret;
1389
1390 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001391 ret = upeek (tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001392 else
1393 ret = umoven (tcp,
1394 (unsigned long) ia64_rse_skip_regs(*state, 0),
1395 sizeof(long), (void *) valp);
1396 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001397}
1398
1399static int
1400get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1401{
Roland McGrath08267b82004-02-20 22:56:43 +00001402 int ret;
1403
1404 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001405 ret = upeek (tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001406 else
1407 ret = umoven (tcp,
1408 (unsigned long) ia64_rse_skip_regs(*state, 1),
1409 sizeof(long), (void *) valp);
1410 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001411}
1412#endif
1413
1414static int
1415set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1416{
Roland McGrath08267b82004-02-20 22:56:43 +00001417 int req = PTRACE_POKEDATA;
1418 void *ap;
1419
1420 if (ia32) {
1421 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1422 req = PTRACE_POKEUSER;
1423 } else
1424 ap = ia64_rse_skip_regs(*state, 0);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001425 errno = 0;
Roland McGrath08267b82004-02-20 22:56:43 +00001426 ptrace(req, tcp->pid, ap, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001427 return errno ? -1 : 0;
1428}
1429
1430static int
1431set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1432{
Roland McGrath08267b82004-02-20 22:56:43 +00001433 int req = PTRACE_POKEDATA;
1434 void *ap;
1435
1436 if (ia32) {
1437 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1438 req = PTRACE_POKEUSER;
1439 } else
1440 ap = ia64_rse_skip_regs(*state, 1);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001441 errno = 0;
Roland McGrath08267b82004-02-20 22:56:43 +00001442 ptrace(req, tcp->pid, ap, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001443 return errno ? -1 : 0;
1444}
1445
Roland McGrathb659f872008-07-18 01:19:36 +00001446/* ia64 does not return the input arguments from functions (and syscalls)
1447 according to ia64 RSE (Register Stack Engine) behavior. */
1448
1449# define restore_arg0(tcp, state, val) ((void) (state), 0)
1450# define restore_arg1(tcp, state, val) ((void) (state), 0)
1451
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001452#elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001453
1454typedef struct regs arg_setup_state;
1455
1456# define arg_setup(tcp, state) \
1457 (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
1458# define arg_finish_change(tcp, state) \
1459 (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
1460
1461# define get_arg0(tcp, state, valp) (*(valp) = (state)->r_o0, 0)
1462# define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0)
1463# define set_arg0(tcp, state, val) ((state)->r_o0 = (val), 0)
1464# define set_arg1(tcp, state, val) ((state)->r_o1 = (val), 0)
Roland McGrathe1df47f2003-01-14 09:46:15 +00001465# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001466
1467#else
1468
1469# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001470/* Note: this is only true for the `clone' system call, which handles
1471 arguments specially. We could as well say that its first two arguments
1472 are swapped relative to other architectures, but that would just be
1473 another #ifdef in the calls. */
1474# define arg0_offset PT_GPR3
1475# define arg1_offset PT_ORIGGPR2
1476# define restore_arg0(tcp, state, val) ((void) (state), 0)
1477# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001478# define arg0_index 1
1479# define arg1_index 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001480# elif defined (ALPHA) || defined (MIPS)
1481# define arg0_offset REG_A0
1482# define arg1_offset (REG_A0+1)
1483# elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001484# define arg0_offset (sizeof(unsigned long)*PT_R3)
1485# define arg1_offset (sizeof(unsigned long)*PT_R4)
Roland McGrath7b308222003-01-20 09:04:36 +00001486# define restore_arg0(tcp, state, val) ((void) (state), 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001487# elif defined (HPPA)
1488# define arg0_offset PT_GR26
1489# define arg1_offset (PT_GR26-4)
Roland McGrath7f33cc32003-01-10 20:51:00 +00001490# elif defined (X86_64)
1491# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1492# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
Roland McGrathac971c22003-03-31 01:03:33 +00001493# elif defined (SH)
1494# define arg0_offset (4*(REG_REG0+4))
1495# define arg1_offset (4*(REG_REG0+5))
Roland McGrathf5a47772003-06-26 22:40:42 +00001496# elif defined (SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001497 /* ABI defines arg0 & 1 in r2 & r3 */
1498# define arg0_offset (REG_OFFSET+16)
1499# define arg1_offset (REG_OFFSET+24)
1500# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001501# else
1502# define arg0_offset 0
1503# define arg1_offset 4
Roland McGrathac971c22003-03-31 01:03:33 +00001504# if defined ARM
Roland McGrathe1df47f2003-01-14 09:46:15 +00001505# define restore_arg0(tcp, state, val) 0
1506# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001507# endif
1508
1509typedef int arg_setup_state;
1510
1511# define arg_setup(tcp, state) (0)
1512# define arg_finish_change(tcp, state) 0
1513# define get_arg0(tcp, cookie, valp) \
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001514 (upeek ((tcp), arg0_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001515# define get_arg1(tcp, cookie, valp) \
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001516 (upeek ((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001517
1518static int
1519set_arg0 (struct tcb *tcp, void *cookie, long val)
1520{
Roland McGrathca85b972005-06-07 23:22:08 +00001521 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001522}
1523
1524static int
1525set_arg1 (struct tcb *tcp, void *cookie, long val)
1526{
1527 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
1528}
1529
1530#endif
1531
Roland McGrathe1df47f2003-01-14 09:46:15 +00001532#ifndef restore_arg0
1533# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1534#endif
1535#ifndef restore_arg1
1536# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1537#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001538
Roland McGrath90d0afd2004-03-01 21:05:16 +00001539#ifndef arg0_index
1540# define arg0_index 0
1541# define arg1_index 1
1542#endif
1543
Roland McGrathd81f1d92003-01-09 06:53:34 +00001544int
1545setbpt(tcp)
1546struct tcb *tcp;
1547{
Roland McGrath3291ef22008-05-20 00:34:34 +00001548 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001549 extern int change_syscall(struct tcb *, int);
1550 arg_setup_state state;
1551
1552 if (tcp->flags & TCB_BPTSET) {
1553 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1554 return -1;
1555 }
1556
Roland McGrath3291ef22008-05-20 00:34:34 +00001557 /*
1558 * It's a silly kludge to initialize this with a search at runtime.
1559 * But it's better than maintaining another magic thing in the
1560 * godforsaken tables.
1561 */
1562 if (clone_scno[current_personality] == 0) {
1563 int i;
1564 for (i = 0; i < nsyscalls; ++i)
1565 if (sysent[i].sys_func == sys_clone) {
1566 clone_scno[current_personality] = i;
1567 break;
1568 }
1569 }
1570
Roland McGrath76989d72005-06-07 23:21:31 +00001571 switch (known_scno(tcp)) {
Roland McGrath9383c6c2003-01-18 00:19:31 +00001572#ifdef SYS_vfork
1573 case SYS_vfork:
1574#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001575#ifdef SYS_fork
1576 case SYS_fork:
Roland McGrath9b0982b2003-01-18 00:21:51 +00001577#endif
1578#if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001579 if (arg_setup (tcp, &state) < 0
1580 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1581 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001582 || change_syscall(tcp, clone_scno[current_personality]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001583 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1584 || set_arg1 (tcp, &state, 0) < 0
1585 || arg_finish_change (tcp, &state) < 0)
1586 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001587 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1588 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001589 tcp->flags |= TCB_BPTSET;
1590 return 0;
1591#endif
1592
1593 case SYS_clone:
1594#ifdef SYS_clone2
1595 case SYS_clone2:
1596#endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001597 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1598 contrary to x86 SYS_vfork above. Even on x86 we turn the
1599 vfork semantics into plain fork - each application must not
1600 depend on the vfork specifics according to POSIX. We would
1601 hang waiting for the parent resume otherwise. We need to
1602 clear also CLONE_VM but only in the CLONE_VFORK case as
1603 otherwise we would break pthread_create. */
1604
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001605 if ((arg_setup (tcp, &state) < 0
1606 || set_arg0 (tcp, &state,
1607 (tcp->u_arg[arg0_index] | CLONE_PTRACE)
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001608 & ~(tcp->u_arg[arg0_index] & CLONE_VFORK
1609 ? CLONE_VFORK | CLONE_VM : 0)) < 0
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001610 || arg_finish_change (tcp, &state) < 0))
1611 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001612 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001613 tcp->inst[0] = tcp->u_arg[arg0_index];
1614 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001615 return 0;
1616
1617 default:
1618 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1619 tcp->scno, tcp->pid);
1620 break;
1621 }
1622
1623 return -1;
1624}
1625
1626int
1627clearbpt(tcp)
1628struct tcb *tcp;
1629{
1630 arg_setup_state state;
1631 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001632 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1633 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001634 || arg_finish_change (tcp, &state))
1635 return -1;
1636 tcp->flags &= ~TCB_BPTSET;
1637 return 0;
1638}
1639
1640#else
1641
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642int
1643setbpt(tcp)
1644struct tcb *tcp;
1645{
1646
1647#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001648#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001649 /* We simply use the SunOS breakpoint code. */
1650
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001651 struct regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001652 unsigned long inst;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653#define LOOPA 0x30800000 /* ba,a 0 */
1654
1655 if (tcp->flags & TCB_BPTSET) {
1656 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1657 return -1;
1658 }
1659 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1660 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1661 return -1;
1662 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001663 tcp->baddr = regs.r_o7 + 8;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664 errno = 0;
1665 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1666 if(errno) {
1667 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1668 return -1;
1669 }
1670
1671 /*
1672 * XXX - BRUTAL MODE ON
1673 * We cannot set a real BPT in the child, since it will not be
1674 * traced at the moment it will reach the trap and would probably
1675 * die with a core dump.
1676 * Thus, we are force our way in by taking out two instructions
1677 * and insert an eternal loop instead, in expectance of the SIGSTOP
1678 * generated by out PTRACE_ATTACH.
1679 * Of cause, if we evaporate ourselves in the middle of all this...
1680 */
1681 errno = 0;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001682 inst = LOOPA;
1683#if defined (SPARC64)
1684 inst <<= 32;
1685 inst |= (tcp->inst[0] & 0xffffffffUL);
1686#endif
1687 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, inst);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001688 if(errno) {
1689 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1690 return -1;
1691 }
1692 tcp->flags |= TCB_BPTSET;
1693
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001694#else /* !SPARC && !SPARC64 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001695#ifdef IA64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001696 if (ia32) {
1697# define LOOP 0x0000feeb
1698 if (tcp->flags & TCB_BPTSET) {
1699 fprintf(stderr, "PANIC: bpt already set in pid %u\n",
1700 tcp->pid);
1701 return -1;
1702 }
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001703 if (upeek(tcp, PT_CR_IIP, &tcp->baddr) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001704 return -1;
1705 if (debug)
1706 fprintf(stderr, "[%d] setting bpt at %lx\n",
1707 tcp->pid, tcp->baddr);
1708 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid,
1709 (char *) tcp->baddr, 0);
1710 if (errno) {
1711 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1712 return -1;
1713 }
1714 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1715 if (errno) {
1716 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1717 return -1;
1718 }
1719 tcp->flags |= TCB_BPTSET;
1720 } else {
1721 /*
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001722 * Our strategy here is to replace the bundle that
1723 * contained the clone() syscall with a bundle of the
1724 * form:
1725 *
1726 * { 1: br 1b; br 1b; br 1b }
1727 *
1728 * This ensures that the newly forked child will loop
1729 * endlessly until we've got a chance to attach to it.
1730 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001731# define LOOP0 0x0000100000000017
1732# define LOOP1 0x4000000000200000
1733 unsigned long addr, ipsr;
1734 pid_t pid;
1735
1736 pid = tcp->pid;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001737 if (upeek(tcp, PT_CR_IPSR, &ipsr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001738 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001739 if (upeek(tcp, PT_CR_IIP, &addr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001740 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001741 /* store "ri" in low two bits */
1742 tcp->baddr = addr | ((ipsr >> 41) & 0x3);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001743
1744 errno = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001745 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0,
1746 0);
1747 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8,
1748 0);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001749 if (errno) {
1750 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1751 return -1;
1752 }
1753
1754 errno = 0;
1755 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1756 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1757 if (errno) {
1758 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1759 return -1;
1760 }
1761 tcp->flags |= TCB_BPTSET;
1762 }
1763#else /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001764
Michal Ludvig0e035502002-09-23 15:41:01 +00001765#if defined (I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001766#define LOOP 0x0000feeb
1767#elif defined (M68K)
1768#define LOOP 0x60fe0000
1769#elif defined (ALPHA)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001770#define LOOP 0xc3ffffff
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001771#elif defined (POWERPC)
Roland McGrath1e85cf92002-12-16 20:40:54 +00001772#define LOOP 0x48000000
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001773#elif defined(ARM)
Wichert Akkerman9a8a37f1999-12-24 23:19:31 +00001774#define LOOP 0xEAFFFFFE
Wichert Akkermanf90da011999-10-31 21:15:38 +00001775#elif defined(MIPS)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001776#define LOOP 0x1000ffff
1777#elif defined(S390)
1778#define LOOP 0xa7f40000 /* BRC 15,0 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001779#elif defined(S390X)
1780#define LOOP 0xa7f4000000000000UL /* BRC 15,0 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001781#elif defined(HPPA)
1782#define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001783#elif defined(SH)
1784#ifdef __LITTLE_ENDIAN__
1785#define LOOP 0x0000affe
1786#else
1787#define LOOP 0xfeaf0000
1788#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001789#else
1790#error unknown architecture
1791#endif
1792
1793 if (tcp->flags & TCB_BPTSET) {
1794 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1795 return -1;
1796 }
1797#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001798 if (upeek(tcp, 4*EIP, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001799 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00001800#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001801 if (upeek(tcp, 8*RIP, &tcp->baddr) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001802 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001803#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001804 if (upeek(tcp, 4*PT_PC, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001805 return -1;
1806#elif defined (ALPHA)
1807 return -1;
1808#elif defined (ARM)
1809 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001810#elif defined (MIPS)
1811 return -1; /* FIXME: I do not know what i do - Flo */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001812#elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001813 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001814 return -1;
Michal Ludvig10a88d02002-10-07 14:31:00 +00001815#elif defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001816 if (upeek(tcp,PT_PSWADDR, &tcp->baddr) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001817 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001818#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001819 if (upeek(tcp, PT_IAOQ0, &tcp->baddr) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001820 return -1;
1821 tcp->baddr &= ~0x03;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001822#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001823 if (upeek(tcp, 4*REG_PC, &tcp->baddr) < 0)
Wichert Akkermanccef6372002-05-01 16:39:22 +00001824 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001825#else
1826#error unknown architecture
1827#endif
1828 if (debug)
1829 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1830 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1831 if (errno) {
1832 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1833 return -1;
1834 }
1835 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1836 if (errno) {
1837 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1838 return -1;
1839 }
1840 tcp->flags |= TCB_BPTSET;
1841
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001842#endif /* !IA64 */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001843#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001844#endif /* LINUX */
1845
1846#ifdef SUNOS4
1847#ifdef SPARC /* This code is slightly sparc specific */
1848
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001849 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001850#define BPT 0x91d02001 /* ta 1 */
1851#define LOOP 0x10800000 /* ba 0 */
1852#define LOOPA 0x30800000 /* ba,a 0 */
1853#define NOP 0x01000000
1854#if LOOPA
1855 static int loopdeloop[1] = {LOOPA};
1856#else
1857 static int loopdeloop[2] = {LOOP, NOP};
1858#endif
1859
1860 if (tcp->flags & TCB_BPTSET) {
1861 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1862 return -1;
1863 }
1864 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1865 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1866 return -1;
1867 }
1868 tcp->baddr = regs.r_o7 + 8;
1869 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1870 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1871 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1872 return -1;
1873 }
1874
1875 /*
1876 * XXX - BRUTAL MODE ON
1877 * We cannot set a real BPT in the child, since it will not be
1878 * traced at the moment it will reach the trap and would probably
1879 * die with a core dump.
1880 * Thus, we are force our way in by taking out two instructions
1881 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1882 * generated by out PTRACE_ATTACH.
1883 * Of cause, if we evaporate ourselves in the middle of all this...
1884 */
1885 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1886 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1887 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1888 return -1;
1889 }
1890 tcp->flags |= TCB_BPTSET;
1891
1892#endif /* SPARC */
1893#endif /* SUNOS4 */
1894
1895 return 0;
1896}
1897
1898int
1899clearbpt(tcp)
1900struct tcb *tcp;
1901{
1902
1903#ifdef LINUX
Michal Ludvig0e035502002-09-23 15:41:01 +00001904#if defined(I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001905 long eip;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001906#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001907 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001908#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001909 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001910#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001911 long pc;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001912#elif defined(HPPA)
1913 long iaoq;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001914#elif defined(SH)
1915 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001916#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001917
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001918#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001919 /* Again, we borrow the SunOS breakpoint code. */
1920 if (!(tcp->flags & TCB_BPTSET)) {
1921 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1922 return -1;
1923 }
1924 errno = 0;
1925 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1926 if(errno) {
1927 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1928 return -1;
1929 }
1930 tcp->flags &= ~TCB_BPTSET;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001931#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001932 if (ia32) {
1933 unsigned long addr;
1934
1935 if (debug)
1936 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1937 if (!(tcp->flags & TCB_BPTSET)) {
1938 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1939 return -1;
1940 }
1941 errno = 0;
1942 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1943 if (errno) {
1944 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1945 return -1;
1946 }
1947 tcp->flags &= ~TCB_BPTSET;
1948
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001949 if (upeek(tcp, PT_CR_IIP, &addr) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001950 return -1;
1951 if (addr != tcp->baddr) {
1952 /* The breakpoint has not been reached yet. */
1953 if (debug)
1954 fprintf(stderr,
1955 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1956 addr, tcp->baddr);
1957 return 0;
1958 }
1959 } else {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001960 unsigned long addr, ipsr;
1961 pid_t pid;
1962
1963 pid = tcp->pid;
1964
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001965 if (upeek(tcp, PT_CR_IPSR, &ipsr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001966 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001967 if (upeek(tcp, PT_CR_IIP, &addr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001968 return -1;
1969
1970 /* restore original bundle: */
1971 errno = 0;
1972 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
1973 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
1974 if (errno) {
1975 perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
1976 return -1;
1977 }
1978
1979 /* restore original "ri" in ipsr: */
1980 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
1981 errno = 0;
1982 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
1983 if (errno) {
1984 perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
1985 return -1;
1986 }
1987
1988 tcp->flags &= ~TCB_BPTSET;
1989
1990 if (addr != (tcp->baddr & ~0x3)) {
1991 /* the breakpoint has not been reached yet. */
1992 if (debug)
1993 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1994 addr, tcp->baddr);
1995 return 0;
1996 }
1997 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001998#else /* !IA64 && !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001999
2000 if (debug)
2001 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
2002 if (!(tcp->flags & TCB_BPTSET)) {
2003 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
2004 return -1;
2005 }
2006 errno = 0;
2007 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
2008 if (errno) {
2009 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
2010 return -1;
2011 }
2012 tcp->flags &= ~TCB_BPTSET;
2013
2014#ifdef I386
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002015 if (upeek(tcp, 4*EIP, &eip) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002016 return -1;
2017 if (eip != tcp->baddr) {
2018 /* The breakpoint has not been reached yet. */
2019 if (debug)
2020 fprintf(stderr,
2021 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2022 eip, tcp->baddr);
2023 return 0;
2024 }
Michal Ludvig0e035502002-09-23 15:41:01 +00002025#elif defined(X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002026 if (upeek(tcp, 8*RIP, &eip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002027 return -1;
2028 if (eip != tcp->baddr) {
2029 /* The breakpoint has not been reached yet. */
2030 if (debug)
2031 fprintf(stderr,
2032 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2033 eip, tcp->baddr);
2034 return 0;
2035 }
Wichert Akkermanc7926982000-04-10 22:22:31 +00002036#elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002037 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002038 return -1;
2039 if (pc != tcp->baddr) {
2040 /* The breakpoint has not been reached yet. */
2041 if (debug)
2042 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2043 pc, tcp->baddr);
2044 return 0;
2045 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002046#elif defined(M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002047 if (upeek(tcp, 4*PT_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002048 return -1;
2049 if (pc != tcp->baddr) {
2050 /* The breakpoint has not been reached yet. */
2051 if (debug)
2052 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2053 pc, tcp->baddr);
2054 return 0;
2055 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002056#elif defined(ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002057 if (upeek(tcp, REG_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002058 return -1;
2059 if (pc != tcp->baddr) {
2060 /* The breakpoint has not been reached yet. */
2061 if (debug)
2062 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2063 pc, tcp->baddr);
2064 return 0;
2065 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002066#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002067 if (upeek(tcp, PT_IAOQ0, &iaoq) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002068 return -1;
2069 iaoq &= ~0x03;
2070 if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
2071 /* The breakpoint has not been reached yet. */
2072 if (debug)
2073 fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
2074 iaoq, tcp->baddr);
2075 return 0;
2076 }
2077 iaoq = tcp->baddr | 3;
2078 /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
2079 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
2080 * has no significant effect.
2081 */
2082 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
2083 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
Wichert Akkermanccef6372002-05-01 16:39:22 +00002084#elif defined(SH)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002085 if (upeek(tcp, 4*REG_PC, &pc) < 0)
Wichert Akkermanccef6372002-05-01 16:39:22 +00002086 return -1;
2087 if (pc != tcp->baddr) {
2088 /* The breakpoint has not been reached yet. */
2089 if (debug)
2090 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2091 pc, tcp->baddr);
2092 return 0;
2093 }
2094
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002095#endif /* arch */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002096#endif /* !SPARC && !SPARC64 && !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002097#endif /* LINUX */
2098
2099#ifdef SUNOS4
2100#ifdef SPARC
2101
2102#if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00002103 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002104#endif
2105
2106 if (!(tcp->flags & TCB_BPTSET)) {
2107 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
2108 return -1;
2109 }
2110 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
2111 sizeof tcp->inst, (char *) tcp->inst) < 0) {
2112 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
2113 return -1;
2114 }
2115 tcp->flags &= ~TCB_BPTSET;
2116
2117#if !LOOPA
2118 /*
2119 * Since we don't have a single instruction breakpoint, we may have
2120 * to adjust the program counter after removing the our `breakpoint'.
2121 */
2122 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
2123 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
2124 return -1;
2125 }
2126 if ((regs.r_pc < tcp->baddr) ||
2127 (regs.r_pc > tcp->baddr + 4)) {
2128 /* The breakpoint has not been reached yet */
2129 if (debug)
2130 fprintf(stderr,
2131 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
2132 regs.r_pc, tcp->parent->baddr);
2133 return 0;
2134 }
2135 if (regs.r_pc != tcp->baddr)
2136 if (debug)
2137 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
2138 regs.r_pc, tcp->baddr);
2139
2140 regs.r_pc = tcp->baddr;
2141 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
2142 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
2143 return -1;
2144 }
2145#endif /* LOOPA */
2146#endif /* SPARC */
2147#endif /* SUNOS4 */
2148
2149 return 0;
2150}
2151
Roland McGrathd81f1d92003-01-09 06:53:34 +00002152#endif
2153
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002154#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002155
2156#ifdef SUNOS4
2157
2158static int
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002159getex(tcp, hdr)
2160struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002161struct exec *hdr;
2162{
2163 int n;
2164
2165 for (n = 0; n < sizeof *hdr; n += 4) {
2166 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002167 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002168 return -1;
2169 memcpy(((char *) hdr) + n, &res, 4);
2170 }
2171 if (debug) {
2172 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
2173 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
2174 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
2175 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
2176 }
2177 return 0;
2178}
2179
2180int
2181fixvfork(tcp)
2182struct tcb *tcp;
2183{
2184 int pid = tcp->pid;
2185 /*
2186 * Change `vfork' in a freshly exec'ed dynamically linked
2187 * executable's (internal) symbol table to plain old `fork'
2188 */
2189
2190 struct exec hdr;
2191 struct link_dynamic dyn;
2192 struct link_dynamic_2 ld;
2193 char *strtab, *cp;
2194
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002195 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002196 return -1;
2197 if (!hdr.a_dynamic)
2198 return -1;
2199
2200 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
2201 fprintf(stderr, "Cannot read DYNAMIC\n");
2202 return -1;
2203 }
2204 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
2205 fprintf(stderr, "Cannot read link_dynamic_2\n");
2206 return -1;
2207 }
2208 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00002209 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002210 return -1;
2211 }
2212 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
2213 (int)ld.ld_symb_size, strtab) < 0)
2214 goto err;
2215
2216#if 0
2217 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2218 fprintf(stderr, "[symbol: %s]\n", cp);
2219 cp += strlen(cp)+1;
2220 }
2221 return 0;
2222#endif
2223 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2224 if (strcmp(cp, "_vfork") == 0) {
2225 if (debug)
2226 fprintf(stderr, "fixvfork: FOUND _vfork\n");
2227 strcpy(cp, "_fork");
2228 break;
2229 }
2230 cp += strlen(cp)+1;
2231 }
2232 if (cp < strtab + ld.ld_symb_size)
2233 /*
2234 * Write entire symbol table back to avoid
2235 * memory alignment bugs in ptrace
2236 */
2237 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
2238 (int)ld.ld_symb_size, strtab) < 0)
2239 goto err;
2240
2241 free(strtab);
2242 return 0;
2243
2244err:
2245 free(strtab);
2246 return -1;
2247}
2248
2249#endif /* SUNOS4 */