blob: affb16788fadcb483df369b0638540efe9abdc79 [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) \
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000130 return (type) __res; \
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000131errno = -__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/*
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000244 * Generic ptrace wrapper which tracks ESRCH errors
245 * by setting tcp->ptrace_errno to ESRCH.
246 *
247 * We assume that ESRCH indicates likely process death (SIGKILL?),
248 * modulo bugs where process somehow ended up not stopped.
249 * Unfortunately kernel uses ESRCH for that case too. Oh well.
250 *
251 * Currently used by upeek() only.
252 * TODO: use this in all other ptrace() calls while decoding.
253 */
254long
255do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
256{
257 long l;
258
259 errno = 0;
260 l = ptrace(request, tcp->pid, addr, data);
261 /* Non-ESRCH errors might be our invalid reg/mem accesses,
262 * we do not record them. */
263 if (errno == ESRCH)
264 tcp->ptrace_errno = ESRCH;
265 return l;
266}
267
268/*
269 * Used when we want to unblock stopped traced process.
270 * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
271 * Returns 0 on success or if error was ESRCH
272 * (presumably process was killed while we talk to it).
273 * Otherwise prints error message and returns -1.
274 */
275int
276ptrace_restart(int op, struct tcb *tcp, int sig)
277{
278 int err;
279 const char *msg;
280
281 errno = 0;
282 ptrace(op, tcp->pid, (void *) 1, (void *) (long) sig);
283 err = errno;
284 if (!err || err == ESRCH)
285 return 0;
286
287 tcp->ptrace_errno = err;
288 msg = "SYSCALL";
289 if (op == PTRACE_CONT)
290 msg = "CONT";
291 if (op == PTRACE_DETACH)
292 msg = "DETACH";
293 fprintf(stderr, "strace: ptrace(PTRACE_%s,1,%d): %s\n",
294 msg, sig, strerror(err));
295 return -1;
296}
297
298/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000299 * Print entry in struct xlat table, if there.
300 */
301void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000302printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000303{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000304 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000305
306 if (str)
307 tprintf("%s", str);
308 else
309 tprintf("%#x /* %s */", val, dflt);
310}
311
312/*
313 * Interpret `xlat' as an array of flags
314 * print the entries whose bits are on in `flags'
315 * return # of flags printed.
316 */
317int
318addflags(xlat, flags)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000319const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000320int flags;
321{
322 int n;
323
324 for (n = 0; xlat->str; xlat++) {
325 if (xlat->val && (flags & xlat->val) == xlat->val) {
326 tprintf("|%s", xlat->str);
327 flags &= ~xlat->val;
328 n++;
329 }
330 }
331 if (flags) {
332 tprintf("|%#x", flags);
333 n++;
334 }
335 return n;
336}
337
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000338/*
339 * Interpret `xlat' as an array of flags/
340 * Print to static string the entries whose bits are on in `flags'
341 * Return static string.
342 */
343const char *
344sprintflags(const char *prefix, const struct xlat *xlat, int flags)
345{
346 static char outstr[1024];
347 int found = 0;
348
349 strcpy(outstr, prefix);
350
351 for (; xlat->str; xlat++) {
352 if ((flags & xlat->val) == xlat->val) {
353 if (found)
354 strcat(outstr, "|");
355 strcat(outstr, xlat->str);
356 flags &= ~xlat->val;
357 found = 1;
358 }
359 }
360 if (flags) {
361 if (found)
362 strcat(outstr, "|");
363 sprintf(outstr + strlen(outstr), "%#x", flags);
364 }
365
366 return outstr;
367}
368
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000369int
Roland McGrathb2dee132005-06-01 19:02:36 +0000370printflags(xlat, flags, dflt)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000371const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000372int flags;
Roland McGrathb2dee132005-06-01 19:02:36 +0000373const char *dflt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000374{
375 int n;
376 char *sep;
377
378 if (flags == 0 && xlat->val == 0) {
379 tprintf("%s", xlat->str);
380 return 1;
381 }
382
383 sep = "";
384 for (n = 0; xlat->str; xlat++) {
385 if (xlat->val && (flags & xlat->val) == xlat->val) {
386 tprintf("%s%s", sep, xlat->str);
387 flags &= ~xlat->val;
388 sep = "|";
389 n++;
390 }
391 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000392
393 if (n) {
394 if (flags) {
395 tprintf("%s%#x", sep, flags);
396 n++;
397 }
398 } else {
399 if (flags) {
400 tprintf("%#x", flags);
401 if (dflt)
402 tprintf(" /* %s */", dflt);
403 } else {
404 if (dflt)
405 tprintf("0");
406 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000407 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000408
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000409 return n;
410}
411
412void
413printnum(tcp, addr, fmt)
414struct tcb *tcp;
415long addr;
416char *fmt;
417{
Roland McGratheb285352003-01-14 09:59:00 +0000418 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000419
420 if (!addr) {
421 tprintf("NULL");
422 return;
423 }
424 if (umove(tcp, addr, &num) < 0) {
425 tprintf("%#lx", addr);
426 return;
427 }
428 tprintf("[");
429 tprintf(fmt, num);
430 tprintf("]");
431}
432
Roland McGrath6bc12202003-11-13 22:32:27 +0000433void
Roland McGrath9814a942005-07-04 23:28:10 +0000434printnum_int(tcp, addr, fmt)
435struct tcb *tcp;
436long addr;
437char *fmt;
438{
439 int num;
440
441 if (!addr) {
442 tprintf("NULL");
443 return;
444 }
445 if (umove(tcp, addr, &num) < 0) {
446 tprintf("%#lx", addr);
447 return;
448 }
449 tprintf("[");
450 tprintf(fmt, num);
451 tprintf("]");
452}
453
454void
Roland McGrath6bc12202003-11-13 22:32:27 +0000455printuid(text, uid)
456const char *text;
457unsigned long uid;
458{
459 tprintf("%s", text);
460 tprintf((uid == -1) ? "%ld" : "%lu", uid);
461}
462
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000463static char path[MAXPATHLEN + 1];
464
Dmitry V. Levina501f142008-11-10 23:19:13 +0000465/*
466 * Quote string `instr' of length `size'
467 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
468 * If `len' < 0, treat `instr' as a NUL-terminated string
469 * and quote at most (`size' - 1) bytes.
470 */
Roland McGrath6d970322007-11-01 23:53:59 +0000471static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000472string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000473{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000474 const unsigned char *ustr = (const unsigned char *) instr;
475 char *s = outstr;
476 int usehex = 0, c, i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000477
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000478 if (xflag > 1)
479 usehex = 1;
480 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000481 /* Check for presence of symbol which require
482 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000483 for (i = 0; i < size; ++i) {
484 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000485 /* Check for NUL-terminated string. */
486 if (len < 0) {
487 if (c == '\0')
488 break;
489 /* Quote at most size - 1 bytes. */
490 if (i == size - 1)
491 continue;
492 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000493 if (!isprint(c) && !isspace(c)) {
494 usehex = 1;
495 break;
496 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000497 }
498 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000499
500 *s++ = '\"';
501
502 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000503 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000504 for (i = 0; i < size; ++i) {
505 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000506 /* Check for NUL-terminated string. */
507 if (len < 0) {
508 if (c == '\0')
509 break;
510 /* Quote at most size - 1 bytes. */
511 if (i == size - 1)
512 continue;
513 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000514 sprintf(s, "\\x%02x", c);
515 s += 4;
516 }
517 } else {
518 for (i = 0; i < size; ++i) {
519 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000520 /* Check for NUL-terminated string. */
521 if (len < 0) {
522 if (c == '\0')
523 break;
524 /* Quote at most size - 1 bytes. */
525 if (i == size - 1)
526 continue;
527 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000528 switch (c) {
529 case '\"': case '\\':
530 *s++ = '\\';
531 *s++ = c;
532 break;
533 case '\f':
534 *s++ = '\\';
535 *s++ = 'f';
536 break;
537 case '\n':
538 *s++ = '\\';
539 *s++ = 'n';
540 break;
541 case '\r':
542 *s++ = '\\';
543 *s++ = 'r';
544 break;
545 case '\t':
546 *s++ = '\\';
547 *s++ = 't';
548 break;
549 case '\v':
550 *s++ = '\\';
551 *s++ = 'v';
552 break;
553 default:
554 if (isprint(c))
555 *s++ = c;
556 else if (i + 1 < size
557 && isdigit(ustr[i + 1])) {
558 sprintf(s, "\\%03o", c);
559 s += 4;
560 } else {
561 sprintf(s, "\\%o", c);
562 s += strlen(s);
563 }
564 break;
565 }
566 }
567 }
568
569 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000570 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000571
572 /* Return nonzero if the string was unterminated. */
573 return i == size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000574}
575
Dmitry V. Levina501f142008-11-10 23:19:13 +0000576/*
577 * Print path string specified by address `addr' and length `n'.
578 * If path length exceeds `n', append `...' to the output.
579 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000580void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000581printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000582{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000583 if (!addr) {
Roland McGrath371ed8f2005-02-06 01:55:07 +0000584 tprintf("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000585 return;
586 }
587
Dmitry V. Levina501f142008-11-10 23:19:13 +0000588 /* Cap path length to the path buffer size,
589 and NUL-terminate the buffer. */
590 if (n > sizeof path - 1)
591 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000592 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000593
594 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000595 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000596 tprintf("%#lx", addr);
597 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000598 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
599 int trunc = (path[n] != '\0');
600
601 if (trunc)
602 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000603 (void) string_quote(path, outstr, -1, n + 1);
604 if (trunc)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000605 strcat(outstr, "...");
606 tprintf("%s", outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607 }
608}
609
610void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000611printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000613 printpathn(tcp, addr, sizeof path - 1);
614}
615
Dmitry V. Levina501f142008-11-10 23:19:13 +0000616/*
617 * Print string specified by address `addr' and length `len'.
618 * If `len' < 0, treat the string as a NUL-terminated string.
619 * If string length exceeds `max_strlen', append `...' to the output.
620 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000621void
622printstr(struct tcb *tcp, long addr, int len)
623{
624 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000625 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000626 int size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000627
628 if (!addr) {
629 tprintf("NULL");
630 return;
631 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000632 /* Allocate static buffers if they are not allocated yet. */
633 if (!str)
634 str = malloc(max_strlen + 1);
635 if (!outstr)
636 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
637 if (!str || !outstr) {
638 fprintf(stderr, "out of memory\n");
639 tprintf("%#lx", addr);
640 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000642
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000643 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000644 /*
645 * Treat as a NUL-terminated string: fetch one byte more
646 * because string_quote() quotes one byte less.
647 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000648 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000649 str[max_strlen] = '\0';
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000650 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000651 tprintf("%#lx", addr);
652 return;
653 }
654 }
655 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000656 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000657 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000658 tprintf("%#lx", addr);
659 return;
660 }
661 }
662
Dmitry V. Levina501f142008-11-10 23:19:13 +0000663 if (string_quote(str, outstr, len, size) &&
664 (len < 0 || len > max_strlen))
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000665 strcat(outstr, "...");
Roland McGratha503dcf2007-08-02 02:06:26 +0000666
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000667 tprintf("%s", outstr);
668}
669
John Hughes1d08dcf2001-07-10 13:48:44 +0000670#if HAVE_SYS_UIO_H
671void
672dumpiov(tcp, len, addr)
673struct tcb * tcp;
674int len;
675long addr;
676{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000677#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
678 union {
679 struct { u_int32_t base; u_int32_t len; } *iov32;
680 struct { u_int64_t base; u_int64_t len; } *iov64;
681 } iovu;
682#define iov iovu.iov64
683#define sizeof_iov \
684 (personality_wordsize[current_personality] == 4 \
685 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
686#define iov_iov_base(i) \
687 (personality_wordsize[current_personality] == 4 \
688 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
689#define iov_iov_len(i) \
690 (personality_wordsize[current_personality] == 4 \
691 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
692#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000693 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000694#define sizeof_iov sizeof(*iov)
695#define iov_iov_base(i) iov[i].iov_base
696#define iov_iov_len(i) iov[i].iov_len
697#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000698 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000699 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000700
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000701 size = sizeof_iov * (unsigned long) len;
702 if (size / sizeof_iov != len
703 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000704 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000705 return;
706 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000707 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000708 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000709 /* include the buffer number to make it easy to
710 * match up the trace with the source */
711 tprintf(" * %lu bytes in buffer %d\n",
712 (unsigned long)iov_iov_len(i), i);
713 dumpstr(tcp, (long) iov_iov_base(i),
714 iov_iov_len(i));
715 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000716 }
717 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000718#undef sizeof_iov
719#undef iov_iov_base
720#undef iov_iov_len
721#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000722}
723#endif
724
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000725void
726dumpstr(tcp, addr, len)
727struct tcb *tcp;
728long addr;
729int len;
730{
731 static int strsize = -1;
732 static unsigned char *str;
733 static char outstr[80];
734 char *s;
735 int i, j;
736
737 if (strsize < len) {
738 if (str)
739 free(str);
740 if ((str = malloc(len)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000741 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000742 return;
743 }
744 strsize = len;
745 }
746
747 if (umoven(tcp, addr, len, (char *) str) < 0)
748 return;
749
750 for (i = 0; i < len; i += 16) {
751 s = outstr;
752 sprintf(s, " | %05x ", i);
753 s += 9;
754 for (j = 0; j < 16; j++) {
755 if (j == 8)
756 *s++ = ' ';
757 if (i + j < len) {
758 sprintf(s, " %02x", str[i + j]);
759 s += 3;
760 }
761 else {
762 *s++ = ' '; *s++ = ' '; *s++ = ' ';
763 }
764 }
765 *s++ = ' '; *s++ = ' ';
766 for (j = 0; j < 16; j++) {
767 if (j == 8)
768 *s++ = ' ';
769 if (i + j < len) {
770 if (isprint(str[i + j]))
771 *s++ = str[i + j];
772 else
773 *s++ = '.';
774 }
775 else
776 *s++ = ' ';
777 }
778 tprintf("%s |\n", outstr);
779 }
780}
781
782#define PAGMASK (~(PAGSIZ - 1))
783/*
784 * move `len' bytes of data from process `pid'
785 * at address `addr' to our space at `laddr'
786 */
787int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000788umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790#ifdef LINUX
791 int pid = tcp->pid;
792 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000793 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000794 union {
795 long val;
796 char x[sizeof(long)];
797 } u;
798
799 if (addr & (sizeof(long) - 1)) {
800 /* addr not a multiple of sizeof(long) */
801 n = addr - (addr & -sizeof(long)); /* residue */
802 addr &= -sizeof(long); /* residue */
803 errno = 0;
804 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
805 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000806 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000807 /* Ran into 'end of memory' - stupid "printpath" */
808 return 0;
809 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000810 /* But if not started, we had a bogus address. */
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000811 if (addr != 0 && errno != EIO && errno != ESRCH)
Roland McGrath1c459762007-08-02 02:22:06 +0000812 perror("ptrace: umoven");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000813 return -1;
814 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000815 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000816 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
817 addr += sizeof(long), laddr += m, len -= m;
818 }
819 while (len) {
820 errno = 0;
821 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
822 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000823 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000824 /* Ran into 'end of memory' - stupid "printpath" */
825 return 0;
826 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000827 if (addr != 0 && errno != EIO && errno != ESRCH)
Roland McGrath4db26242003-01-30 20:15:19 +0000828 perror("ptrace: umoven");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000829 return -1;
830 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000831 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000832 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
833 addr += sizeof(long), laddr += m, len -= m;
834 }
835#endif /* LINUX */
836
837#ifdef SUNOS4
838 int pid = tcp->pid;
839#if 0
840 int n, m;
841 union {
842 long val;
843 char x[sizeof(long)];
844 } u;
845
846 if (addr & (sizeof(long) - 1)) {
847 /* addr not a multiple of sizeof(long) */
848 n = addr - (addr & -sizeof(long)); /* residue */
849 addr &= -sizeof(long); /* residue */
850 errno = 0;
851 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
852 if (errno) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000853 if (errno != ESRCH)
854 perror("umoven");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000855 return -1;
856 }
857 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
858 addr += sizeof(long), laddr += m, len -= m;
859 }
860 while (len) {
861 errno = 0;
862 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
863 if (errno) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000864 if (errno != ESRCH)
865 perror("umoven");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000866 return -1;
867 }
868 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
869 addr += sizeof(long), laddr += m, len -= m;
870 }
871#else /* !oldway */
872 int n;
873
874 while (len) {
875 n = MIN(len, PAGSIZ);
876 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
877 if (ptrace(PTRACE_READDATA, pid,
878 (char *) addr, len, laddr) < 0) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000879 if (errno != ESRCH) {
880 perror("umoven: ptrace(PTRACE_READDATA, ...)");
881 abort();
882 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000883 return -1;
884 }
885 len -= n;
886 addr += n;
887 laddr += n;
888 }
889#endif /* !oldway */
890#endif /* SUNOS4 */
891
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000892#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000893#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000894 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000895#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000896 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000897#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000898 lseek(fd, addr, SEEK_SET);
899 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000900 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000901#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000902
903 return 0;
904}
905
906/*
907 * like `umove' but make the additional effort of looking
908 * for a terminating zero byte.
909 */
910int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000911umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000912{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000913#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000914#ifdef HAVE_MP_PROCFS
915 int fd = tcp->pfd_as;
916#else
917 int fd = tcp->pfd;
918#endif
919 /* Some systems (e.g. FreeBSD) can be upset if we read off the
920 end of valid memory, avoid this by trying to read up
921 to page boundaries. But we don't know what a page is (and
922 getpagesize(2) (if it exists) doesn't necessarily return
923 hardware page size). Assume all pages >= 1024 (a-historical
924 I know) */
925
926 int page = 1024; /* How to find this? */
927 int move = page - (addr & (page - 1));
928 int left = len;
929
930 lseek(fd, addr, SEEK_SET);
931
932 while (left) {
933 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000934 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000935 return left != len ? 0 : -1;
936 if (memchr (laddr, 0, move)) break;
937 left -= move;
938 laddr += move;
939 addr += move;
940 move = page;
941 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000942#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000943 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000944 int pid = tcp->pid;
945 int i, n, m;
946 union {
947 long val;
948 char x[sizeof(long)];
949 } u;
950
951 if (addr & (sizeof(long) - 1)) {
952 /* addr not a multiple of sizeof(long) */
953 n = addr - (addr & -sizeof(long)); /* residue */
954 addr &= -sizeof(long); /* residue */
955 errno = 0;
956 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
957 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000958 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000959 /* Ran into 'end of memory' - stupid "printpath" */
960 return 0;
961 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000962 if (addr != 0 && errno != EIO && errno != ESRCH)
Roland McGrath1c459762007-08-02 02:22:06 +0000963 perror("umovestr");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000964 return -1;
965 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000966 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000967 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
968 while (n & (sizeof(long) - 1))
969 if (u.x[n++] == '\0')
970 return 0;
971 addr += sizeof(long), laddr += m, len -= m;
972 }
973 while (len) {
974 errno = 0;
975 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
976 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000977 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000978 /* Ran into 'end of memory' - stupid "printpath" */
979 return 0;
980 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000981 if (addr != 0 && errno != EIO && errno != ESRCH)
Roland McGrath1c459762007-08-02 02:22:06 +0000982 perror("umovestr");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000983 return -1;
984 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000985 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
987 for (i = 0; i < sizeof(long); i++)
988 if (u.x[i] == '\0')
989 return 0;
990
991 addr += sizeof(long), laddr += m, len -= m;
992 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000993#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000994 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000995}
996
997#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000998#if !defined (SPARC) && !defined(SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000999#define PTRACE_WRITETEXT 101
1000#define PTRACE_WRITEDATA 102
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001001#endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001002#endif /* LINUX */
1003
1004#ifdef SUNOS4
1005
1006static int
1007uload(cmd, pid, addr, len, laddr)
1008int cmd;
1009int pid;
1010long addr;
1011int len;
1012char *laddr;
1013{
1014#if 0
1015 int n;
1016
1017 while (len) {
1018 n = MIN(len, PAGSIZ);
1019 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
1020 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
1021 perror("uload: ptrace(PTRACE_WRITE, ...)");
1022 return -1;
1023 }
1024 len -= n;
1025 addr += n;
1026 laddr += n;
1027 }
1028#else
1029 int peek, poke;
1030 int n, m;
1031 union {
1032 long val;
1033 char x[sizeof(long)];
1034 } u;
1035
1036 if (cmd == PTRACE_WRITETEXT) {
1037 peek = PTRACE_PEEKTEXT;
1038 poke = PTRACE_POKETEXT;
1039 }
1040 else {
1041 peek = PTRACE_PEEKDATA;
1042 poke = PTRACE_POKEDATA;
1043 }
1044 if (addr & (sizeof(long) - 1)) {
1045 /* addr not a multiple of sizeof(long) */
1046 n = addr - (addr & -sizeof(long)); /* residue */
1047 addr &= -sizeof(long);
1048 errno = 0;
1049 u.val = ptrace(peek, pid, (char *) addr, 0);
1050 if (errno) {
1051 perror("uload: POKE");
1052 return -1;
1053 }
1054 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
1055 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
1056 perror("uload: POKE");
1057 return -1;
1058 }
1059 addr += sizeof(long), laddr += m, len -= m;
1060 }
1061 while (len) {
1062 if (len < sizeof(long))
1063 u.val = ptrace(peek, pid, (char *) addr, 0);
1064 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
1065 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1066 perror("uload: POKE");
1067 return -1;
1068 }
1069 addr += sizeof(long), laddr += m, len -= m;
1070 }
1071#endif
1072 return 0;
1073}
1074
1075int
1076tload(pid, addr, len, laddr)
1077int pid;
1078int addr, len;
1079char *laddr;
1080{
1081 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1082}
1083
1084int
1085dload(pid, addr, len, laddr)
1086int pid;
1087int addr;
1088int len;
1089char *laddr;
1090{
1091 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
1092}
1093
1094#endif /* SUNOS4 */
1095
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001096#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001097
1098int
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001099upeek(tcp, off, res)
1100struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101long off;
1102long *res;
1103{
1104 long val;
1105
1106#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
1107 {
1108 static int is_sun4m = -1;
1109 struct utsname name;
1110
1111 /* Round up the usual suspects. */
1112 if (is_sun4m == -1) {
1113 if (uname(&name) < 0) {
1114 perror("upeek: uname?");
1115 exit(1);
1116 }
1117 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1118 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001119 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120
1121 for (x = struct_user_offsets; x->str; x++)
1122 x->val += 1024;
1123 }
1124 }
1125 if (is_sun4m)
1126 off += 1024;
1127 }
1128#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
1129 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001130 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 if (val == -1 && errno) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001132 if (errno != ESRCH) {
1133 char buf[60];
1134 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
1135 perror(buf);
1136 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001137 return -1;
1138 }
1139 *res = val;
1140 return 0;
1141}
1142
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001143#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001144
Roland McGratha4d48532005-06-08 20:45:28 +00001145#if 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001146long
1147getpc(tcp)
1148struct tcb *tcp;
1149{
1150
1151#ifdef LINUX
1152 long pc;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001153#if defined(I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001154 if (upeek(tcp, 4*EIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001155 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00001156#elif defined(X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001157 if (upeek(tcp, 8*RIP, &pc) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001158 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001159#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001160 if (upeek(tcp, PT_B0, &pc) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001161 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001162#elif defined(ARM)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001163 if (upeek(tcp, 4*15, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001164 return -1;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001165#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001166 if (upeek(tcp, REG_PC, &pc) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001167 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001168#elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001169 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001170 return -1;
Roland McGrath84fa9232005-06-08 18:06:22 +00001171#elif defined(M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001172 if (upeek(tcp, 4*PT_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001173 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001174#elif defined(ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001175 if (upeek(tcp, REG_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001177#elif defined(MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001178 if (upeek(tcp, REG_EPC, &pc) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001179 return -1;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001180#elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001181 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001182 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
1183 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001184 pc = regs.r_pc;
Michal Ludvig10a88d02002-10-07 14:31:00 +00001185#elif defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001186 if(upeek(tcp,PT_PSWADDR,&pc) < 0)
Michal Ludvig10a88d02002-10-07 14:31:00 +00001187 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001188#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001189 if(upeek(tcp,PT_IAOQ0,&pc) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001190 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001191#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001192 if (upeek(tcp, 4*REG_PC ,&pc) < 0)
1193 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001194#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001195 if (upeek(tcp, REG_PC ,&pc) < 0)
1196 return -1;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +00001197#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001198 return pc;
1199#endif /* LINUX */
1200
1201#ifdef SUNOS4
1202 /*
1203 * Return current program counter for `pid'
1204 * Assumes PC is never 0xffffffff
1205 */
1206 struct regs regs;
1207
1208 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1209 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
1210 return -1;
1211 }
1212 return regs.r_pc;
1213#endif /* SUNOS4 */
1214
1215#ifdef SVR4
1216 /* XXX */
1217 return 0;
1218#endif /* SVR4 */
1219
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001220#ifdef FREEBSD
1221 struct reg regs;
1222 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1223 return regs.r_eip;
1224#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001225}
Roland McGratha4d48532005-06-08 20:45:28 +00001226#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001227
1228void
1229printcall(tcp)
1230struct tcb *tcp;
1231{
Roland McGrath7a918832005-02-02 20:55:23 +00001232#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1233 sizeof(long) == 8 ? "[????????????????] " : \
1234 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235
1236#ifdef LINUX
1237#ifdef I386
1238 long eip;
1239
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001240 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001241 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001242 return;
1243 }
1244 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001245
1246#elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001247 long psw;
1248 if(upeek(tcp,PT_PSWADDR,&psw) < 0) {
1249 PRINTBADPC;
1250 return;
1251 }
Roland McGratheac26fc2005-02-02 02:48:53 +00001252#ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001253 tprintf("[%08lx] ", psw);
Roland McGratheac26fc2005-02-02 02:48:53 +00001254#elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001255 tprintf("[%16lx] ", psw);
Roland McGratheac26fc2005-02-02 02:48:53 +00001256#endif
1257
Michal Ludvig0e035502002-09-23 15:41:01 +00001258#elif defined(X86_64)
1259 long rip;
1260
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001261 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001262 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001263 return;
1264 }
1265 tprintf("[%16lx] ", rip);
Roland McGrathef388682003-06-03 23:28:59 +00001266#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001267 long ip;
1268
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001269 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001270 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001271 return;
1272 }
1273 tprintf("[%08lx] ", ip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001274#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001275 long pc;
1276
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001277 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001278 tprintf ("[????????] ");
1279 return;
1280 }
1281 tprintf("[%08lx] ", pc);
Roland McGrath84fa9232005-06-08 18:06:22 +00001282#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001283 long pc;
1284
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001285 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286 tprintf ("[????????] ");
1287 return;
1288 }
1289 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001290#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001291 long pc;
1292
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001293 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001294 tprintf ("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001295 return;
1296 }
1297 tprintf("[%08lx] ", pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001298#elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001299 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001301 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001302 return;
1303 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001304 tprintf("[%08lx] ", regs.r_pc);
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001305#elif defined(HPPA)
1306 long pc;
1307
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001308 if(upeek(tcp,PT_IAOQ0,&pc) < 0) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001309 tprintf ("[????????] ");
1310 return;
1311 }
1312 tprintf("[%08lx] ", pc);
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001313#elif defined(MIPS)
1314 long pc;
1315
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001316 if (upeek(tcp, REG_EPC, &pc) < 0) {
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001317 tprintf ("[????????] ");
1318 return;
1319 }
1320 tprintf("[%08lx] ", pc);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001321#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001322 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001323
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001324 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
1325 tprintf ("[????????] ");
1326 return;
1327 }
1328 tprintf("[%08lx] ", pc);
Roland McGrathf5a47772003-06-26 22:40:42 +00001329#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001330 long pc;
1331
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001332 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001333 tprintf ("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001334 return;
1335 }
1336 tprintf("[%08lx] ", pc);
Roland McGrathef388682003-06-03 23:28:59 +00001337#elif defined(ARM)
1338 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001339
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001340 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001341 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001342 return;
1343 }
1344 tprintf("[%08lx] ", pc);
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001345#elif defined(BFIN)
1346 long pc;
1347
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001348 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001349 PRINTBADPC;
1350 return;
1351 }
1352 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001353#endif /* !architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001354#endif /* LINUX */
1355
1356#ifdef SUNOS4
1357 struct regs regs;
1358
1359 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1360 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001361 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001362 return;
1363 }
1364 tprintf("[%08x] ", regs.r_o7);
1365#endif /* SUNOS4 */
1366
1367#ifdef SVR4
1368 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001369 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001370#endif
1371
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001372#ifdef FREEBSD
1373 struct reg regs;
1374 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1375 tprintf("[%08x] ", regs.r_eip);
1376#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001377}
1378
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001379#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001380
Roland McGrathd81f1d92003-01-09 06:53:34 +00001381#if defined LINUX
1382
Roland McGrath3291ef22008-05-20 00:34:34 +00001383#include "syscall.h"
1384
Roland McGrathd81f1d92003-01-09 06:53:34 +00001385#include <sys/syscall.h>
1386#ifndef CLONE_PTRACE
1387# define CLONE_PTRACE 0x00002000
1388#endif
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001389#ifndef CLONE_VFORK
1390# define CLONE_VFORK 0x00004000
1391#endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001392#ifndef CLONE_VM
1393# define CLONE_VM 0x00000100
1394#endif
Roland McGrath76989d72005-06-07 23:21:31 +00001395#ifndef CLONE_STOPPED
1396# define CLONE_STOPPED 0x02000000
1397#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001398
1399#ifdef IA64
1400
Roland McGrath08267b82004-02-20 22:56:43 +00001401/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1402 subsystem has them for x86... */
1403#define SYS_fork 2
1404#define SYS_vfork 190
1405
Roland McGrathd81f1d92003-01-09 06:53:34 +00001406typedef unsigned long *arg_setup_state;
1407
1408static int
1409arg_setup(struct tcb *tcp, arg_setup_state *state)
1410{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001411 unsigned long cfm, sof, sol;
1412 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001413
Jan Kratochvil1f942712008-08-06 21:38:52 +00001414 if (ia32) {
1415 /* Satisfy a false GCC warning. */
1416 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001417 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001418 }
Roland McGrath08267b82004-02-20 22:56:43 +00001419
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001420 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001421 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001422 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001423 return -1;
1424
1425 sof = (cfm >> 0) & 0x7f;
1426 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001427 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001428
Jan Kratochvil1f942712008-08-06 21:38:52 +00001429 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001430 return 0;
1431}
1432
1433# define arg_finish_change(tcp, state) 0
1434
1435#ifdef SYS_fork
1436static int
1437get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1438{
Roland McGrath08267b82004-02-20 22:56:43 +00001439 int ret;
1440
1441 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001442 ret = upeek (tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001443 else
1444 ret = umoven (tcp,
1445 (unsigned long) ia64_rse_skip_regs(*state, 0),
1446 sizeof(long), (void *) valp);
1447 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001448}
1449
1450static int
1451get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1452{
Roland McGrath08267b82004-02-20 22:56:43 +00001453 int ret;
1454
1455 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001456 ret = upeek (tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001457 else
1458 ret = umoven (tcp,
1459 (unsigned long) ia64_rse_skip_regs(*state, 1),
1460 sizeof(long), (void *) valp);
1461 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001462}
1463#endif
1464
1465static int
1466set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1467{
Roland McGrath08267b82004-02-20 22:56:43 +00001468 int req = PTRACE_POKEDATA;
1469 void *ap;
1470
1471 if (ia32) {
1472 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1473 req = PTRACE_POKEUSER;
1474 } else
1475 ap = ia64_rse_skip_regs(*state, 0);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001476 errno = 0;
Roland McGrath08267b82004-02-20 22:56:43 +00001477 ptrace(req, tcp->pid, ap, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001478 return errno ? -1 : 0;
1479}
1480
1481static int
1482set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1483{
Roland McGrath08267b82004-02-20 22:56:43 +00001484 int req = PTRACE_POKEDATA;
1485 void *ap;
1486
1487 if (ia32) {
1488 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1489 req = PTRACE_POKEUSER;
1490 } else
1491 ap = ia64_rse_skip_regs(*state, 1);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001492 errno = 0;
Roland McGrath08267b82004-02-20 22:56:43 +00001493 ptrace(req, tcp->pid, ap, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001494 return errno ? -1 : 0;
1495}
1496
Roland McGrathb659f872008-07-18 01:19:36 +00001497/* ia64 does not return the input arguments from functions (and syscalls)
1498 according to ia64 RSE (Register Stack Engine) behavior. */
1499
1500# define restore_arg0(tcp, state, val) ((void) (state), 0)
1501# define restore_arg1(tcp, state, val) ((void) (state), 0)
1502
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001503#elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001504
1505typedef struct regs arg_setup_state;
1506
1507# define arg_setup(tcp, state) \
1508 (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
1509# define arg_finish_change(tcp, state) \
1510 (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
1511
1512# define get_arg0(tcp, state, valp) (*(valp) = (state)->r_o0, 0)
1513# define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0)
1514# define set_arg0(tcp, state, val) ((state)->r_o0 = (val), 0)
1515# define set_arg1(tcp, state, val) ((state)->r_o1 = (val), 0)
Roland McGrathe1df47f2003-01-14 09:46:15 +00001516# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001517
1518#else
1519
1520# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001521/* Note: this is only true for the `clone' system call, which handles
1522 arguments specially. We could as well say that its first two arguments
1523 are swapped relative to other architectures, but that would just be
1524 another #ifdef in the calls. */
1525# define arg0_offset PT_GPR3
1526# define arg1_offset PT_ORIGGPR2
1527# define restore_arg0(tcp, state, val) ((void) (state), 0)
1528# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001529# define arg0_index 1
1530# define arg1_index 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001531# elif defined (ALPHA) || defined (MIPS)
1532# define arg0_offset REG_A0
1533# define arg1_offset (REG_A0+1)
1534# elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001535# define arg0_offset (sizeof(unsigned long)*PT_R3)
1536# define arg1_offset (sizeof(unsigned long)*PT_R4)
Roland McGrath7b308222003-01-20 09:04:36 +00001537# define restore_arg0(tcp, state, val) ((void) (state), 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001538# elif defined (HPPA)
1539# define arg0_offset PT_GR26
1540# define arg1_offset (PT_GR26-4)
Roland McGrath7f33cc32003-01-10 20:51:00 +00001541# elif defined (X86_64)
1542# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1543# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
Roland McGrathac971c22003-03-31 01:03:33 +00001544# elif defined (SH)
1545# define arg0_offset (4*(REG_REG0+4))
1546# define arg1_offset (4*(REG_REG0+5))
Roland McGrathf5a47772003-06-26 22:40:42 +00001547# elif defined (SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001548 /* ABI defines arg0 & 1 in r2 & r3 */
1549# define arg0_offset (REG_OFFSET+16)
1550# define arg1_offset (REG_OFFSET+24)
1551# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001552# else
1553# define arg0_offset 0
1554# define arg1_offset 4
Roland McGrathac971c22003-03-31 01:03:33 +00001555# if defined ARM
Roland McGrathe1df47f2003-01-14 09:46:15 +00001556# define restore_arg0(tcp, state, val) 0
1557# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001558# endif
1559
1560typedef int arg_setup_state;
1561
1562# define arg_setup(tcp, state) (0)
1563# define arg_finish_change(tcp, state) 0
1564# define get_arg0(tcp, cookie, valp) \
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001565 (upeek ((tcp), arg0_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001566# define get_arg1(tcp, cookie, valp) \
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001567 (upeek ((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001568
1569static int
1570set_arg0 (struct tcb *tcp, void *cookie, long val)
1571{
Roland McGrathca85b972005-06-07 23:22:08 +00001572 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001573}
1574
1575static int
1576set_arg1 (struct tcb *tcp, void *cookie, long val)
1577{
1578 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
1579}
1580
1581#endif
1582
Roland McGrathe1df47f2003-01-14 09:46:15 +00001583#ifndef restore_arg0
1584# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1585#endif
1586#ifndef restore_arg1
1587# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1588#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001589
Roland McGrath90d0afd2004-03-01 21:05:16 +00001590#ifndef arg0_index
1591# define arg0_index 0
1592# define arg1_index 1
1593#endif
1594
Roland McGrathd81f1d92003-01-09 06:53:34 +00001595int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001596setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001597{
Roland McGrath3291ef22008-05-20 00:34:34 +00001598 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001599 arg_setup_state state;
1600
1601 if (tcp->flags & TCB_BPTSET) {
1602 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1603 return -1;
1604 }
1605
Roland McGrath3291ef22008-05-20 00:34:34 +00001606 /*
1607 * It's a silly kludge to initialize this with a search at runtime.
1608 * But it's better than maintaining another magic thing in the
1609 * godforsaken tables.
1610 */
1611 if (clone_scno[current_personality] == 0) {
1612 int i;
1613 for (i = 0; i < nsyscalls; ++i)
1614 if (sysent[i].sys_func == sys_clone) {
1615 clone_scno[current_personality] = i;
1616 break;
1617 }
1618 }
1619
Roland McGrath76989d72005-06-07 23:21:31 +00001620 switch (known_scno(tcp)) {
Roland McGrath9383c6c2003-01-18 00:19:31 +00001621#ifdef SYS_vfork
1622 case SYS_vfork:
1623#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001624#ifdef SYS_fork
1625 case SYS_fork:
Roland McGrath9b0982b2003-01-18 00:21:51 +00001626#endif
1627#if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001628 if (arg_setup (tcp, &state) < 0
1629 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1630 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001631 || change_syscall(tcp, clone_scno[current_personality]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001632 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1633 || set_arg1 (tcp, &state, 0) < 0
1634 || arg_finish_change (tcp, &state) < 0)
1635 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001636 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1637 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001638 tcp->flags |= TCB_BPTSET;
1639 return 0;
1640#endif
1641
1642 case SYS_clone:
1643#ifdef SYS_clone2
1644 case SYS_clone2:
1645#endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001646 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1647 contrary to x86 SYS_vfork above. Even on x86 we turn the
1648 vfork semantics into plain fork - each application must not
1649 depend on the vfork specifics according to POSIX. We would
1650 hang waiting for the parent resume otherwise. We need to
1651 clear also CLONE_VM but only in the CLONE_VFORK case as
1652 otherwise we would break pthread_create. */
1653
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001654 if ((arg_setup (tcp, &state) < 0
1655 || set_arg0 (tcp, &state,
1656 (tcp->u_arg[arg0_index] | CLONE_PTRACE)
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001657 & ~(tcp->u_arg[arg0_index] & CLONE_VFORK
1658 ? CLONE_VFORK | CLONE_VM : 0)) < 0
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001659 || arg_finish_change (tcp, &state) < 0))
1660 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001661 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001662 tcp->inst[0] = tcp->u_arg[arg0_index];
1663 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001664 return 0;
1665
1666 default:
1667 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1668 tcp->scno, tcp->pid);
1669 break;
1670 }
1671
1672 return -1;
1673}
1674
1675int
1676clearbpt(tcp)
1677struct tcb *tcp;
1678{
1679 arg_setup_state state;
1680 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001681 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1682 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001683 || arg_finish_change (tcp, &state))
1684 return -1;
1685 tcp->flags &= ~TCB_BPTSET;
1686 return 0;
1687}
1688
1689#else
1690
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001691int
1692setbpt(tcp)
1693struct tcb *tcp;
1694{
1695
1696#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001697#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698 /* We simply use the SunOS breakpoint code. */
1699
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001700 struct regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001701 unsigned long inst;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001702#define LOOPA 0x30800000 /* ba,a 0 */
1703
1704 if (tcp->flags & TCB_BPTSET) {
1705 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1706 return -1;
1707 }
1708 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1709 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1710 return -1;
1711 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001712 tcp->baddr = regs.r_o7 + 8;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001713 errno = 0;
1714 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1715 if(errno) {
1716 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1717 return -1;
1718 }
1719
1720 /*
1721 * XXX - BRUTAL MODE ON
1722 * We cannot set a real BPT in the child, since it will not be
1723 * traced at the moment it will reach the trap and would probably
1724 * die with a core dump.
1725 * Thus, we are force our way in by taking out two instructions
1726 * and insert an eternal loop instead, in expectance of the SIGSTOP
1727 * generated by out PTRACE_ATTACH.
1728 * Of cause, if we evaporate ourselves in the middle of all this...
1729 */
1730 errno = 0;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001731 inst = LOOPA;
1732#if defined (SPARC64)
1733 inst <<= 32;
1734 inst |= (tcp->inst[0] & 0xffffffffUL);
1735#endif
1736 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, inst);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001737 if(errno) {
1738 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1739 return -1;
1740 }
1741 tcp->flags |= TCB_BPTSET;
1742
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001743#else /* !SPARC && !SPARC64 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001744#ifdef IA64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001745 if (ia32) {
1746# define LOOP 0x0000feeb
1747 if (tcp->flags & TCB_BPTSET) {
1748 fprintf(stderr, "PANIC: bpt already set in pid %u\n",
1749 tcp->pid);
1750 return -1;
1751 }
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001752 if (upeek(tcp, PT_CR_IIP, &tcp->baddr) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001753 return -1;
1754 if (debug)
1755 fprintf(stderr, "[%d] setting bpt at %lx\n",
1756 tcp->pid, tcp->baddr);
1757 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid,
1758 (char *) tcp->baddr, 0);
1759 if (errno) {
1760 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1761 return -1;
1762 }
1763 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1764 if (errno) {
1765 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1766 return -1;
1767 }
1768 tcp->flags |= TCB_BPTSET;
1769 } else {
1770 /*
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001771 * Our strategy here is to replace the bundle that
1772 * contained the clone() syscall with a bundle of the
1773 * form:
1774 *
1775 * { 1: br 1b; br 1b; br 1b }
1776 *
1777 * This ensures that the newly forked child will loop
1778 * endlessly until we've got a chance to attach to it.
1779 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001780# define LOOP0 0x0000100000000017
1781# define LOOP1 0x4000000000200000
1782 unsigned long addr, ipsr;
1783 pid_t pid;
1784
1785 pid = tcp->pid;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001786 if (upeek(tcp, PT_CR_IPSR, &ipsr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001787 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001788 if (upeek(tcp, PT_CR_IIP, &addr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001789 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001790 /* store "ri" in low two bits */
1791 tcp->baddr = addr | ((ipsr >> 41) & 0x3);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001792
1793 errno = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001794 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0,
1795 0);
1796 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8,
1797 0);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001798 if (errno) {
1799 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1800 return -1;
1801 }
1802
1803 errno = 0;
1804 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1805 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1806 if (errno) {
1807 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1808 return -1;
1809 }
1810 tcp->flags |= TCB_BPTSET;
1811 }
1812#else /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001813
Michal Ludvig0e035502002-09-23 15:41:01 +00001814#if defined (I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001815#define LOOP 0x0000feeb
1816#elif defined (M68K)
1817#define LOOP 0x60fe0000
1818#elif defined (ALPHA)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001819#define LOOP 0xc3ffffff
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001820#elif defined (POWERPC)
Roland McGrath1e85cf92002-12-16 20:40:54 +00001821#define LOOP 0x48000000
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001822#elif defined(ARM)
Wichert Akkerman9a8a37f1999-12-24 23:19:31 +00001823#define LOOP 0xEAFFFFFE
Wichert Akkermanf90da011999-10-31 21:15:38 +00001824#elif defined(MIPS)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001825#define LOOP 0x1000ffff
1826#elif defined(S390)
1827#define LOOP 0xa7f40000 /* BRC 15,0 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001828#elif defined(S390X)
1829#define LOOP 0xa7f4000000000000UL /* BRC 15,0 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001830#elif defined(HPPA)
1831#define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001832#elif defined(SH)
1833#ifdef __LITTLE_ENDIAN__
1834#define LOOP 0x0000affe
1835#else
1836#define LOOP 0xfeaf0000
1837#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001838#else
1839#error unknown architecture
1840#endif
1841
1842 if (tcp->flags & TCB_BPTSET) {
1843 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1844 return -1;
1845 }
1846#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001847 if (upeek(tcp, 4*EIP, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001848 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00001849#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001850 if (upeek(tcp, 8*RIP, &tcp->baddr) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001851 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001852#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001853 if (upeek(tcp, 4*PT_PC, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001854 return -1;
1855#elif defined (ALPHA)
1856 return -1;
1857#elif defined (ARM)
1858 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001859#elif defined (MIPS)
1860 return -1; /* FIXME: I do not know what i do - Flo */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001861#elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001862 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001863 return -1;
Michal Ludvig10a88d02002-10-07 14:31:00 +00001864#elif defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001865 if (upeek(tcp,PT_PSWADDR, &tcp->baddr) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001866 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001867#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001868 if (upeek(tcp, PT_IAOQ0, &tcp->baddr) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001869 return -1;
1870 tcp->baddr &= ~0x03;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001871#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001872 if (upeek(tcp, 4*REG_PC, &tcp->baddr) < 0)
1873 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001874#else
1875#error unknown architecture
1876#endif
1877 if (debug)
1878 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1879 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1880 if (errno) {
1881 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1882 return -1;
1883 }
1884 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1885 if (errno) {
1886 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1887 return -1;
1888 }
1889 tcp->flags |= TCB_BPTSET;
1890
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001891#endif /* !IA64 */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001892#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001893#endif /* LINUX */
1894
1895#ifdef SUNOS4
1896#ifdef SPARC /* This code is slightly sparc specific */
1897
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001898 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001899#define BPT 0x91d02001 /* ta 1 */
1900#define LOOP 0x10800000 /* ba 0 */
1901#define LOOPA 0x30800000 /* ba,a 0 */
1902#define NOP 0x01000000
1903#if LOOPA
1904 static int loopdeloop[1] = {LOOPA};
1905#else
1906 static int loopdeloop[2] = {LOOP, NOP};
1907#endif
1908
1909 if (tcp->flags & TCB_BPTSET) {
1910 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1911 return -1;
1912 }
1913 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1914 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1915 return -1;
1916 }
1917 tcp->baddr = regs.r_o7 + 8;
1918 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1919 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1920 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1921 return -1;
1922 }
1923
1924 /*
1925 * XXX - BRUTAL MODE ON
1926 * We cannot set a real BPT in the child, since it will not be
1927 * traced at the moment it will reach the trap and would probably
1928 * die with a core dump.
1929 * Thus, we are force our way in by taking out two instructions
1930 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1931 * generated by out PTRACE_ATTACH.
1932 * Of cause, if we evaporate ourselves in the middle of all this...
1933 */
1934 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1935 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1936 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1937 return -1;
1938 }
1939 tcp->flags |= TCB_BPTSET;
1940
1941#endif /* SPARC */
1942#endif /* SUNOS4 */
1943
1944 return 0;
1945}
1946
1947int
1948clearbpt(tcp)
1949struct tcb *tcp;
1950{
1951
1952#ifdef LINUX
Michal Ludvig0e035502002-09-23 15:41:01 +00001953#if defined(I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001954 long eip;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001955#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001956 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001957#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001958 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001959#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001960 long pc;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001961#elif defined(HPPA)
1962 long iaoq;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001963#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001964 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001965#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001966
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001967#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001968 /* Again, we borrow the SunOS breakpoint code. */
1969 if (!(tcp->flags & TCB_BPTSET)) {
1970 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1971 return -1;
1972 }
1973 errno = 0;
1974 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1975 if(errno) {
1976 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1977 return -1;
1978 }
1979 tcp->flags &= ~TCB_BPTSET;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001980#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001981 if (ia32) {
1982 unsigned long addr;
1983
1984 if (debug)
1985 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1986 if (!(tcp->flags & TCB_BPTSET)) {
1987 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1988 return -1;
1989 }
1990 errno = 0;
1991 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1992 if (errno) {
1993 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1994 return -1;
1995 }
1996 tcp->flags &= ~TCB_BPTSET;
1997
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001998 if (upeek(tcp, PT_CR_IIP, &addr) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001999 return -1;
2000 if (addr != tcp->baddr) {
2001 /* The breakpoint has not been reached yet. */
2002 if (debug)
2003 fprintf(stderr,
2004 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2005 addr, tcp->baddr);
2006 return 0;
2007 }
2008 } else {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002009 unsigned long addr, ipsr;
2010 pid_t pid;
2011
2012 pid = tcp->pid;
2013
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002014 if (upeek(tcp, PT_CR_IPSR, &ipsr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002015 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002016 if (upeek(tcp, PT_CR_IIP, &addr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002017 return -1;
2018
2019 /* restore original bundle: */
2020 errno = 0;
2021 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
2022 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
2023 if (errno) {
2024 perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
2025 return -1;
2026 }
2027
2028 /* restore original "ri" in ipsr: */
2029 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
2030 errno = 0;
2031 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
2032 if (errno) {
2033 perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
2034 return -1;
2035 }
2036
2037 tcp->flags &= ~TCB_BPTSET;
2038
2039 if (addr != (tcp->baddr & ~0x3)) {
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 addr, tcp->baddr);
2044 return 0;
2045 }
2046 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002047#else /* !IA64 && !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002048
2049 if (debug)
2050 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
2051 if (!(tcp->flags & TCB_BPTSET)) {
2052 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
2053 return -1;
2054 }
2055 errno = 0;
2056 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
2057 if (errno) {
2058 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
2059 return -1;
2060 }
2061 tcp->flags &= ~TCB_BPTSET;
2062
2063#ifdef I386
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002064 if (upeek(tcp, 4*EIP, &eip) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002065 return -1;
2066 if (eip != tcp->baddr) {
2067 /* The breakpoint has not been reached yet. */
2068 if (debug)
2069 fprintf(stderr,
2070 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2071 eip, tcp->baddr);
2072 return 0;
2073 }
Michal Ludvig0e035502002-09-23 15:41:01 +00002074#elif defined(X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002075 if (upeek(tcp, 8*RIP, &eip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002076 return -1;
2077 if (eip != tcp->baddr) {
2078 /* The breakpoint has not been reached yet. */
2079 if (debug)
2080 fprintf(stderr,
2081 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2082 eip, tcp->baddr);
2083 return 0;
2084 }
Wichert Akkermanc7926982000-04-10 22:22:31 +00002085#elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002086 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002087 return -1;
2088 if (pc != tcp->baddr) {
2089 /* The breakpoint has not been reached yet. */
2090 if (debug)
2091 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2092 pc, tcp->baddr);
2093 return 0;
2094 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002095#elif defined(M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002096 if (upeek(tcp, 4*PT_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002097 return -1;
2098 if (pc != tcp->baddr) {
2099 /* The breakpoint has not been reached yet. */
2100 if (debug)
2101 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2102 pc, tcp->baddr);
2103 return 0;
2104 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002105#elif defined(ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002106 if (upeek(tcp, REG_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002107 return -1;
2108 if (pc != tcp->baddr) {
2109 /* The breakpoint has not been reached yet. */
2110 if (debug)
2111 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2112 pc, tcp->baddr);
2113 return 0;
2114 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002115#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002116 if (upeek(tcp, PT_IAOQ0, &iaoq) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002117 return -1;
2118 iaoq &= ~0x03;
2119 if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
2120 /* The breakpoint has not been reached yet. */
2121 if (debug)
2122 fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
2123 iaoq, tcp->baddr);
2124 return 0;
2125 }
2126 iaoq = tcp->baddr | 3;
2127 /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
2128 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
2129 * has no significant effect.
2130 */
2131 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
2132 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
Wichert Akkermanccef6372002-05-01 16:39:22 +00002133#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002134 if (upeek(tcp, 4*REG_PC, &pc) < 0)
2135 return -1;
2136 if (pc != tcp->baddr) {
2137 /* The breakpoint has not been reached yet. */
2138 if (debug)
2139 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2140 pc, tcp->baddr);
2141 return 0;
2142 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002143
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002144#endif /* arch */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002145#endif /* !SPARC && !SPARC64 && !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002146#endif /* LINUX */
2147
2148#ifdef SUNOS4
2149#ifdef SPARC
2150
2151#if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00002152 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002153#endif
2154
2155 if (!(tcp->flags & TCB_BPTSET)) {
2156 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
2157 return -1;
2158 }
2159 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
2160 sizeof tcp->inst, (char *) tcp->inst) < 0) {
2161 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
2162 return -1;
2163 }
2164 tcp->flags &= ~TCB_BPTSET;
2165
2166#if !LOOPA
2167 /*
2168 * Since we don't have a single instruction breakpoint, we may have
2169 * to adjust the program counter after removing the our `breakpoint'.
2170 */
2171 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
2172 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
2173 return -1;
2174 }
2175 if ((regs.r_pc < tcp->baddr) ||
2176 (regs.r_pc > tcp->baddr + 4)) {
2177 /* The breakpoint has not been reached yet */
2178 if (debug)
2179 fprintf(stderr,
2180 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
2181 regs.r_pc, tcp->parent->baddr);
2182 return 0;
2183 }
2184 if (regs.r_pc != tcp->baddr)
2185 if (debug)
2186 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
2187 regs.r_pc, tcp->baddr);
2188
2189 regs.r_pc = tcp->baddr;
2190 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
2191 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
2192 return -1;
2193 }
2194#endif /* LOOPA */
2195#endif /* SPARC */
2196#endif /* SUNOS4 */
2197
2198 return 0;
2199}
2200
Roland McGrathd81f1d92003-01-09 06:53:34 +00002201#endif
2202
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002203#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002204
2205#ifdef SUNOS4
2206
2207static int
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002208getex(tcp, hdr)
2209struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002210struct exec *hdr;
2211{
2212 int n;
2213
2214 for (n = 0; n < sizeof *hdr; n += 4) {
2215 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002216 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002217 return -1;
2218 memcpy(((char *) hdr) + n, &res, 4);
2219 }
2220 if (debug) {
2221 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
2222 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
2223 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
2224 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
2225 }
2226 return 0;
2227}
2228
2229int
2230fixvfork(tcp)
2231struct tcb *tcp;
2232{
2233 int pid = tcp->pid;
2234 /*
2235 * Change `vfork' in a freshly exec'ed dynamically linked
2236 * executable's (internal) symbol table to plain old `fork'
2237 */
2238
2239 struct exec hdr;
2240 struct link_dynamic dyn;
2241 struct link_dynamic_2 ld;
2242 char *strtab, *cp;
2243
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002244 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002245 return -1;
2246 if (!hdr.a_dynamic)
2247 return -1;
2248
2249 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
2250 fprintf(stderr, "Cannot read DYNAMIC\n");
2251 return -1;
2252 }
2253 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
2254 fprintf(stderr, "Cannot read link_dynamic_2\n");
2255 return -1;
2256 }
2257 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00002258 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002259 return -1;
2260 }
2261 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
2262 (int)ld.ld_symb_size, strtab) < 0)
2263 goto err;
2264
2265#if 0
2266 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2267 fprintf(stderr, "[symbol: %s]\n", cp);
2268 cp += strlen(cp)+1;
2269 }
2270 return 0;
2271#endif
2272 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2273 if (strcmp(cp, "_vfork") == 0) {
2274 if (debug)
2275 fprintf(stderr, "fixvfork: FOUND _vfork\n");
2276 strcpy(cp, "_fork");
2277 break;
2278 }
2279 cp += strlen(cp)+1;
2280 }
2281 if (cp < strtab + ld.ld_symb_size)
2282 /*
2283 * Write entire symbol table back to avoid
2284 * memory alignment bugs in ptrace
2285 */
2286 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
2287 (int)ld.ld_symb_size, strtab) < 0)
2288 goto err;
2289
2290 free(strtab);
2291 return 0;
2292
2293err:
2294 free(strtab);
2295 return -1;
2296}
2297
2298#endif /* SUNOS4 */