blob: 64210ef9b0320f71b97b68d2c339940d68775ca2 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
Roland McGrathd81f1d92003-01-09 06:53:34 +000038#include <signal.h>
39#include <sys/syscall.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000040#include <sys/user.h>
41#include <sys/param.h>
42#include <fcntl.h>
John Hughes1d08dcf2001-07-10 13:48:44 +000043#if HAVE_SYS_UIO_H
44#include <sys/uio.h>
45#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000046#ifdef SUNOS4
47#include <machine/reg.h>
48#include <a.out.h>
49#include <link.h>
50#endif /* SUNOS4 */
Wichert Akkerman36915a11999-07-13 15:45:02 +000051
Wichert Akkerman43a74822000-06-27 17:33:32 +000052#if defined(linux) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1))
Wichert Akkerman36915a11999-07-13 15:45:02 +000053#include <linux/ptrace.h>
Roland McGrath1e85cf92002-12-16 20:40:54 +000054#endif
Wichert Akkerman36915a11999-07-13 15:45:02 +000055
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000056#if defined(LINUX) && defined(IA64)
Roland McGrathd81f1d92003-01-09 06:53:34 +000057# include <asm/ptrace_offsets.h>
58# include <asm/rse.h>
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000059#endif
60
Wichert Akkerman36915a11999-07-13 15:45:02 +000061#ifdef HAVE_SYS_REG_H
62#include <sys/reg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000063# define PTRACE_PEEKUSR PTRACE_PEEKUSER
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
65#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman2e2553a1999-05-09 00:29:58 +000075#endif
76
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000077#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
78#include <sys/utsname.h>
79#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
80
Roland McGrath6d1a65c2004-07-12 07:44:08 +000081#if defined(LINUXSPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000082
Roland McGrath4db26242003-01-30 20:15:19 +000083# define fpq kernel_fpq
84# define fq kernel_fq
85# define fpu kernel_fpu
86# include <asm/reg.h>
87# undef fpq
88# undef fq
89# undef fpu
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000090
Roland McGrath6d1a65c2004-07-12 07:44:08 +000091#if defined (SPARC64)
92# define r_pc r_tpc
93# undef PTRACE_GETREGS
94# define PTRACE_GETREGS PTRACE_GETREGS64
95# undef PTRACE_SETREGS
96# define PTRACE_SETREGS PTRACE_SETREGS64
97#endif /* SPARC64 */
98
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000099#if !defined(__GLIBC__)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000100
101#include <linux/unistd.h>
102
103#define _hack_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,\
104 type5,arg5,syscall) \
105type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
106{ \
107 long __res; \
108\
109__asm__ volatile ("or %%g0, %1, %%o0\n\t" \
110 "or %%g0, %2, %%o1\n\t" \
111 "or %%g0, %3, %%o2\n\t" \
112 "or %%g0, %4, %%o3\n\t" \
113 "or %%g0, %5, %%o4\n\t" \
114 "or %%g0, %6, %%g1\n\t" \
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000115#if defined (SPARC64)
116 "t 0x6d\n\t" \
117#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000118 "t 0x10\n\t" \
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000119#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120 "bcc 1f\n\t" \
121 "or %%g0, %%o0, %0\n\t" \
122 "sub %%g0, %%o0, %0\n\t" \
123 "1:\n\t" \
124 : "=r" (__res) \
125 : "0" ((long)(arg1)),"1" ((long)(arg2)), \
126 "2" ((long)(arg3)),"3" ((long)(arg4)),"4" ((long)(arg5)), \
127 "i" (__NR_##syscall) \
128 : "g1", "o0", "o1", "o2", "o3", "o4"); \
129if (__res>=0) \
130 return (type) __res; \
131errno = -__res; \
132return -1; \
133}
134
135static _hack_syscall5(int,_ptrace,int,__request,int,__pid,int,__addr,int,__data,int,__addr2,ptrace)
136
137#define _ptrace
138
139#endif
140
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000141#endif
142
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000143/* macros */
144#ifndef MAX
145#define MAX(a,b) (((a) > (b)) ? (a) : (b))
146#endif
147#ifndef MIN
148#define MIN(a,b) (((a) < (b)) ? (a) : (b))
149#endif
150
Roland McGratha4d48532005-06-08 20:45:28 +0000151#if 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152void
153tv_tv(tv, a, b)
154struct timeval *tv;
155int a;
156int b;
157{
158 tv->tv_sec = a;
159 tv->tv_usec = b;
160}
Roland McGratha4d48532005-06-08 20:45:28 +0000161#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000162
163int
164tv_nz(a)
165struct timeval *a;
166{
167 return a->tv_sec || a->tv_usec;
168}
169
170int
171tv_cmp(a, b)
172struct timeval *a, *b;
173{
174 if (a->tv_sec < b->tv_sec
175 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
176 return -1;
177 if (a->tv_sec > b->tv_sec
178 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
179 return 1;
180 return 0;
181}
182
183double
184tv_float(tv)
185struct timeval *tv;
186{
187 return tv->tv_sec + tv->tv_usec/1000000.0;
188}
189
190void
191tv_add(tv, a, b)
192struct timeval *tv, *a, *b;
193{
194 tv->tv_sec = a->tv_sec + b->tv_sec;
195 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000196 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000197 tv->tv_sec++;
198 tv->tv_usec -= 1000000;
199 }
200}
201
202void
203tv_sub(tv, a, b)
204struct timeval *tv, *a, *b;
205{
206 tv->tv_sec = a->tv_sec - b->tv_sec;
207 tv->tv_usec = a->tv_usec - b->tv_usec;
208 if (((long) tv->tv_usec) < 0) {
209 tv->tv_sec--;
210 tv->tv_usec += 1000000;
211 }
212}
213
214void
215tv_div(tv, a, n)
216struct timeval *tv, *a;
217int n;
218{
219 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
220 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
221 tv->tv_usec %= 1000000;
222}
223
224void
225tv_mul(tv, a, n)
226struct timeval *tv, *a;
227int n;
228{
229 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000230 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000231 tv->tv_usec %= 1000000;
232}
233
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000234const char *
235xlookup(const struct xlat *xlat, int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000236{
237 for (; xlat->str != NULL; xlat++)
238 if (xlat->val == val)
239 return xlat->str;
240 return NULL;
241}
242
243/*
244 * Print entry in struct xlat table, if there.
245 */
246void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000247printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000248{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000249 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000250
251 if (str)
252 tprintf("%s", str);
253 else
254 tprintf("%#x /* %s */", val, dflt);
255}
256
257/*
258 * Interpret `xlat' as an array of flags
259 * print the entries whose bits are on in `flags'
260 * return # of flags printed.
261 */
262int
263addflags(xlat, flags)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000264const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000265int flags;
266{
267 int n;
268
269 for (n = 0; xlat->str; xlat++) {
270 if (xlat->val && (flags & xlat->val) == xlat->val) {
271 tprintf("|%s", xlat->str);
272 flags &= ~xlat->val;
273 n++;
274 }
275 }
276 if (flags) {
277 tprintf("|%#x", flags);
278 n++;
279 }
280 return n;
281}
282
283int
Roland McGrathb2dee132005-06-01 19:02:36 +0000284printflags(xlat, flags, dflt)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000285const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000286int flags;
Roland McGrathb2dee132005-06-01 19:02:36 +0000287const char *dflt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000288{
289 int n;
290 char *sep;
291
292 if (flags == 0 && xlat->val == 0) {
293 tprintf("%s", xlat->str);
294 return 1;
295 }
296
297 sep = "";
298 for (n = 0; xlat->str; xlat++) {
299 if (xlat->val && (flags & xlat->val) == xlat->val) {
300 tprintf("%s%s", sep, xlat->str);
301 flags &= ~xlat->val;
302 sep = "|";
303 n++;
304 }
305 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000306
307 if (n) {
308 if (flags) {
309 tprintf("%s%#x", sep, flags);
310 n++;
311 }
312 } else {
313 if (flags) {
314 tprintf("%#x", flags);
315 if (dflt)
316 tprintf(" /* %s */", dflt);
317 } else {
318 if (dflt)
319 tprintf("0");
320 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000321 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000322
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000323 return n;
324}
325
326void
327printnum(tcp, addr, fmt)
328struct tcb *tcp;
329long addr;
330char *fmt;
331{
Roland McGratheb285352003-01-14 09:59:00 +0000332 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000333
334 if (!addr) {
335 tprintf("NULL");
336 return;
337 }
338 if (umove(tcp, addr, &num) < 0) {
339 tprintf("%#lx", addr);
340 return;
341 }
342 tprintf("[");
343 tprintf(fmt, num);
344 tprintf("]");
345}
346
Roland McGrath6bc12202003-11-13 22:32:27 +0000347void
Roland McGrath9814a942005-07-04 23:28:10 +0000348printnum_int(tcp, addr, fmt)
349struct tcb *tcp;
350long addr;
351char *fmt;
352{
353 int num;
354
355 if (!addr) {
356 tprintf("NULL");
357 return;
358 }
359 if (umove(tcp, addr, &num) < 0) {
360 tprintf("%#lx", addr);
361 return;
362 }
363 tprintf("[");
364 tprintf(fmt, num);
365 tprintf("]");
366}
367
368void
Roland McGrath6bc12202003-11-13 22:32:27 +0000369printuid(text, uid)
370const char *text;
371unsigned long uid;
372{
373 tprintf("%s", text);
374 tprintf((uid == -1) ? "%ld" : "%lu", uid);
375}
376
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000377static char path[MAXPATHLEN + 1];
378
Roland McGratha4d48532005-06-08 20:45:28 +0000379static void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380string_quote(str)
Roland McGratha4d48532005-06-08 20:45:28 +0000381const char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000382{
383 char buf[2 * MAXPATHLEN + 1];
384 char *s;
385
386 if (!strpbrk(str, "\"\'\\")) {
387 tprintf("\"%s\"", str);
388 return;
389 }
390 for (s = buf; *str; str++) {
391 switch (*str) {
392 case '\"': case '\'': case '\\':
393 *s++ = '\\'; *s++ = *str; break;
394 default:
395 *s++ = *str; break;
396 }
397 }
398 *s = '\0';
399 tprintf("\"%s\"", buf);
400}
401
402void
403printpath(tcp, addr)
404struct tcb *tcp;
405long addr;
406{
Roland McGrath371ed8f2005-02-06 01:55:07 +0000407 if (addr == 0)
408 tprintf("NULL");
409 else if (umovestr(tcp, addr, MAXPATHLEN, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000410 tprintf("%#lx", addr);
411 else
412 string_quote(path);
413 return;
414}
415
416void
417printpathn(tcp, addr, n)
418struct tcb *tcp;
419long addr;
420int n;
421{
Roland McGrathb15c4e42005-10-21 22:06:46 +0000422 if (n >= sizeof path)
423 n = sizeof path - 1;
424
Roland McGrath371ed8f2005-02-06 01:55:07 +0000425 if (addr == 0)
426 tprintf("NULL");
427 else if (umovestr(tcp, addr, n, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000428 tprintf("%#lx", addr);
429 else {
430 path[n] = '\0';
431 string_quote(path);
432 }
433}
434
435void
436printstr(tcp, addr, len)
437struct tcb *tcp;
438long addr;
439int len;
440{
441 static unsigned char *str = NULL;
442 static char *outstr;
443 int i, n, c, usehex;
444 char *s, *outend;
445
446 if (!addr) {
447 tprintf("NULL");
448 return;
449 }
450 if (!str) {
451 if ((str = malloc(max_strlen)) == NULL
Roland McGrath779c4662007-07-11 07:23:40 +0000452 || (outstr = malloc(4*max_strlen
453 + sizeof "\"\"...")) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000454 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000455 tprintf("%#lx", addr);
456 return;
457 }
458 }
Roland McGrath779c4662007-07-11 07:23:40 +0000459 outend = outstr + max_strlen * 4;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000460 if (len < 0) {
461 n = max_strlen;
462 if (umovestr(tcp, addr, n, (char *) str) < 0) {
463 tprintf("%#lx", addr);
464 return;
465 }
466 }
467 else {
468 n = MIN(len, max_strlen);
469 if (umoven(tcp, addr, n, (char *) str) < 0) {
470 tprintf("%#lx", addr);
471 return;
472 }
473 }
474
475 usehex = 0;
476 if (xflag > 1)
477 usehex = 1;
478 else if (xflag) {
479 for (i = 0; i < n; i++) {
480 c = str[i];
481 if (len < 0 && c == '\0')
482 break;
483 if (!isprint(c) && !isspace(c)) {
484 usehex = 1;
485 break;
486 }
487 }
488 }
489
490 s = outstr;
491 *s++ = '\"';
492
493 if (usehex) {
494 for (i = 0; i < n; i++) {
495 c = str[i];
496 if (len < 0 && c == '\0')
497 break;
498 sprintf(s, "\\x%02x", c);
499 s += 4;
500 if (s > outend)
501 break;
502 }
503 }
504 else {
505 for (i = 0; i < n; i++) {
506 c = str[i];
507 if (len < 0 && c == '\0')
508 break;
509 switch (c) {
510 case '\"': case '\'': case '\\':
511 *s++ = '\\'; *s++ = c; break;
512 case '\f':
513 *s++ = '\\'; *s++ = 'f'; break;
514 case '\n':
515 *s++ = '\\'; *s++ = 'n'; break;
516 case '\r':
517 *s++ = '\\'; *s++ = 'r'; break;
518 case '\t':
519 *s++ = '\\'; *s++ = 't'; break;
520 case '\v':
521 *s++ = '\\'; *s++ = 'v'; break;
522 default:
523 if (isprint(c))
524 *s++ = c;
525 else if (i < n - 1 && isdigit(str[i + 1])) {
526 sprintf(s, "\\%03o", c);
527 s += 4;
528 }
529 else {
530 sprintf(s, "\\%o", c);
531 s += strlen(s);
532 }
533 break;
534 }
535 if (s > outend)
536 break;
537 }
538 }
539
540 *s++ = '\"';
541 if (i < len || (len < 0 && (i == n || s > outend))) {
542 *s++ = '.'; *s++ = '.'; *s++ = '.';
543 }
544 *s = '\0';
545 tprintf("%s", outstr);
546}
547
John Hughes1d08dcf2001-07-10 13:48:44 +0000548#if HAVE_SYS_UIO_H
549void
550dumpiov(tcp, len, addr)
551struct tcb * tcp;
552int len;
553long addr;
554{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000555#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
556 union {
557 struct { u_int32_t base; u_int32_t len; } *iov32;
558 struct { u_int64_t base; u_int64_t len; } *iov64;
559 } iovu;
560#define iov iovu.iov64
561#define sizeof_iov \
562 (personality_wordsize[current_personality] == 4 \
563 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
564#define iov_iov_base(i) \
565 (personality_wordsize[current_personality] == 4 \
566 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
567#define iov_iov_len(i) \
568 (personality_wordsize[current_personality] == 4 \
569 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
570#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000571 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000572#define sizeof_iov sizeof(*iov)
573#define iov_iov_base(i) iov[i].iov_base
574#define iov_iov_len(i) iov[i].iov_len
575#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000576 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000577 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000578
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000579 size = sizeof_iov * (unsigned long) len;
580 if (size / sizeof_iov != len
581 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000582 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000583 return;
584 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000585 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000586 for (i = 0; i < len; i++) {
587 /* include the buffer number to make it easy to
588 * match up the trace with the source */
589 tprintf(" * %lu bytes in buffer %d\n",
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000590 (unsigned long)iov_iov_len(i), i);
591 dumpstr(tcp, (long) iov_iov_base(i),
592 iov_iov_len(i));
John Hughes1d08dcf2001-07-10 13:48:44 +0000593 }
594 }
595 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000596#undef sizeof_iov
597#undef iov_iov_base
598#undef iov_iov_len
599#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000600}
601#endif
602
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000603void
604dumpstr(tcp, addr, len)
605struct tcb *tcp;
606long addr;
607int len;
608{
609 static int strsize = -1;
610 static unsigned char *str;
611 static char outstr[80];
612 char *s;
613 int i, j;
614
615 if (strsize < len) {
616 if (str)
617 free(str);
618 if ((str = malloc(len)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000619 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000620 return;
621 }
622 strsize = len;
623 }
624
625 if (umoven(tcp, addr, len, (char *) str) < 0)
626 return;
627
628 for (i = 0; i < len; i += 16) {
629 s = outstr;
630 sprintf(s, " | %05x ", i);
631 s += 9;
632 for (j = 0; j < 16; j++) {
633 if (j == 8)
634 *s++ = ' ';
635 if (i + j < len) {
636 sprintf(s, " %02x", str[i + j]);
637 s += 3;
638 }
639 else {
640 *s++ = ' '; *s++ = ' '; *s++ = ' ';
641 }
642 }
643 *s++ = ' '; *s++ = ' ';
644 for (j = 0; j < 16; j++) {
645 if (j == 8)
646 *s++ = ' ';
647 if (i + j < len) {
648 if (isprint(str[i + j]))
649 *s++ = str[i + j];
650 else
651 *s++ = '.';
652 }
653 else
654 *s++ = ' ';
655 }
656 tprintf("%s |\n", outstr);
657 }
658}
659
660#define PAGMASK (~(PAGSIZ - 1))
661/*
662 * move `len' bytes of data from process `pid'
663 * at address `addr' to our space at `laddr'
664 */
665int
666umoven(tcp, addr, len, laddr)
667struct tcb *tcp;
668long addr;
669int len;
670char *laddr;
671{
672
673#ifdef LINUX
674 int pid = tcp->pid;
675 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000676 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000677 union {
678 long val;
679 char x[sizeof(long)];
680 } u;
681
682 if (addr & (sizeof(long) - 1)) {
683 /* addr not a multiple of sizeof(long) */
684 n = addr - (addr & -sizeof(long)); /* residue */
685 addr &= -sizeof(long); /* residue */
686 errno = 0;
687 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
688 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000689 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000690 /* Ran into 'end of memory' - stupid "printpath" */
691 return 0;
692 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000693 /* But if not started, we had a bogus address. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000694 perror("ptrace: umoven");
695 return -1;
696 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000697 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000698 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
699 addr += sizeof(long), laddr += m, len -= m;
700 }
701 while (len) {
702 errno = 0;
703 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
704 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000705 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000706 /* Ran into 'end of memory' - stupid "printpath" */
707 return 0;
708 }
Roland McGrath4db26242003-01-30 20:15:19 +0000709 if (addr != 0)
710 perror("ptrace: umoven");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000711 return -1;
712 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000713 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000714 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
715 addr += sizeof(long), laddr += m, len -= m;
716 }
717#endif /* LINUX */
718
719#ifdef SUNOS4
720 int pid = tcp->pid;
721#if 0
722 int n, m;
723 union {
724 long val;
725 char x[sizeof(long)];
726 } u;
727
728 if (addr & (sizeof(long) - 1)) {
729 /* addr not a multiple of sizeof(long) */
730 n = addr - (addr & -sizeof(long)); /* residue */
731 addr &= -sizeof(long); /* residue */
732 errno = 0;
733 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
734 if (errno) {
735 perror("umoven");
736 return -1;
737 }
738 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
739 addr += sizeof(long), laddr += m, len -= m;
740 }
741 while (len) {
742 errno = 0;
743 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
744 if (errno) {
745 perror("umoven");
746 return -1;
747 }
748 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
749 addr += sizeof(long), laddr += m, len -= m;
750 }
751#else /* !oldway */
752 int n;
753
754 while (len) {
755 n = MIN(len, PAGSIZ);
756 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
757 if (ptrace(PTRACE_READDATA, pid,
758 (char *) addr, len, laddr) < 0) {
759 perror("umoven: ptrace(PTRACE_READDATA, ...)");
760 abort();
761 return -1;
762 }
763 len -= n;
764 addr += n;
765 laddr += n;
766 }
767#endif /* !oldway */
768#endif /* SUNOS4 */
769
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000770#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000771#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000772 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000773#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000774 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000776 lseek(fd, addr, SEEK_SET);
777 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000779#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000780
781 return 0;
782}
783
784/*
785 * like `umove' but make the additional effort of looking
786 * for a terminating zero byte.
787 */
788int
789umovestr(tcp, addr, len, laddr)
790struct tcb *tcp;
791long addr;
792int len;
793char *laddr;
794{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000795#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000796#ifdef HAVE_MP_PROCFS
797 int fd = tcp->pfd_as;
798#else
799 int fd = tcp->pfd;
800#endif
801 /* Some systems (e.g. FreeBSD) can be upset if we read off the
802 end of valid memory, avoid this by trying to read up
803 to page boundaries. But we don't know what a page is (and
804 getpagesize(2) (if it exists) doesn't necessarily return
805 hardware page size). Assume all pages >= 1024 (a-historical
806 I know) */
807
808 int page = 1024; /* How to find this? */
809 int move = page - (addr & (page - 1));
810 int left = len;
811
812 lseek(fd, addr, SEEK_SET);
813
814 while (left) {
815 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000816 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000817 return left != len ? 0 : -1;
818 if (memchr (laddr, 0, move)) break;
819 left -= move;
820 laddr += move;
821 addr += move;
822 move = page;
823 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000824#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000825 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000826 int pid = tcp->pid;
827 int i, n, m;
828 union {
829 long val;
830 char x[sizeof(long)];
831 } u;
832
833 if (addr & (sizeof(long) - 1)) {
834 /* addr not a multiple of sizeof(long) */
835 n = addr - (addr & -sizeof(long)); /* residue */
836 addr &= -sizeof(long); /* residue */
837 errno = 0;
838 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
839 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000840 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000841 /* Ran into 'end of memory' - stupid "printpath" */
842 return 0;
843 }
844 perror("umovestr");
845 return -1;
846 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000847 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000848 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
849 while (n & (sizeof(long) - 1))
850 if (u.x[n++] == '\0')
851 return 0;
852 addr += sizeof(long), laddr += m, len -= m;
853 }
854 while (len) {
855 errno = 0;
856 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
857 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000858 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000859 /* Ran into 'end of memory' - stupid "printpath" */
860 return 0;
861 }
862 perror("umovestr");
863 return -1;
864 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000865 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000866 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
867 for (i = 0; i < sizeof(long); i++)
868 if (u.x[i] == '\0')
869 return 0;
870
871 addr += sizeof(long), laddr += m, len -= m;
872 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000873#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000874 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000875}
876
877#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000878#if !defined (SPARC) && !defined(SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000879#define PTRACE_WRITETEXT 101
880#define PTRACE_WRITEDATA 102
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000881#endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000882#endif /* LINUX */
883
884#ifdef SUNOS4
885
886static int
887uload(cmd, pid, addr, len, laddr)
888int cmd;
889int pid;
890long addr;
891int len;
892char *laddr;
893{
894#if 0
895 int n;
896
897 while (len) {
898 n = MIN(len, PAGSIZ);
899 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
900 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
901 perror("uload: ptrace(PTRACE_WRITE, ...)");
902 return -1;
903 }
904 len -= n;
905 addr += n;
906 laddr += n;
907 }
908#else
909 int peek, poke;
910 int n, m;
911 union {
912 long val;
913 char x[sizeof(long)];
914 } u;
915
916 if (cmd == PTRACE_WRITETEXT) {
917 peek = PTRACE_PEEKTEXT;
918 poke = PTRACE_POKETEXT;
919 }
920 else {
921 peek = PTRACE_PEEKDATA;
922 poke = PTRACE_POKEDATA;
923 }
924 if (addr & (sizeof(long) - 1)) {
925 /* addr not a multiple of sizeof(long) */
926 n = addr - (addr & -sizeof(long)); /* residue */
927 addr &= -sizeof(long);
928 errno = 0;
929 u.val = ptrace(peek, pid, (char *) addr, 0);
930 if (errno) {
931 perror("uload: POKE");
932 return -1;
933 }
934 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
935 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
936 perror("uload: POKE");
937 return -1;
938 }
939 addr += sizeof(long), laddr += m, len -= m;
940 }
941 while (len) {
942 if (len < sizeof(long))
943 u.val = ptrace(peek, pid, (char *) addr, 0);
944 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
945 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
946 perror("uload: POKE");
947 return -1;
948 }
949 addr += sizeof(long), laddr += m, len -= m;
950 }
951#endif
952 return 0;
953}
954
955int
956tload(pid, addr, len, laddr)
957int pid;
958int addr, len;
959char *laddr;
960{
961 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
962}
963
964int
965dload(pid, addr, len, laddr)
966int pid;
967int addr;
968int len;
969char *laddr;
970{
971 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
972}
973
974#endif /* SUNOS4 */
975
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000976#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000977
978int
979upeek(pid, off, res)
980int pid;
981long off;
982long *res;
983{
984 long val;
985
986#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
987 {
988 static int is_sun4m = -1;
989 struct utsname name;
990
991 /* Round up the usual suspects. */
992 if (is_sun4m == -1) {
993 if (uname(&name) < 0) {
994 perror("upeek: uname?");
995 exit(1);
996 }
997 is_sun4m = strcmp(name.machine, "sun4m") == 0;
998 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +0000999 extern const struct xlat struct_user_offsets[];
1000 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001001
1002 for (x = struct_user_offsets; x->str; x++)
1003 x->val += 1024;
1004 }
1005 }
1006 if (is_sun4m)
1007 off += 1024;
1008 }
1009#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
1010 errno = 0;
1011 val = ptrace(PTRACE_PEEKUSER, pid, (char *) off, 0);
1012 if (val == -1 && errno) {
Roland McGrath1e85cf92002-12-16 20:40:54 +00001013 char buf[60];
Michal Ludvig0e035502002-09-23 15:41:01 +00001014 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)",pid,off);
Roland McGrath1e85cf92002-12-16 20:40:54 +00001015 perror(buf);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001016 return -1;
1017 }
1018 *res = val;
1019 return 0;
1020}
1021
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001022#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001023
Roland McGratha4d48532005-06-08 20:45:28 +00001024#if 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025long
1026getpc(tcp)
1027struct tcb *tcp;
1028{
1029
1030#ifdef LINUX
1031 long pc;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001032#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033 if (upeek(tcp->pid, 4*EIP, &pc) < 0)
1034 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00001035#elif defined(X86_64)
1036 if (upeek(tcp->pid, 8*RIP, &pc) < 0)
1037 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001038#elif defined(IA64)
1039 if (upeek(tcp->pid, PT_B0, &pc) < 0)
1040 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001041#elif defined(ARM)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001042 if (upeek(tcp->pid, 4*15, &pc) < 0)
1043 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001044#elif defined(POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001045 if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001046 return -1;
Roland McGrath84fa9232005-06-08 18:06:22 +00001047#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1049 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001050#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001051 if (upeek(tcp->pid, REG_PC, &pc) < 0)
1052 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001053#elif defined(MIPS)
1054 if (upeek(tcp->pid, REG_EPC, &pc) < 0)
1055 return -1;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001056#elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001057 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001058 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
1059 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001060 pc = regs.r_pc;
Michal Ludvig10a88d02002-10-07 14:31:00 +00001061#elif defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001062 if(upeek(tcp->pid,PT_PSWADDR,&pc) < 0)
Michal Ludvig10a88d02002-10-07 14:31:00 +00001063 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001064#elif defined(HPPA)
1065 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0)
1066 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001067#elif defined(SH)
1068 if (upeek(tcp->pid, 4*REG_PC ,&pc) < 0)
1069 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +00001070#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001071 if (upeek(tcp->pid, REG_PC ,&pc) < 0)
1072 return -1;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +00001073#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074 return pc;
1075#endif /* LINUX */
1076
1077#ifdef SUNOS4
1078 /*
1079 * Return current program counter for `pid'
1080 * Assumes PC is never 0xffffffff
1081 */
1082 struct regs regs;
1083
1084 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1085 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
1086 return -1;
1087 }
1088 return regs.r_pc;
1089#endif /* SUNOS4 */
1090
1091#ifdef SVR4
1092 /* XXX */
1093 return 0;
1094#endif /* SVR4 */
1095
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001096#ifdef FREEBSD
1097 struct reg regs;
1098 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1099 return regs.r_eip;
1100#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101}
Roland McGratha4d48532005-06-08 20:45:28 +00001102#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001103
1104void
1105printcall(tcp)
1106struct tcb *tcp;
1107{
Roland McGrath7a918832005-02-02 20:55:23 +00001108#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1109 sizeof(long) == 8 ? "[????????????????] " : \
1110 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001111
1112#ifdef LINUX
1113#ifdef I386
1114 long eip;
1115
1116 if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001117 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001118 return;
1119 }
1120 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001121
1122#elif defined(S390) || defined(S390X)
1123 long psw;
1124 if(upeek(tcp->pid,PT_PSWADDR,&psw) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001125 PRINTBADPC;
Roland McGratheac26fc2005-02-02 02:48:53 +00001126 return;
1127 }
1128#ifdef S390
1129 tprintf("[%08lx] ", psw);
1130#elif S390X
1131 tprintf("[%16lx] ", psw);
1132#endif
1133
Michal Ludvig0e035502002-09-23 15:41:01 +00001134#elif defined(X86_64)
1135 long rip;
1136
1137 if (upeek(tcp->pid, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001138 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001139 return;
1140 }
1141 tprintf("[%16lx] ", rip);
Roland McGrathef388682003-06-03 23:28:59 +00001142#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001143 long ip;
1144
1145 if (upeek(tcp->pid, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001146 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001147 return;
1148 }
1149 tprintf("[%08lx] ", ip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001150#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001151 long pc;
1152
Roland McGratheb285352003-01-14 09:59:00 +00001153 if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001154 tprintf ("[????????] ");
1155 return;
1156 }
1157 tprintf("[%08lx] ", pc);
Roland McGrath84fa9232005-06-08 18:06:22 +00001158#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159 long pc;
1160
1161 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
1162 tprintf ("[????????] ");
1163 return;
1164 }
1165 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001166#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001167 long pc;
1168
1169 if (upeek(tcp->pid, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001170 tprintf ("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001171 return;
1172 }
1173 tprintf("[%08lx] ", pc);
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001174#elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001175 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001177 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001178 return;
1179 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001180 tprintf("[%08lx] ", regs.r_pc);
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001181#elif defined(HPPA)
1182 long pc;
1183
1184 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0) {
1185 tprintf ("[????????] ");
1186 return;
1187 }
1188 tprintf("[%08lx] ", pc);
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001189#elif defined(MIPS)
1190 long pc;
1191
1192 if (upeek(tcp->pid, REG_EPC, &pc) < 0) {
1193 tprintf ("[????????] ");
1194 return;
1195 }
1196 tprintf("[%08lx] ", pc);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001197#elif defined(SH)
1198 long pc;
1199
1200 if (upeek(tcp->pid, 4*REG_PC, &pc) < 0) {
1201 tprintf ("[????????] ");
1202 return;
1203 }
1204 tprintf("[%08lx] ", pc);
Roland McGrathf5a47772003-06-26 22:40:42 +00001205#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001206 long pc;
1207
1208 if (upeek(tcp->pid, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001209 tprintf ("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001210 return;
1211 }
1212 tprintf("[%08lx] ", pc);
Roland McGrathef388682003-06-03 23:28:59 +00001213#elif defined(ARM)
1214 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001215
Roland McGrathef388682003-06-03 23:28:59 +00001216 if (upeek(tcp->pid, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001217 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001218 return;
1219 }
1220 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001221#endif /* !architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001222#endif /* LINUX */
1223
1224#ifdef SUNOS4
1225 struct regs regs;
1226
1227 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1228 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001229 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001230 return;
1231 }
1232 tprintf("[%08x] ", regs.r_o7);
1233#endif /* SUNOS4 */
1234
1235#ifdef SVR4
1236 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001237 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001238#endif
1239
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001240#ifdef FREEBSD
1241 struct reg regs;
1242 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1243 tprintf("[%08x] ", regs.r_eip);
1244#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245}
1246
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001247#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001248
Roland McGrathd81f1d92003-01-09 06:53:34 +00001249#if defined LINUX
1250
1251#include <sys/syscall.h>
1252#ifndef CLONE_PTRACE
1253# define CLONE_PTRACE 0x00002000
1254#endif
Roland McGrath76989d72005-06-07 23:21:31 +00001255#ifndef CLONE_STOPPED
1256# define CLONE_STOPPED 0x02000000
1257#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001258
1259#ifdef IA64
1260
Roland McGrath08267b82004-02-20 22:56:43 +00001261/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1262 subsystem has them for x86... */
1263#define SYS_fork 2
1264#define SYS_vfork 190
1265
Roland McGrathd81f1d92003-01-09 06:53:34 +00001266typedef unsigned long *arg_setup_state;
1267
1268static int
1269arg_setup(struct tcb *tcp, arg_setup_state *state)
1270{
1271 unsigned long *bsp, cfm, sof, sol;
1272
Roland McGrath08267b82004-02-20 22:56:43 +00001273 if (ia32)
1274 return 0;
1275
Roland McGrathd81f1d92003-01-09 06:53:34 +00001276 if (upeek(tcp->pid, PT_AR_BSP, (long *) &bsp) < 0)
1277 return -1;
1278 if (upeek(tcp->pid, PT_CFM, (long *) &cfm) < 0)
1279 return -1;
1280
1281 sof = (cfm >> 0) & 0x7f;
1282 sol = (cfm >> 7) & 0x7f;
1283 bsp = ia64_rse_skip_regs(bsp, -sof + sol);
1284
1285 *state = bsp;
1286 return 0;
1287}
1288
1289# define arg_finish_change(tcp, state) 0
1290
1291#ifdef SYS_fork
1292static int
1293get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1294{
Roland McGrath08267b82004-02-20 22:56:43 +00001295 int ret;
1296
1297 if (ia32)
1298 ret = upeek (tcp->pid, PT_R11, valp);
1299 else
1300 ret = umoven (tcp,
1301 (unsigned long) ia64_rse_skip_regs(*state, 0),
1302 sizeof(long), (void *) valp);
1303 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001304}
1305
1306static int
1307get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1308{
Roland McGrath08267b82004-02-20 22:56:43 +00001309 int ret;
1310
1311 if (ia32)
1312 ret = upeek (tcp->pid, PT_R9, valp);
1313 else
1314 ret = umoven (tcp,
1315 (unsigned long) ia64_rse_skip_regs(*state, 1),
1316 sizeof(long), (void *) valp);
1317 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001318}
1319#endif
1320
1321static int
1322set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1323{
Roland McGrath08267b82004-02-20 22:56:43 +00001324 int req = PTRACE_POKEDATA;
1325 void *ap;
1326
1327 if (ia32) {
1328 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1329 req = PTRACE_POKEUSER;
1330 } else
1331 ap = ia64_rse_skip_regs(*state, 0);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001332 errno = 0;
Roland McGrath08267b82004-02-20 22:56:43 +00001333 ptrace(req, tcp->pid, ap, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001334 return errno ? -1 : 0;
1335}
1336
1337static int
1338set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1339{
Roland McGrath08267b82004-02-20 22:56:43 +00001340 int req = PTRACE_POKEDATA;
1341 void *ap;
1342
1343 if (ia32) {
1344 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1345 req = PTRACE_POKEUSER;
1346 } else
1347 ap = ia64_rse_skip_regs(*state, 1);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001348 errno = 0;
Roland McGrath08267b82004-02-20 22:56:43 +00001349 ptrace(req, tcp->pid, ap, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001350 return errno ? -1 : 0;
1351}
1352
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001353#elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001354
1355typedef struct regs arg_setup_state;
1356
1357# define arg_setup(tcp, state) \
1358 (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
1359# define arg_finish_change(tcp, state) \
1360 (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
1361
1362# define get_arg0(tcp, state, valp) (*(valp) = (state)->r_o0, 0)
1363# define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0)
1364# define set_arg0(tcp, state, val) ((state)->r_o0 = (val), 0)
1365# define set_arg1(tcp, state, val) ((state)->r_o1 = (val), 0)
Roland McGrathe1df47f2003-01-14 09:46:15 +00001366# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001367
1368#else
1369
1370# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001371/* Note: this is only true for the `clone' system call, which handles
1372 arguments specially. We could as well say that its first two arguments
1373 are swapped relative to other architectures, but that would just be
1374 another #ifdef in the calls. */
1375# define arg0_offset PT_GPR3
1376# define arg1_offset PT_ORIGGPR2
1377# define restore_arg0(tcp, state, val) ((void) (state), 0)
1378# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001379# define arg0_index 1
1380# define arg1_index 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001381# elif defined (ALPHA) || defined (MIPS)
1382# define arg0_offset REG_A0
1383# define arg1_offset (REG_A0+1)
1384# elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001385# define arg0_offset (sizeof(unsigned long)*PT_R3)
1386# define arg1_offset (sizeof(unsigned long)*PT_R4)
Roland McGrath7b308222003-01-20 09:04:36 +00001387# define restore_arg0(tcp, state, val) ((void) (state), 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001388# elif defined (HPPA)
1389# define arg0_offset PT_GR26
1390# define arg1_offset (PT_GR26-4)
Roland McGrath7f33cc32003-01-10 20:51:00 +00001391# elif defined (X86_64)
1392# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1393# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
Roland McGrathac971c22003-03-31 01:03:33 +00001394# elif defined (SH)
1395# define arg0_offset (4*(REG_REG0+4))
1396# define arg1_offset (4*(REG_REG0+5))
Roland McGrathf5a47772003-06-26 22:40:42 +00001397# elif defined (SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001398 /* ABI defines arg0 & 1 in r2 & r3 */
1399# define arg0_offset (REG_OFFSET+16)
1400# define arg1_offset (REG_OFFSET+24)
1401# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001402# else
1403# define arg0_offset 0
1404# define arg1_offset 4
Roland McGrathac971c22003-03-31 01:03:33 +00001405# if defined ARM
Roland McGrathe1df47f2003-01-14 09:46:15 +00001406# define restore_arg0(tcp, state, val) 0
1407# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001408# endif
1409
1410typedef int arg_setup_state;
1411
1412# define arg_setup(tcp, state) (0)
1413# define arg_finish_change(tcp, state) 0
1414# define get_arg0(tcp, cookie, valp) \
1415 (upeek ((tcp)->pid, arg0_offset, (valp)))
1416# define get_arg1(tcp, cookie, valp) \
1417 (upeek ((tcp)->pid, arg1_offset, (valp)))
1418
1419static int
1420set_arg0 (struct tcb *tcp, void *cookie, long val)
1421{
Roland McGrathca85b972005-06-07 23:22:08 +00001422 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001423}
1424
1425static int
1426set_arg1 (struct tcb *tcp, void *cookie, long val)
1427{
1428 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
1429}
1430
1431#endif
1432
Roland McGrathe1df47f2003-01-14 09:46:15 +00001433#ifndef restore_arg0
1434# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1435#endif
1436#ifndef restore_arg1
1437# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1438#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001439
Roland McGrath90d0afd2004-03-01 21:05:16 +00001440#ifndef arg0_index
1441# define arg0_index 0
1442# define arg1_index 1
1443#endif
1444
Roland McGrathd81f1d92003-01-09 06:53:34 +00001445int
1446setbpt(tcp)
1447struct tcb *tcp;
1448{
1449 extern int change_syscall(struct tcb *, int);
1450 arg_setup_state state;
1451
1452 if (tcp->flags & TCB_BPTSET) {
1453 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1454 return -1;
1455 }
1456
Roland McGrath76989d72005-06-07 23:21:31 +00001457 switch (known_scno(tcp)) {
Roland McGrath9383c6c2003-01-18 00:19:31 +00001458#ifdef SYS_vfork
1459 case SYS_vfork:
1460#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001461#ifdef SYS_fork
1462 case SYS_fork:
Roland McGrath9b0982b2003-01-18 00:21:51 +00001463#endif
1464#if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001465 if (arg_setup (tcp, &state) < 0
1466 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1467 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
1468 || change_syscall(tcp, SYS_clone) < 0
1469 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1470 || set_arg1 (tcp, &state, 0) < 0
1471 || arg_finish_change (tcp, &state) < 0)
1472 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001473 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1474 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001475 tcp->flags |= TCB_BPTSET;
1476 return 0;
1477#endif
1478
1479 case SYS_clone:
1480#ifdef SYS_clone2
1481 case SYS_clone2:
1482#endif
Roland McGrath02cee8d2004-03-02 08:50:42 +00001483 if ((tcp->u_arg[arg0_index] & CLONE_PTRACE) == 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001484 && (arg_setup (tcp, &state) < 0
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001485 || set_arg0 (tcp, &state,
1486 tcp->u_arg[arg0_index] | CLONE_PTRACE) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001487 || arg_finish_change (tcp, &state) < 0))
1488 return -1;
1489 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001490 tcp->inst[0] = tcp->u_arg[arg0_index];
1491 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001492 return 0;
1493
1494 default:
1495 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1496 tcp->scno, tcp->pid);
1497 break;
1498 }
1499
1500 return -1;
1501}
1502
1503int
1504clearbpt(tcp)
1505struct tcb *tcp;
1506{
1507 arg_setup_state state;
1508 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001509 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1510 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001511 || arg_finish_change (tcp, &state))
1512 return -1;
1513 tcp->flags &= ~TCB_BPTSET;
1514 return 0;
1515}
1516
1517#else
1518
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001519int
1520setbpt(tcp)
1521struct tcb *tcp;
1522{
1523
1524#ifdef LINUX
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001525#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001526 /* We simply use the SunOS breakpoint code. */
1527
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001528 struct regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001529 unsigned long inst;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001530#define LOOPA 0x30800000 /* ba,a 0 */
1531
1532 if (tcp->flags & TCB_BPTSET) {
1533 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1534 return -1;
1535 }
1536 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1537 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1538 return -1;
1539 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001540 tcp->baddr = regs.r_o7 + 8;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001541 errno = 0;
1542 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1543 if(errno) {
1544 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1545 return -1;
1546 }
1547
1548 /*
1549 * XXX - BRUTAL MODE ON
1550 * We cannot set a real BPT in the child, since it will not be
1551 * traced at the moment it will reach the trap and would probably
1552 * die with a core dump.
1553 * Thus, we are force our way in by taking out two instructions
1554 * and insert an eternal loop instead, in expectance of the SIGSTOP
1555 * generated by out PTRACE_ATTACH.
1556 * Of cause, if we evaporate ourselves in the middle of all this...
1557 */
1558 errno = 0;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001559 inst = LOOPA;
1560#if defined (SPARC64)
1561 inst <<= 32;
1562 inst |= (tcp->inst[0] & 0xffffffffUL);
1563#endif
1564 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, inst);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001565 if(errno) {
1566 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1567 return -1;
1568 }
1569 tcp->flags |= TCB_BPTSET;
1570
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001571#else /* !SPARC && !SPARC64 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001572#ifdef IA64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001573 if (ia32) {
1574# define LOOP 0x0000feeb
1575 if (tcp->flags & TCB_BPTSET) {
1576 fprintf(stderr, "PANIC: bpt already set in pid %u\n",
1577 tcp->pid);
1578 return -1;
1579 }
1580 if (upeek(tcp->pid, PT_CR_IIP, &tcp->baddr) < 0)
1581 return -1;
1582 if (debug)
1583 fprintf(stderr, "[%d] setting bpt at %lx\n",
1584 tcp->pid, tcp->baddr);
1585 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid,
1586 (char *) tcp->baddr, 0);
1587 if (errno) {
1588 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1589 return -1;
1590 }
1591 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1592 if (errno) {
1593 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1594 return -1;
1595 }
1596 tcp->flags |= TCB_BPTSET;
1597 } else {
1598 /*
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001599 * Our strategy here is to replace the bundle that
1600 * contained the clone() syscall with a bundle of the
1601 * form:
1602 *
1603 * { 1: br 1b; br 1b; br 1b }
1604 *
1605 * This ensures that the newly forked child will loop
1606 * endlessly until we've got a chance to attach to it.
1607 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001608# define LOOP0 0x0000100000000017
1609# define LOOP1 0x4000000000200000
1610 unsigned long addr, ipsr;
1611 pid_t pid;
1612
1613 pid = tcp->pid;
1614 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1615 return -1;
1616 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1617 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001618 /* store "ri" in low two bits */
1619 tcp->baddr = addr | ((ipsr >> 41) & 0x3);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001620
1621 errno = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001622 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0,
1623 0);
1624 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8,
1625 0);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001626 if (errno) {
1627 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1628 return -1;
1629 }
1630
1631 errno = 0;
1632 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1633 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1634 if (errno) {
1635 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1636 return -1;
1637 }
1638 tcp->flags |= TCB_BPTSET;
1639 }
1640#else /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001641
Michal Ludvig0e035502002-09-23 15:41:01 +00001642#if defined (I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001643#define LOOP 0x0000feeb
1644#elif defined (M68K)
1645#define LOOP 0x60fe0000
1646#elif defined (ALPHA)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001647#define LOOP 0xc3ffffff
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648#elif defined (POWERPC)
Roland McGrath1e85cf92002-12-16 20:40:54 +00001649#define LOOP 0x48000000
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001650#elif defined(ARM)
Wichert Akkerman9a8a37f1999-12-24 23:19:31 +00001651#define LOOP 0xEAFFFFFE
Wichert Akkermanf90da011999-10-31 21:15:38 +00001652#elif defined(MIPS)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001653#define LOOP 0x1000ffff
1654#elif defined(S390)
1655#define LOOP 0xa7f40000 /* BRC 15,0 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001656#elif defined(S390X)
1657#define LOOP 0xa7f4000000000000UL /* BRC 15,0 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001658#elif defined(HPPA)
1659#define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001660#elif defined(SH)
1661#ifdef __LITTLE_ENDIAN__
1662#define LOOP 0x0000affe
1663#else
1664#define LOOP 0xfeaf0000
1665#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666#else
1667#error unknown architecture
1668#endif
1669
1670 if (tcp->flags & TCB_BPTSET) {
1671 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1672 return -1;
1673 }
1674#if defined (I386)
1675 if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1676 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00001677#elif defined (X86_64)
1678 if (upeek(tcp->pid, 8*RIP, &tcp->baddr) < 0)
1679 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001680#elif defined (M68K)
1681 if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1682 return -1;
1683#elif defined (ALPHA)
1684 return -1;
1685#elif defined (ARM)
1686 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001687#elif defined (MIPS)
1688 return -1; /* FIXME: I do not know what i do - Flo */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001689#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001690 if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001691 return -1;
Michal Ludvig10a88d02002-10-07 14:31:00 +00001692#elif defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001693 if (upeek(tcp->pid,PT_PSWADDR, &tcp->baddr) < 0)
1694 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001695#elif defined(HPPA)
1696 if (upeek(tcp->pid, PT_IAOQ0, &tcp->baddr) < 0)
1697 return -1;
1698 tcp->baddr &= ~0x03;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001699#elif defined(SH)
1700 if (upeek(tcp->pid, 4*REG_PC, &tcp->baddr) < 0)
1701 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001702#else
1703#error unknown architecture
1704#endif
1705 if (debug)
1706 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1707 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1708 if (errno) {
1709 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1710 return -1;
1711 }
1712 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1713 if (errno) {
1714 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1715 return -1;
1716 }
1717 tcp->flags |= TCB_BPTSET;
1718
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001719#endif /* !IA64 */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001720#endif /* SPARC || SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001721#endif /* LINUX */
1722
1723#ifdef SUNOS4
1724#ifdef SPARC /* This code is slightly sparc specific */
1725
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001726 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001727#define BPT 0x91d02001 /* ta 1 */
1728#define LOOP 0x10800000 /* ba 0 */
1729#define LOOPA 0x30800000 /* ba,a 0 */
1730#define NOP 0x01000000
1731#if LOOPA
1732 static int loopdeloop[1] = {LOOPA};
1733#else
1734 static int loopdeloop[2] = {LOOP, NOP};
1735#endif
1736
1737 if (tcp->flags & TCB_BPTSET) {
1738 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1739 return -1;
1740 }
1741 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1742 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1743 return -1;
1744 }
1745 tcp->baddr = regs.r_o7 + 8;
1746 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1747 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1748 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1749 return -1;
1750 }
1751
1752 /*
1753 * XXX - BRUTAL MODE ON
1754 * We cannot set a real BPT in the child, since it will not be
1755 * traced at the moment it will reach the trap and would probably
1756 * die with a core dump.
1757 * Thus, we are force our way in by taking out two instructions
1758 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1759 * generated by out PTRACE_ATTACH.
1760 * Of cause, if we evaporate ourselves in the middle of all this...
1761 */
1762 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1763 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1764 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1765 return -1;
1766 }
1767 tcp->flags |= TCB_BPTSET;
1768
1769#endif /* SPARC */
1770#endif /* SUNOS4 */
1771
1772 return 0;
1773}
1774
1775int
1776clearbpt(tcp)
1777struct tcb *tcp;
1778{
1779
1780#ifdef LINUX
Michal Ludvig0e035502002-09-23 15:41:01 +00001781#if defined(I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001782 long eip;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001783#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001784 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001785#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001786 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001787#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001788 long pc;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001789#elif defined(HPPA)
1790 long iaoq;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001791#elif defined(SH)
1792 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001793#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001794
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001795#if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001796 /* Again, we borrow the SunOS breakpoint code. */
1797 if (!(tcp->flags & TCB_BPTSET)) {
1798 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1799 return -1;
1800 }
1801 errno = 0;
1802 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1803 if(errno) {
1804 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1805 return -1;
1806 }
1807 tcp->flags &= ~TCB_BPTSET;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001808#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001809 if (ia32) {
1810 unsigned long addr;
1811
1812 if (debug)
1813 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1814 if (!(tcp->flags & TCB_BPTSET)) {
1815 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1816 return -1;
1817 }
1818 errno = 0;
1819 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1820 if (errno) {
1821 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1822 return -1;
1823 }
1824 tcp->flags &= ~TCB_BPTSET;
1825
1826 if (upeek(tcp->pid, PT_CR_IIP, &addr) < 0)
1827 return -1;
1828 if (addr != tcp->baddr) {
1829 /* The breakpoint has not been reached yet. */
1830 if (debug)
1831 fprintf(stderr,
1832 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1833 addr, tcp->baddr);
1834 return 0;
1835 }
1836 } else {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001837 unsigned long addr, ipsr;
1838 pid_t pid;
1839
1840 pid = tcp->pid;
1841
1842 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1843 return -1;
1844 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1845 return -1;
1846
1847 /* restore original bundle: */
1848 errno = 0;
1849 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
1850 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
1851 if (errno) {
1852 perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
1853 return -1;
1854 }
1855
1856 /* restore original "ri" in ipsr: */
1857 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
1858 errno = 0;
1859 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
1860 if (errno) {
1861 perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
1862 return -1;
1863 }
1864
1865 tcp->flags &= ~TCB_BPTSET;
1866
1867 if (addr != (tcp->baddr & ~0x3)) {
1868 /* the breakpoint has not been reached yet. */
1869 if (debug)
1870 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1871 addr, tcp->baddr);
1872 return 0;
1873 }
1874 }
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001875#else /* !IA64 && !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001876
1877 if (debug)
1878 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1879 if (!(tcp->flags & TCB_BPTSET)) {
1880 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1881 return -1;
1882 }
1883 errno = 0;
1884 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1885 if (errno) {
1886 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1887 return -1;
1888 }
1889 tcp->flags &= ~TCB_BPTSET;
1890
1891#ifdef I386
1892 if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1893 return -1;
1894 if (eip != tcp->baddr) {
1895 /* The breakpoint has not been reached yet. */
1896 if (debug)
1897 fprintf(stderr,
1898 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1899 eip, tcp->baddr);
1900 return 0;
1901 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001902#elif defined(X86_64)
1903 if (upeek(tcp->pid, 8*RIP, &eip) < 0)
1904 return -1;
1905 if (eip != tcp->baddr) {
1906 /* The breakpoint has not been reached yet. */
1907 if (debug)
1908 fprintf(stderr,
1909 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1910 eip, tcp->baddr);
1911 return 0;
1912 }
Wichert Akkermanc7926982000-04-10 22:22:31 +00001913#elif defined(POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001914 if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001915 return -1;
1916 if (pc != tcp->baddr) {
1917 /* The breakpoint has not been reached yet. */
1918 if (debug)
1919 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1920 pc, tcp->baddr);
1921 return 0;
1922 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001923#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001924 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1925 return -1;
1926 if (pc != tcp->baddr) {
1927 /* The breakpoint has not been reached yet. */
1928 if (debug)
1929 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1930 pc, tcp->baddr);
1931 return 0;
1932 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001933#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001934 if (upeek(tcp->pid, REG_PC, &pc) < 0)
1935 return -1;
1936 if (pc != tcp->baddr) {
1937 /* The breakpoint has not been reached yet. */
1938 if (debug)
1939 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1940 pc, tcp->baddr);
1941 return 0;
1942 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001943#elif defined(HPPA)
1944 if (upeek(tcp->pid, PT_IAOQ0, &iaoq) < 0)
1945 return -1;
1946 iaoq &= ~0x03;
1947 if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
1948 /* The breakpoint has not been reached yet. */
1949 if (debug)
1950 fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
1951 iaoq, tcp->baddr);
1952 return 0;
1953 }
1954 iaoq = tcp->baddr | 3;
1955 /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
1956 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
1957 * has no significant effect.
1958 */
1959 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
1960 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001961#elif defined(SH)
1962 if (upeek(tcp->pid, 4*REG_PC, &pc) < 0)
1963 return -1;
1964 if (pc != tcp->baddr) {
1965 /* The breakpoint has not been reached yet. */
1966 if (debug)
1967 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1968 pc, tcp->baddr);
1969 return 0;
1970 }
1971
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001972#endif /* arch */
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001973#endif /* !SPARC && !SPARC64 && !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001974#endif /* LINUX */
1975
1976#ifdef SUNOS4
1977#ifdef SPARC
1978
1979#if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001980 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001981#endif
1982
1983 if (!(tcp->flags & TCB_BPTSET)) {
1984 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1985 return -1;
1986 }
1987 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1988 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1989 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1990 return -1;
1991 }
1992 tcp->flags &= ~TCB_BPTSET;
1993
1994#if !LOOPA
1995 /*
1996 * Since we don't have a single instruction breakpoint, we may have
1997 * to adjust the program counter after removing the our `breakpoint'.
1998 */
1999 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
2000 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
2001 return -1;
2002 }
2003 if ((regs.r_pc < tcp->baddr) ||
2004 (regs.r_pc > tcp->baddr + 4)) {
2005 /* The breakpoint has not been reached yet */
2006 if (debug)
2007 fprintf(stderr,
2008 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
2009 regs.r_pc, tcp->parent->baddr);
2010 return 0;
2011 }
2012 if (regs.r_pc != tcp->baddr)
2013 if (debug)
2014 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
2015 regs.r_pc, tcp->baddr);
2016
2017 regs.r_pc = tcp->baddr;
2018 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
2019 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
2020 return -1;
2021 }
2022#endif /* LOOPA */
2023#endif /* SPARC */
2024#endif /* SUNOS4 */
2025
2026 return 0;
2027}
2028
Roland McGrathd81f1d92003-01-09 06:53:34 +00002029#endif
2030
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002031#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002032
2033#ifdef SUNOS4
2034
2035static int
2036getex(pid, hdr)
2037int pid;
2038struct exec *hdr;
2039{
2040 int n;
2041
2042 for (n = 0; n < sizeof *hdr; n += 4) {
2043 long res;
2044 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
2045 return -1;
2046 memcpy(((char *) hdr) + n, &res, 4);
2047 }
2048 if (debug) {
2049 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
2050 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
2051 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
2052 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
2053 }
2054 return 0;
2055}
2056
2057int
2058fixvfork(tcp)
2059struct tcb *tcp;
2060{
2061 int pid = tcp->pid;
2062 /*
2063 * Change `vfork' in a freshly exec'ed dynamically linked
2064 * executable's (internal) symbol table to plain old `fork'
2065 */
2066
2067 struct exec hdr;
2068 struct link_dynamic dyn;
2069 struct link_dynamic_2 ld;
2070 char *strtab, *cp;
2071
2072 if (getex(pid, &hdr) < 0)
2073 return -1;
2074 if (!hdr.a_dynamic)
2075 return -1;
2076
2077 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
2078 fprintf(stderr, "Cannot read DYNAMIC\n");
2079 return -1;
2080 }
2081 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
2082 fprintf(stderr, "Cannot read link_dynamic_2\n");
2083 return -1;
2084 }
2085 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00002086 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002087 return -1;
2088 }
2089 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
2090 (int)ld.ld_symb_size, strtab) < 0)
2091 goto err;
2092
2093#if 0
2094 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2095 fprintf(stderr, "[symbol: %s]\n", cp);
2096 cp += strlen(cp)+1;
2097 }
2098 return 0;
2099#endif
2100 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2101 if (strcmp(cp, "_vfork") == 0) {
2102 if (debug)
2103 fprintf(stderr, "fixvfork: FOUND _vfork\n");
2104 strcpy(cp, "_fork");
2105 break;
2106 }
2107 cp += strlen(cp)+1;
2108 }
2109 if (cp < strtab + ld.ld_symb_size)
2110 /*
2111 * Write entire symbol table back to avoid
2112 * memory alignment bugs in ptrace
2113 */
2114 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
2115 (int)ld.ld_symb_size, strtab) < 0)
2116 goto err;
2117
2118 free(strtab);
2119 return 0;
2120
2121err:
2122 free(strtab);
2123 return -1;
2124}
2125
2126#endif /* SUNOS4 */