blob: ac9255136e378a3f2e7c749acc3373749090f196 [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
788umoven(tcp, addr, len, laddr)
789struct tcb *tcp;
790long addr;
791int len;
792char *laddr;
793{
794
795#ifdef LINUX
796 int pid = tcp->pid;
797 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000798 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799 union {
800 long val;
801 char x[sizeof(long)];
802 } u;
803
804 if (addr & (sizeof(long) - 1)) {
805 /* addr not a multiple of sizeof(long) */
806 n = addr - (addr & -sizeof(long)); /* residue */
807 addr &= -sizeof(long); /* residue */
808 errno = 0;
809 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
810 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000811 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000812 /* Ran into 'end of memory' - stupid "printpath" */
813 return 0;
814 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000815 /* But if not started, we had a bogus address. */
Roland McGrath1c459762007-08-02 02:22:06 +0000816 if (addr != 0 && errno != EIO)
817 perror("ptrace: umoven");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000818 return -1;
819 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000820 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000821 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
822 addr += sizeof(long), laddr += m, len -= m;
823 }
824 while (len) {
825 errno = 0;
826 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
827 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000828 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000829 /* Ran into 'end of memory' - stupid "printpath" */
830 return 0;
831 }
Roland McGrath1c459762007-08-02 02:22:06 +0000832 if (addr != 0 && errno != EIO)
Roland McGrath4db26242003-01-30 20:15:19 +0000833 perror("ptrace: umoven");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000834 return -1;
835 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000836 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000837 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
838 addr += sizeof(long), laddr += m, len -= m;
839 }
840#endif /* LINUX */
841
842#ifdef SUNOS4
843 int pid = tcp->pid;
844#if 0
845 int n, m;
846 union {
847 long val;
848 char x[sizeof(long)];
849 } u;
850
851 if (addr & (sizeof(long) - 1)) {
852 /* addr not a multiple of sizeof(long) */
853 n = addr - (addr & -sizeof(long)); /* residue */
854 addr &= -sizeof(long); /* residue */
855 errno = 0;
856 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
857 if (errno) {
858 perror("umoven");
859 return -1;
860 }
861 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
862 addr += sizeof(long), laddr += m, len -= m;
863 }
864 while (len) {
865 errno = 0;
866 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
867 if (errno) {
868 perror("umoven");
869 return -1;
870 }
871 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
872 addr += sizeof(long), laddr += m, len -= m;
873 }
874#else /* !oldway */
875 int n;
876
877 while (len) {
878 n = MIN(len, PAGSIZ);
879 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
880 if (ptrace(PTRACE_READDATA, pid,
881 (char *) addr, len, laddr) < 0) {
882 perror("umoven: ptrace(PTRACE_READDATA, ...)");
883 abort();
884 return -1;
885 }
886 len -= n;
887 addr += n;
888 laddr += n;
889 }
890#endif /* !oldway */
891#endif /* SUNOS4 */
892
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000893#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000894#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000895 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000896#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000897 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000898#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000899 lseek(fd, addr, SEEK_SET);
900 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000901 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000902#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000903
904 return 0;
905}
906
907/*
908 * like `umove' but make the additional effort of looking
909 * for a terminating zero byte.
910 */
911int
912umovestr(tcp, addr, len, laddr)
913struct tcb *tcp;
914long addr;
915int len;
916char *laddr;
917{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000918#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000919#ifdef HAVE_MP_PROCFS
920 int fd = tcp->pfd_as;
921#else
922 int fd = tcp->pfd;
923#endif
924 /* Some systems (e.g. FreeBSD) can be upset if we read off the
925 end of valid memory, avoid this by trying to read up
926 to page boundaries. But we don't know what a page is (and
927 getpagesize(2) (if it exists) doesn't necessarily return
928 hardware page size). Assume all pages >= 1024 (a-historical
929 I know) */
930
931 int page = 1024; /* How to find this? */
932 int move = page - (addr & (page - 1));
933 int left = len;
934
935 lseek(fd, addr, SEEK_SET);
936
937 while (left) {
938 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000939 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000940 return left != len ? 0 : -1;
941 if (memchr (laddr, 0, move)) break;
942 left -= move;
943 laddr += move;
944 addr += move;
945 move = page;
946 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000947#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000948 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000949 int pid = tcp->pid;
950 int i, n, m;
951 union {
952 long val;
953 char x[sizeof(long)];
954 } u;
955
956 if (addr & (sizeof(long) - 1)) {
957 /* addr not a multiple of sizeof(long) */
958 n = addr - (addr & -sizeof(long)); /* residue */
959 addr &= -sizeof(long); /* residue */
960 errno = 0;
961 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
962 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000963 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000964 /* Ran into 'end of memory' - stupid "printpath" */
965 return 0;
966 }
Roland McGrath1c459762007-08-02 02:22:06 +0000967 if (addr != 0 && errno != EIO)
968 perror("umovestr");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000969 return -1;
970 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000971 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000972 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
973 while (n & (sizeof(long) - 1))
974 if (u.x[n++] == '\0')
975 return 0;
976 addr += sizeof(long), laddr += m, len -= m;
977 }
978 while (len) {
979 errno = 0;
980 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
981 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000982 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000983 /* Ran into 'end of memory' - stupid "printpath" */
984 return 0;
985 }
Roland McGrath1c459762007-08-02 02:22:06 +0000986 if (addr != 0 && errno != EIO)
987 perror("umovestr");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000988 return -1;
989 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000990 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
992 for (i = 0; i < sizeof(long); i++)
993 if (u.x[i] == '\0')
994 return 0;
995
996 addr += sizeof(long), laddr += m, len -= m;
997 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000998#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000999 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001000}
1001
1002#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001003#if !defined (SPARC) && !defined(SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001004#define PTRACE_WRITETEXT 101
1005#define PTRACE_WRITEDATA 102
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001006#endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001007#endif /* LINUX */
1008
1009#ifdef SUNOS4
1010
1011static int
1012uload(cmd, pid, addr, len, laddr)
1013int cmd;
1014int pid;
1015long addr;
1016int len;
1017char *laddr;
1018{
1019#if 0
1020 int n;
1021
1022 while (len) {
1023 n = MIN(len, PAGSIZ);
1024 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
1025 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
1026 perror("uload: ptrace(PTRACE_WRITE, ...)");
1027 return -1;
1028 }
1029 len -= n;
1030 addr += n;
1031 laddr += n;
1032 }
1033#else
1034 int peek, poke;
1035 int n, m;
1036 union {
1037 long val;
1038 char x[sizeof(long)];
1039 } u;
1040
1041 if (cmd == PTRACE_WRITETEXT) {
1042 peek = PTRACE_PEEKTEXT;
1043 poke = PTRACE_POKETEXT;
1044 }
1045 else {
1046 peek = PTRACE_PEEKDATA;
1047 poke = PTRACE_POKEDATA;
1048 }
1049 if (addr & (sizeof(long) - 1)) {
1050 /* addr not a multiple of sizeof(long) */
1051 n = addr - (addr & -sizeof(long)); /* residue */
1052 addr &= -sizeof(long);
1053 errno = 0;
1054 u.val = ptrace(peek, pid, (char *) addr, 0);
1055 if (errno) {
1056 perror("uload: POKE");
1057 return -1;
1058 }
1059 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
1060 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
1061 perror("uload: POKE");
1062 return -1;
1063 }
1064 addr += sizeof(long), laddr += m, len -= m;
1065 }
1066 while (len) {
1067 if (len < sizeof(long))
1068 u.val = ptrace(peek, pid, (char *) addr, 0);
1069 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
1070 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1071 perror("uload: POKE");
1072 return -1;
1073 }
1074 addr += sizeof(long), laddr += m, len -= m;
1075 }
1076#endif
1077 return 0;
1078}
1079
1080int
1081tload(pid, addr, len, laddr)
1082int pid;
1083int addr, len;
1084char *laddr;
1085{
1086 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1087}
1088
1089int
1090dload(pid, addr, len, laddr)
1091int pid;
1092int addr;
1093int len;
1094char *laddr;
1095{
1096 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
1097}
1098
1099#endif /* SUNOS4 */
1100
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001101#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102
1103int
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001104upeek(tcp, off, res)
1105struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001106long off;
1107long *res;
1108{
1109 long val;
1110
1111#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
1112 {
1113 static int is_sun4m = -1;
1114 struct utsname name;
1115
1116 /* Round up the usual suspects. */
1117 if (is_sun4m == -1) {
1118 if (uname(&name) < 0) {
1119 perror("upeek: uname?");
1120 exit(1);
1121 }
1122 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1123 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001124 extern const struct xlat struct_user_offsets[];
1125 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001126
1127 for (x = struct_user_offsets; x->str; x++)
1128 x->val += 1024;
1129 }
1130 }
1131 if (is_sun4m)
1132 off += 1024;
1133 }
1134#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
1135 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001136 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001137 if (val == -1 && errno) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001138 if (errno != ESRCH) {
1139 char buf[60];
1140 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
1141 perror(buf);
1142 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001143 return -1;
1144 }
1145 *res = val;
1146 return 0;
1147}
1148
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001149#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001150
Roland McGratha4d48532005-06-08 20:45:28 +00001151#if 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001152long
1153getpc(tcp)
1154struct tcb *tcp;
1155{
1156
1157#ifdef LINUX
1158 long pc;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001159#if defined(I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001160 if (upeek(tcp, 4*EIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001161 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00001162#elif defined(X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001163 if (upeek(tcp, 8*RIP, &pc) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001164 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001165#elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001166 if (upeek(tcp, PT_B0, &pc) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001167 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001168#elif defined(ARM)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001169 if (upeek(tcp, 4*15, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001170 return -1;
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001171#elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001172 if (upeek(tcp, REG_PC, &pc) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001173 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001174#elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001175 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176 return -1;
Roland McGrath84fa9232005-06-08 18:06:22 +00001177#elif defined(M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001178 if (upeek(tcp, 4*PT_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001180#elif defined(ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001181 if (upeek(tcp, REG_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001182 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001183#elif defined(MIPS)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001184 if (upeek(tcp, REG_EPC, &pc) < 0)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001185 return -1;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001186#elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001187 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001188 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
1189 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001190 pc = regs.r_pc;
Michal Ludvig10a88d02002-10-07 14:31:00 +00001191#elif defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001192 if(upeek(tcp,PT_PSWADDR,&pc) < 0)
Michal Ludvig10a88d02002-10-07 14:31:00 +00001193 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001194#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001195 if(upeek(tcp,PT_IAOQ0,&pc) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001196 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001197#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001198 if (upeek(tcp, 4*REG_PC ,&pc) < 0)
1199 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001200#elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001201 if (upeek(tcp, REG_PC ,&pc) < 0)
1202 return -1;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +00001203#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001204 return pc;
1205#endif /* LINUX */
1206
1207#ifdef SUNOS4
1208 /*
1209 * Return current program counter for `pid'
1210 * Assumes PC is never 0xffffffff
1211 */
1212 struct regs regs;
1213
1214 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1215 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
1216 return -1;
1217 }
1218 return regs.r_pc;
1219#endif /* SUNOS4 */
1220
1221#ifdef SVR4
1222 /* XXX */
1223 return 0;
1224#endif /* SVR4 */
1225
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001226#ifdef FREEBSD
1227 struct reg regs;
1228 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1229 return regs.r_eip;
1230#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231}
Roland McGratha4d48532005-06-08 20:45:28 +00001232#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001233
1234void
1235printcall(tcp)
1236struct tcb *tcp;
1237{
Roland McGrath7a918832005-02-02 20:55:23 +00001238#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1239 sizeof(long) == 8 ? "[????????????????] " : \
1240 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001241
1242#ifdef LINUX
1243#ifdef I386
1244 long eip;
1245
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001246 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001247 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001248 return;
1249 }
1250 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001251
1252#elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001253 long psw;
1254 if(upeek(tcp,PT_PSWADDR,&psw) < 0) {
1255 PRINTBADPC;
1256 return;
1257 }
Roland McGratheac26fc2005-02-02 02:48:53 +00001258#ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001259 tprintf("[%08lx] ", psw);
Roland McGratheac26fc2005-02-02 02:48:53 +00001260#elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001261 tprintf("[%16lx] ", psw);
Roland McGratheac26fc2005-02-02 02:48:53 +00001262#endif
1263
Michal Ludvig0e035502002-09-23 15:41:01 +00001264#elif defined(X86_64)
1265 long rip;
1266
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001267 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001268 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001269 return;
1270 }
1271 tprintf("[%16lx] ", rip);
Roland McGrathef388682003-06-03 23:28:59 +00001272#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001273 long ip;
1274
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001275 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001276 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001277 return;
1278 }
1279 tprintf("[%08lx] ", ip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001280#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001281 long pc;
1282
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001283 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001284 tprintf ("[????????] ");
1285 return;
1286 }
1287 tprintf("[%08lx] ", pc);
Roland McGrath84fa9232005-06-08 18:06:22 +00001288#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001289 long pc;
1290
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001291 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001292 tprintf ("[????????] ");
1293 return;
1294 }
1295 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001296#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001297 long pc;
1298
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001299 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001300 tprintf ("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001301 return;
1302 }
1303 tprintf("[%08lx] ", pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001304#elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001305 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001306 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001307 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001308 return;
1309 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001310 tprintf("[%08lx] ", regs.r_pc);
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001311#elif defined(HPPA)
1312 long pc;
1313
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001314 if(upeek(tcp,PT_IAOQ0,&pc) < 0) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001315 tprintf ("[????????] ");
1316 return;
1317 }
1318 tprintf("[%08lx] ", pc);
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001319#elif defined(MIPS)
1320 long pc;
1321
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001322 if (upeek(tcp, REG_EPC, &pc) < 0) {
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001323 tprintf ("[????????] ");
1324 return;
1325 }
1326 tprintf("[%08lx] ", pc);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001327#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001328 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001329
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001330 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
1331 tprintf ("[????????] ");
1332 return;
1333 }
1334 tprintf("[%08lx] ", pc);
Roland McGrathf5a47772003-06-26 22:40:42 +00001335#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001336 long pc;
1337
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001338 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001339 tprintf ("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001340 return;
1341 }
1342 tprintf("[%08lx] ", pc);
Roland McGrathef388682003-06-03 23:28:59 +00001343#elif defined(ARM)
1344 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001345
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001346 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001347 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001348 return;
1349 }
1350 tprintf("[%08lx] ", pc);
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001351#elif defined(BFIN)
1352 long pc;
1353
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001354 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001355 PRINTBADPC;
1356 return;
1357 }
1358 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001359#endif /* !architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001360#endif /* LINUX */
1361
1362#ifdef SUNOS4
1363 struct regs regs;
1364
1365 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1366 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001367 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001368 return;
1369 }
1370 tprintf("[%08x] ", regs.r_o7);
1371#endif /* SUNOS4 */
1372
1373#ifdef SVR4
1374 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001375 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376#endif
1377
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001378#ifdef FREEBSD
1379 struct reg regs;
1380 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1381 tprintf("[%08x] ", regs.r_eip);
1382#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001383}
1384
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001385#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001386
Roland McGrathd81f1d92003-01-09 06:53:34 +00001387#if defined LINUX
1388
Roland McGrath3291ef22008-05-20 00:34:34 +00001389#include "syscall.h"
1390
Roland McGrathd81f1d92003-01-09 06:53:34 +00001391#include <sys/syscall.h>
1392#ifndef CLONE_PTRACE
1393# define CLONE_PTRACE 0x00002000
1394#endif
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001395#ifndef CLONE_VFORK
1396# define CLONE_VFORK 0x00004000
1397#endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001398#ifndef CLONE_VM
1399# define CLONE_VM 0x00000100
1400#endif
Roland McGrath76989d72005-06-07 23:21:31 +00001401#ifndef CLONE_STOPPED
1402# define CLONE_STOPPED 0x02000000
1403#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001404
1405#ifdef IA64
1406
Roland McGrath08267b82004-02-20 22:56:43 +00001407/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1408 subsystem has them for x86... */
1409#define SYS_fork 2
1410#define SYS_vfork 190
1411
Roland McGrathd81f1d92003-01-09 06:53:34 +00001412typedef unsigned long *arg_setup_state;
1413
1414static int
1415arg_setup(struct tcb *tcp, arg_setup_state *state)
1416{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001417 unsigned long cfm, sof, sol;
1418 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001419
Jan Kratochvil1f942712008-08-06 21:38:52 +00001420 if (ia32) {
1421 /* Satisfy a false GCC warning. */
1422 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001423 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001424 }
Roland McGrath08267b82004-02-20 22:56:43 +00001425
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001426 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001427 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001428 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001429 return -1;
1430
1431 sof = (cfm >> 0) & 0x7f;
1432 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001433 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001434
Jan Kratochvil1f942712008-08-06 21:38:52 +00001435 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001436 return 0;
1437}
1438
1439# define arg_finish_change(tcp, state) 0
1440
1441#ifdef SYS_fork
1442static int
1443get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1444{
Roland McGrath08267b82004-02-20 22:56:43 +00001445 int ret;
1446
1447 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001448 ret = upeek (tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001449 else
1450 ret = umoven (tcp,
1451 (unsigned long) ia64_rse_skip_regs(*state, 0),
1452 sizeof(long), (void *) valp);
1453 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001454}
1455
1456static int
1457get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1458{
Roland McGrath08267b82004-02-20 22:56:43 +00001459 int ret;
1460
1461 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001462 ret = upeek (tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001463 else
1464 ret = umoven (tcp,
1465 (unsigned long) ia64_rse_skip_regs(*state, 1),
1466 sizeof(long), (void *) valp);
1467 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001468}
1469#endif
1470
1471static int
1472set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1473{
Roland McGrath08267b82004-02-20 22:56:43 +00001474 int req = PTRACE_POKEDATA;
1475 void *ap;
1476
1477 if (ia32) {
1478 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1479 req = PTRACE_POKEUSER;
1480 } else
1481 ap = ia64_rse_skip_regs(*state, 0);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001482 errno = 0;
Roland McGrath08267b82004-02-20 22:56:43 +00001483 ptrace(req, tcp->pid, ap, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001484 return errno ? -1 : 0;
1485}
1486
1487static int
1488set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1489{
Roland McGrath08267b82004-02-20 22:56:43 +00001490 int req = PTRACE_POKEDATA;
1491 void *ap;
1492
1493 if (ia32) {
1494 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1495 req = PTRACE_POKEUSER;
1496 } else
1497 ap = ia64_rse_skip_regs(*state, 1);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001498 errno = 0;
Roland McGrath08267b82004-02-20 22:56:43 +00001499 ptrace(req, tcp->pid, ap, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001500 return errno ? -1 : 0;
1501}
1502
Roland McGrathb659f872008-07-18 01:19:36 +00001503/* ia64 does not return the input arguments from functions (and syscalls)
1504 according to ia64 RSE (Register Stack Engine) behavior. */
1505
1506# define restore_arg0(tcp, state, val) ((void) (state), 0)
1507# define restore_arg1(tcp, state, val) ((void) (state), 0)
1508
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001509#elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001510
1511typedef struct regs arg_setup_state;
1512
1513# define arg_setup(tcp, state) \
1514 (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
1515# define arg_finish_change(tcp, state) \
1516 (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
1517
1518# define get_arg0(tcp, state, valp) (*(valp) = (state)->r_o0, 0)
1519# define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0)
1520# define set_arg0(tcp, state, val) ((state)->r_o0 = (val), 0)
1521# define set_arg1(tcp, state, val) ((state)->r_o1 = (val), 0)
Roland McGrathe1df47f2003-01-14 09:46:15 +00001522# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001523
1524#else
1525
1526# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001527/* Note: this is only true for the `clone' system call, which handles
1528 arguments specially. We could as well say that its first two arguments
1529 are swapped relative to other architectures, but that would just be
1530 another #ifdef in the calls. */
1531# define arg0_offset PT_GPR3
1532# define arg1_offset PT_ORIGGPR2
1533# define restore_arg0(tcp, state, val) ((void) (state), 0)
1534# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001535# define arg0_index 1
1536# define arg1_index 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001537# elif defined (ALPHA) || defined (MIPS)
1538# define arg0_offset REG_A0
1539# define arg1_offset (REG_A0+1)
1540# elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001541# define arg0_offset (sizeof(unsigned long)*PT_R3)
1542# define arg1_offset (sizeof(unsigned long)*PT_R4)
Roland McGrath7b308222003-01-20 09:04:36 +00001543# define restore_arg0(tcp, state, val) ((void) (state), 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001544# elif defined (HPPA)
1545# define arg0_offset PT_GR26
1546# define arg1_offset (PT_GR26-4)
Roland McGrath7f33cc32003-01-10 20:51:00 +00001547# elif defined (X86_64)
1548# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1549# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
Roland McGrathac971c22003-03-31 01:03:33 +00001550# elif defined (SH)
1551# define arg0_offset (4*(REG_REG0+4))
1552# define arg1_offset (4*(REG_REG0+5))
Roland McGrathf5a47772003-06-26 22:40:42 +00001553# elif defined (SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001554 /* ABI defines arg0 & 1 in r2 & r3 */
1555# define arg0_offset (REG_OFFSET+16)
1556# define arg1_offset (REG_OFFSET+24)
1557# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001558# else
1559# define arg0_offset 0
1560# define arg1_offset 4
Roland McGrathac971c22003-03-31 01:03:33 +00001561# if defined ARM
Roland McGrathe1df47f2003-01-14 09:46:15 +00001562# define restore_arg0(tcp, state, val) 0
1563# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001564# endif
1565
1566typedef int arg_setup_state;
1567
1568# define arg_setup(tcp, state) (0)
1569# define arg_finish_change(tcp, state) 0
1570# define get_arg0(tcp, cookie, valp) \
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001571 (upeek ((tcp), arg0_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001572# define get_arg1(tcp, cookie, valp) \
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001573 (upeek ((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001574
1575static int
1576set_arg0 (struct tcb *tcp, void *cookie, long val)
1577{
Roland McGrathca85b972005-06-07 23:22:08 +00001578 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001579}
1580
1581static int
1582set_arg1 (struct tcb *tcp, void *cookie, long val)
1583{
1584 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
1585}
1586
1587#endif
1588
Roland McGrathe1df47f2003-01-14 09:46:15 +00001589#ifndef restore_arg0
1590# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1591#endif
1592#ifndef restore_arg1
1593# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1594#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001595
Roland McGrath90d0afd2004-03-01 21:05:16 +00001596#ifndef arg0_index
1597# define arg0_index 0
1598# define arg1_index 1
1599#endif
1600
Roland McGrathd81f1d92003-01-09 06:53:34 +00001601int
1602setbpt(tcp)
1603struct tcb *tcp;
1604{
Roland McGrath3291ef22008-05-20 00:34:34 +00001605 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001606 extern int change_syscall(struct tcb *, int);
1607 arg_setup_state state;
1608
1609 if (tcp->flags & TCB_BPTSET) {
1610 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1611 return -1;
1612 }
1613
Roland McGrath3291ef22008-05-20 00:34:34 +00001614 /*
1615 * It's a silly kludge to initialize this with a search at runtime.
1616 * But it's better than maintaining another magic thing in the
1617 * godforsaken tables.
1618 */
1619 if (clone_scno[current_personality] == 0) {
1620 int i;
1621 for (i = 0; i < nsyscalls; ++i)
1622 if (sysent[i].sys_func == sys_clone) {
1623 clone_scno[current_personality] = i;
1624 break;
1625 }
1626 }
1627
Roland McGrath76989d72005-06-07 23:21:31 +00001628 switch (known_scno(tcp)) {
Roland McGrath9383c6c2003-01-18 00:19:31 +00001629#ifdef SYS_vfork
1630 case SYS_vfork:
1631#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001632#ifdef SYS_fork
1633 case SYS_fork:
Roland McGrath9b0982b2003-01-18 00:21:51 +00001634#endif
1635#if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001636 if (arg_setup (tcp, &state) < 0
1637 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1638 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001639 || change_syscall(tcp, clone_scno[current_personality]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001640 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1641 || set_arg1 (tcp, &state, 0) < 0
1642 || arg_finish_change (tcp, &state) < 0)
1643 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001644 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1645 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001646 tcp->flags |= TCB_BPTSET;
1647 return 0;
1648#endif
1649
1650 case SYS_clone:
1651#ifdef SYS_clone2
1652 case SYS_clone2:
1653#endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001654 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1655 contrary to x86 SYS_vfork above. Even on x86 we turn the
1656 vfork semantics into plain fork - each application must not
1657 depend on the vfork specifics according to POSIX. We would
1658 hang waiting for the parent resume otherwise. We need to
1659 clear also CLONE_VM but only in the CLONE_VFORK case as
1660 otherwise we would break pthread_create. */
1661
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001662 if ((arg_setup (tcp, &state) < 0
1663 || set_arg0 (tcp, &state,
1664 (tcp->u_arg[arg0_index] | CLONE_PTRACE)
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001665 & ~(tcp->u_arg[arg0_index] & CLONE_VFORK
1666 ? CLONE_VFORK | CLONE_VM : 0)) < 0
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001667 || arg_finish_change (tcp, &state) < 0))
1668 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001669 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001670 tcp->inst[0] = tcp->u_arg[arg0_index];
1671 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001672 return 0;
1673
1674 default:
1675 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1676 tcp->scno, tcp->pid);
1677 break;
1678 }
1679
1680 return -1;
1681}
1682
1683int
1684clearbpt(tcp)
1685struct tcb *tcp;
1686{
1687 arg_setup_state state;
1688 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001689 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1690 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001691 || arg_finish_change (tcp, &state))
1692 return -1;
1693 tcp->flags &= ~TCB_BPTSET;
1694 return 0;
1695}
1696
1697#else
1698
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001699int
1700setbpt(tcp)
1701struct tcb *tcp;
1702{
1703
1704#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001705#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001706 /* We simply use the SunOS breakpoint code. */
1707
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001708 struct regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001709 unsigned long inst;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001710#define LOOPA 0x30800000 /* ba,a 0 */
1711
1712 if (tcp->flags & TCB_BPTSET) {
1713 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1714 return -1;
1715 }
1716 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1717 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1718 return -1;
1719 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001720 tcp->baddr = regs.r_o7 + 8;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001721 errno = 0;
1722 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1723 if(errno) {
1724 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1725 return -1;
1726 }
1727
1728 /*
1729 * XXX - BRUTAL MODE ON
1730 * We cannot set a real BPT in the child, since it will not be
1731 * traced at the moment it will reach the trap and would probably
1732 * die with a core dump.
1733 * Thus, we are force our way in by taking out two instructions
1734 * and insert an eternal loop instead, in expectance of the SIGSTOP
1735 * generated by out PTRACE_ATTACH.
1736 * Of cause, if we evaporate ourselves in the middle of all this...
1737 */
1738 errno = 0;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001739 inst = LOOPA;
1740#if defined (SPARC64)
1741 inst <<= 32;
1742 inst |= (tcp->inst[0] & 0xffffffffUL);
1743#endif
1744 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, inst);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001745 if(errno) {
1746 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1747 return -1;
1748 }
1749 tcp->flags |= TCB_BPTSET;
1750
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001751#else /* !SPARC && !SPARC64 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001752#ifdef IA64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001753 if (ia32) {
1754# define LOOP 0x0000feeb
1755 if (tcp->flags & TCB_BPTSET) {
1756 fprintf(stderr, "PANIC: bpt already set in pid %u\n",
1757 tcp->pid);
1758 return -1;
1759 }
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001760 if (upeek(tcp, PT_CR_IIP, &tcp->baddr) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001761 return -1;
1762 if (debug)
1763 fprintf(stderr, "[%d] setting bpt at %lx\n",
1764 tcp->pid, tcp->baddr);
1765 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid,
1766 (char *) tcp->baddr, 0);
1767 if (errno) {
1768 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1769 return -1;
1770 }
1771 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1772 if (errno) {
1773 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1774 return -1;
1775 }
1776 tcp->flags |= TCB_BPTSET;
1777 } else {
1778 /*
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001779 * Our strategy here is to replace the bundle that
1780 * contained the clone() syscall with a bundle of the
1781 * form:
1782 *
1783 * { 1: br 1b; br 1b; br 1b }
1784 *
1785 * This ensures that the newly forked child will loop
1786 * endlessly until we've got a chance to attach to it.
1787 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001788# define LOOP0 0x0000100000000017
1789# define LOOP1 0x4000000000200000
1790 unsigned long addr, ipsr;
1791 pid_t pid;
1792
1793 pid = tcp->pid;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001794 if (upeek(tcp, PT_CR_IPSR, &ipsr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001795 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001796 if (upeek(tcp, PT_CR_IIP, &addr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001797 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001798 /* store "ri" in low two bits */
1799 tcp->baddr = addr | ((ipsr >> 41) & 0x3);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001800
1801 errno = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001802 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0,
1803 0);
1804 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8,
1805 0);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001806 if (errno) {
1807 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1808 return -1;
1809 }
1810
1811 errno = 0;
1812 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1813 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1814 if (errno) {
1815 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1816 return -1;
1817 }
1818 tcp->flags |= TCB_BPTSET;
1819 }
1820#else /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001821
Michal Ludvig0e035502002-09-23 15:41:01 +00001822#if defined (I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001823#define LOOP 0x0000feeb
1824#elif defined (M68K)
1825#define LOOP 0x60fe0000
1826#elif defined (ALPHA)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001827#define LOOP 0xc3ffffff
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001828#elif defined (POWERPC)
Roland McGrath1e85cf92002-12-16 20:40:54 +00001829#define LOOP 0x48000000
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001830#elif defined(ARM)
Wichert Akkerman9a8a37f1999-12-24 23:19:31 +00001831#define LOOP 0xEAFFFFFE
Wichert Akkermanf90da011999-10-31 21:15:38 +00001832#elif defined(MIPS)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001833#define LOOP 0x1000ffff
1834#elif defined(S390)
1835#define LOOP 0xa7f40000 /* BRC 15,0 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001836#elif defined(S390X)
1837#define LOOP 0xa7f4000000000000UL /* BRC 15,0 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001838#elif defined(HPPA)
1839#define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001840#elif defined(SH)
1841#ifdef __LITTLE_ENDIAN__
1842#define LOOP 0x0000affe
1843#else
1844#define LOOP 0xfeaf0000
1845#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001846#else
1847#error unknown architecture
1848#endif
1849
1850 if (tcp->flags & TCB_BPTSET) {
1851 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1852 return -1;
1853 }
1854#if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001855 if (upeek(tcp, 4*EIP, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001856 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00001857#elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001858 if (upeek(tcp, 8*RIP, &tcp->baddr) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001859 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001860#elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001861 if (upeek(tcp, 4*PT_PC, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001862 return -1;
1863#elif defined (ALPHA)
1864 return -1;
1865#elif defined (ARM)
1866 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001867#elif defined (MIPS)
1868 return -1; /* FIXME: I do not know what i do - Flo */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001869#elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001870 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001871 return -1;
Michal Ludvig10a88d02002-10-07 14:31:00 +00001872#elif defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001873 if (upeek(tcp,PT_PSWADDR, &tcp->baddr) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001874 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001875#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001876 if (upeek(tcp, PT_IAOQ0, &tcp->baddr) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001877 return -1;
1878 tcp->baddr &= ~0x03;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001879#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001880 if (upeek(tcp, 4*REG_PC, &tcp->baddr) < 0)
1881 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001882#else
1883#error unknown architecture
1884#endif
1885 if (debug)
1886 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1887 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1888 if (errno) {
1889 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1890 return -1;
1891 }
1892 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1893 if (errno) {
1894 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1895 return -1;
1896 }
1897 tcp->flags |= TCB_BPTSET;
1898
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001899#endif /* !IA64 */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001900#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001901#endif /* LINUX */
1902
1903#ifdef SUNOS4
1904#ifdef SPARC /* This code is slightly sparc specific */
1905
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001906 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001907#define BPT 0x91d02001 /* ta 1 */
1908#define LOOP 0x10800000 /* ba 0 */
1909#define LOOPA 0x30800000 /* ba,a 0 */
1910#define NOP 0x01000000
1911#if LOOPA
1912 static int loopdeloop[1] = {LOOPA};
1913#else
1914 static int loopdeloop[2] = {LOOP, NOP};
1915#endif
1916
1917 if (tcp->flags & TCB_BPTSET) {
1918 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1919 return -1;
1920 }
1921 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1922 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1923 return -1;
1924 }
1925 tcp->baddr = regs.r_o7 + 8;
1926 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1927 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1928 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1929 return -1;
1930 }
1931
1932 /*
1933 * XXX - BRUTAL MODE ON
1934 * We cannot set a real BPT in the child, since it will not be
1935 * traced at the moment it will reach the trap and would probably
1936 * die with a core dump.
1937 * Thus, we are force our way in by taking out two instructions
1938 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1939 * generated by out PTRACE_ATTACH.
1940 * Of cause, if we evaporate ourselves in the middle of all this...
1941 */
1942 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1943 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1944 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1945 return -1;
1946 }
1947 tcp->flags |= TCB_BPTSET;
1948
1949#endif /* SPARC */
1950#endif /* SUNOS4 */
1951
1952 return 0;
1953}
1954
1955int
1956clearbpt(tcp)
1957struct tcb *tcp;
1958{
1959
1960#ifdef LINUX
Michal Ludvig0e035502002-09-23 15:41:01 +00001961#if defined(I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001962 long eip;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001963#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001964 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001965#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001966 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001967#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001968 long pc;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001969#elif defined(HPPA)
1970 long iaoq;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001971#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001972 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001973#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001974
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001975#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001976 /* Again, we borrow the SunOS breakpoint code. */
1977 if (!(tcp->flags & TCB_BPTSET)) {
1978 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1979 return -1;
1980 }
1981 errno = 0;
1982 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1983 if(errno) {
1984 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1985 return -1;
1986 }
1987 tcp->flags &= ~TCB_BPTSET;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001988#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001989 if (ia32) {
1990 unsigned long addr;
1991
1992 if (debug)
1993 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1994 if (!(tcp->flags & TCB_BPTSET)) {
1995 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1996 return -1;
1997 }
1998 errno = 0;
1999 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
2000 if (errno) {
2001 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
2002 return -1;
2003 }
2004 tcp->flags &= ~TCB_BPTSET;
2005
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002006 if (upeek(tcp, PT_CR_IIP, &addr) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002007 return -1;
2008 if (addr != tcp->baddr) {
2009 /* The breakpoint has not been reached yet. */
2010 if (debug)
2011 fprintf(stderr,
2012 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2013 addr, tcp->baddr);
2014 return 0;
2015 }
2016 } else {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002017 unsigned long addr, ipsr;
2018 pid_t pid;
2019
2020 pid = tcp->pid;
2021
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002022 if (upeek(tcp, PT_CR_IPSR, &ipsr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002023 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002024 if (upeek(tcp, PT_CR_IIP, &addr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002025 return -1;
2026
2027 /* restore original bundle: */
2028 errno = 0;
2029 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
2030 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
2031 if (errno) {
2032 perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
2033 return -1;
2034 }
2035
2036 /* restore original "ri" in ipsr: */
2037 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
2038 errno = 0;
2039 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
2040 if (errno) {
2041 perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
2042 return -1;
2043 }
2044
2045 tcp->flags &= ~TCB_BPTSET;
2046
2047 if (addr != (tcp->baddr & ~0x3)) {
2048 /* the breakpoint has not been reached yet. */
2049 if (debug)
2050 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2051 addr, tcp->baddr);
2052 return 0;
2053 }
2054 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002055#else /* !IA64 && !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002056
2057 if (debug)
2058 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
2059 if (!(tcp->flags & TCB_BPTSET)) {
2060 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
2061 return -1;
2062 }
2063 errno = 0;
2064 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
2065 if (errno) {
2066 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
2067 return -1;
2068 }
2069 tcp->flags &= ~TCB_BPTSET;
2070
2071#ifdef I386
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002072 if (upeek(tcp, 4*EIP, &eip) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002073 return -1;
2074 if (eip != tcp->baddr) {
2075 /* The breakpoint has not been reached yet. */
2076 if (debug)
2077 fprintf(stderr,
2078 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2079 eip, tcp->baddr);
2080 return 0;
2081 }
Michal Ludvig0e035502002-09-23 15:41:01 +00002082#elif defined(X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002083 if (upeek(tcp, 8*RIP, &eip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002084 return -1;
2085 if (eip != tcp->baddr) {
2086 /* The breakpoint has not been reached yet. */
2087 if (debug)
2088 fprintf(stderr,
2089 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2090 eip, tcp->baddr);
2091 return 0;
2092 }
Wichert Akkermanc7926982000-04-10 22:22:31 +00002093#elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002094 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002095 return -1;
2096 if (pc != tcp->baddr) {
2097 /* The breakpoint has not been reached yet. */
2098 if (debug)
2099 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2100 pc, tcp->baddr);
2101 return 0;
2102 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002103#elif defined(M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002104 if (upeek(tcp, 4*PT_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002105 return -1;
2106 if (pc != tcp->baddr) {
2107 /* The breakpoint has not been reached yet. */
2108 if (debug)
2109 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2110 pc, tcp->baddr);
2111 return 0;
2112 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002113#elif defined(ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002114 if (upeek(tcp, REG_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002115 return -1;
2116 if (pc != tcp->baddr) {
2117 /* The breakpoint has not been reached yet. */
2118 if (debug)
2119 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2120 pc, tcp->baddr);
2121 return 0;
2122 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002123#elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002124 if (upeek(tcp, PT_IAOQ0, &iaoq) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002125 return -1;
2126 iaoq &= ~0x03;
2127 if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
2128 /* The breakpoint has not been reached yet. */
2129 if (debug)
2130 fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
2131 iaoq, tcp->baddr);
2132 return 0;
2133 }
2134 iaoq = tcp->baddr | 3;
2135 /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
2136 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
2137 * has no significant effect.
2138 */
2139 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
2140 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
Wichert Akkermanccef6372002-05-01 16:39:22 +00002141#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002142 if (upeek(tcp, 4*REG_PC, &pc) < 0)
2143 return -1;
2144 if (pc != tcp->baddr) {
2145 /* The breakpoint has not been reached yet. */
2146 if (debug)
2147 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2148 pc, tcp->baddr);
2149 return 0;
2150 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002151
Wichert Akkermanfaf72222000-02-19 23:59:03 +00002152#endif /* arch */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00002153#endif /* !SPARC && !SPARC64 && !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002154#endif /* LINUX */
2155
2156#ifdef SUNOS4
2157#ifdef SPARC
2158
2159#if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00002160 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002161#endif
2162
2163 if (!(tcp->flags & TCB_BPTSET)) {
2164 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
2165 return -1;
2166 }
2167 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
2168 sizeof tcp->inst, (char *) tcp->inst) < 0) {
2169 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
2170 return -1;
2171 }
2172 tcp->flags &= ~TCB_BPTSET;
2173
2174#if !LOOPA
2175 /*
2176 * Since we don't have a single instruction breakpoint, we may have
2177 * to adjust the program counter after removing the our `breakpoint'.
2178 */
2179 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
2180 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
2181 return -1;
2182 }
2183 if ((regs.r_pc < tcp->baddr) ||
2184 (regs.r_pc > tcp->baddr + 4)) {
2185 /* The breakpoint has not been reached yet */
2186 if (debug)
2187 fprintf(stderr,
2188 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
2189 regs.r_pc, tcp->parent->baddr);
2190 return 0;
2191 }
2192 if (regs.r_pc != tcp->baddr)
2193 if (debug)
2194 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
2195 regs.r_pc, tcp->baddr);
2196
2197 regs.r_pc = tcp->baddr;
2198 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
2199 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
2200 return -1;
2201 }
2202#endif /* LOOPA */
2203#endif /* SPARC */
2204#endif /* SUNOS4 */
2205
2206 return 0;
2207}
2208
Roland McGrathd81f1d92003-01-09 06:53:34 +00002209#endif
2210
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002211#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002212
2213#ifdef SUNOS4
2214
2215static int
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002216getex(tcp, hdr)
2217struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002218struct exec *hdr;
2219{
2220 int n;
2221
2222 for (n = 0; n < sizeof *hdr; n += 4) {
2223 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002224 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002225 return -1;
2226 memcpy(((char *) hdr) + n, &res, 4);
2227 }
2228 if (debug) {
2229 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
2230 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
2231 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
2232 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
2233 }
2234 return 0;
2235}
2236
2237int
2238fixvfork(tcp)
2239struct tcb *tcp;
2240{
2241 int pid = tcp->pid;
2242 /*
2243 * Change `vfork' in a freshly exec'ed dynamically linked
2244 * executable's (internal) symbol table to plain old `fork'
2245 */
2246
2247 struct exec hdr;
2248 struct link_dynamic dyn;
2249 struct link_dynamic_2 ld;
2250 char *strtab, *cp;
2251
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002252 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002253 return -1;
2254 if (!hdr.a_dynamic)
2255 return -1;
2256
2257 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
2258 fprintf(stderr, "Cannot read DYNAMIC\n");
2259 return -1;
2260 }
2261 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
2262 fprintf(stderr, "Cannot read link_dynamic_2\n");
2263 return -1;
2264 }
2265 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00002266 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002267 return -1;
2268 }
2269 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
2270 (int)ld.ld_symb_size, strtab) < 0)
2271 goto err;
2272
2273#if 0
2274 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2275 fprintf(stderr, "[symbol: %s]\n", cp);
2276 cp += strlen(cp)+1;
2277 }
2278 return 0;
2279#endif
2280 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2281 if (strcmp(cp, "_vfork") == 0) {
2282 if (debug)
2283 fprintf(stderr, "fixvfork: FOUND _vfork\n");
2284 strcpy(cp, "_fork");
2285 break;
2286 }
2287 cp += strlen(cp)+1;
2288 }
2289 if (cp < strtab + ld.ld_symb_size)
2290 /*
2291 * Write entire symbol table back to avoid
2292 * memory alignment bugs in ptrace
2293 */
2294 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
2295 (int)ld.ld_symb_size, strtab) < 0)
2296 goto err;
2297
2298 free(strtab);
2299 return 0;
2300
2301err:
2302 free(strtab);
2303 return -1;
2304}
2305
2306#endif /* SUNOS4 */