blob: d40eafc2946a7f2bde896988f5de8e0f24f743e8 [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.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000032 */
33
34#include "defs.h"
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000035#include <sys/param.h>
36#include <fcntl.h>
Mike Frysinger54646b82015-08-19 13:29:27 -040037#include <stdarg.h>
Dmitry V. Levind93c4e82015-06-17 20:09:13 +000038#ifdef HAVE_SYS_XATTR_H
Masatake YAMATOf5480672014-11-22 19:03:33 +090039# include <sys/xattr.h>
40#endif
Dmitry V. Levinb2fa2be2014-11-21 20:46:16 +000041#include <sys/uio.h>
Wichert Akkerman36915a11999-07-13 15:45:02 +000042
Dmitry V. Levin5503dd22015-02-13 02:12:14 +000043#include "regs.h"
Dmitry V. Levin7211dbc2015-02-28 12:20:21 +000044#include "ptrace.h"
Wichert Akkerman2e2553a1999-05-09 00:29:58 +000045
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000046int
Dmitry V. Levinccee1692012-03-25 21:49:48 +000047string_to_uint(const char *str)
48{
49 char *error;
50 long value;
51
52 if (!*str)
53 return -1;
54 errno = 0;
55 value = strtol(str, &error, 10);
56 if (errno || *error || value < 0 || (long)(int)value != value)
57 return -1;
58 return (int)value;
59}
60
61int
Dmitry V. Levin447db452014-05-29 17:59:01 +000062tv_nz(const struct timeval *a)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000063{
64 return a->tv_sec || a->tv_usec;
65}
66
67int
Dmitry V. Levin447db452014-05-29 17:59:01 +000068tv_cmp(const struct timeval *a, const struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000069{
70 if (a->tv_sec < b->tv_sec
71 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
72 return -1;
73 if (a->tv_sec > b->tv_sec
74 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
75 return 1;
76 return 0;
77}
78
79double
Dmitry V. Levin447db452014-05-29 17:59:01 +000080tv_float(const struct timeval *tv)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000081{
82 return tv->tv_sec + tv->tv_usec/1000000.0;
83}
84
85void
Dmitry V. Levin447db452014-05-29 17:59:01 +000086tv_add(struct timeval *tv, const struct timeval *a, const struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000087{
88 tv->tv_sec = a->tv_sec + b->tv_sec;
89 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +000090 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000091 tv->tv_sec++;
92 tv->tv_usec -= 1000000;
93 }
94}
95
96void
Dmitry V. Levin447db452014-05-29 17:59:01 +000097tv_sub(struct timeval *tv, const struct timeval *a, const struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000098{
99 tv->tv_sec = a->tv_sec - b->tv_sec;
100 tv->tv_usec = a->tv_usec - b->tv_usec;
101 if (((long) tv->tv_usec) < 0) {
102 tv->tv_sec--;
103 tv->tv_usec += 1000000;
104 }
105}
106
107void
Dmitry V. Levin447db452014-05-29 17:59:01 +0000108tv_div(struct timeval *tv, const struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000109{
110 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
111 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
112 tv->tv_usec %= 1000000;
113}
114
115void
Dmitry V. Levin447db452014-05-29 17:59:01 +0000116tv_mul(struct timeval *tv, const struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000117{
118 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000119 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120 tv->tv_usec %= 1000000;
121}
122
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000123const char *
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000124xlookup(const struct xlat *xlat, const unsigned int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000125{
126 for (; xlat->str != NULL; xlat++)
127 if (xlat->val == val)
128 return xlat->str;
129 return NULL;
130}
131
Dmitry V. Levin4176d532014-09-21 22:42:45 +0000132static int
133xlat_bsearch_compare(const void *a, const void *b)
134{
135 const unsigned int val1 = (const unsigned long) a;
136 const unsigned int val2 = ((const struct xlat *) b)->val;
137 return (val1 > val2) ? 1 : (val1 < val2) ? -1 : 0;
138}
139
140const char *
141xlat_search(const struct xlat *xlat, const size_t nmemb, const unsigned int val)
142{
143 const struct xlat *e =
144 bsearch((const void*) (const unsigned long) val,
145 xlat, nmemb, sizeof(*xlat), xlat_bsearch_compare);
146
147 return e ? e->str : NULL;
148}
149
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200150#if !defined HAVE_STPCPY
Denys Vlasenko52845572011-08-31 12:07:38 +0200151char *
152stpcpy(char *dst, const char *src)
153{
154 while ((*dst = *src++) != '\0')
155 dst++;
156 return dst;
157}
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200158#endif
Denys Vlasenko52845572011-08-31 12:07:38 +0200159
Denys Vlasenkob338f2d2013-11-09 20:40:31 +0100160/* Find a next bit which is set.
161 * Starts testing at cur_bit.
162 * Returns -1 if no more bits are set.
163 *
164 * We never touch bytes we don't need to.
165 * On big-endian, array is assumed to consist of
166 * current_wordsize wide words: for example, is current_wordsize is 4,
167 * the bytes are walked in 3,2,1,0, 7,6,5,4, 11,10,9,8 ... sequence.
168 * On little-endian machines, word size is immaterial.
169 */
170int
171next_set_bit(const void *bit_array, unsigned cur_bit, unsigned size_bits)
172{
173 const unsigned endian = 1;
174 int little_endian = *(char*)&endian;
175
176 const uint8_t *array = bit_array;
177 unsigned pos = cur_bit / 8;
178 unsigned pos_xor_mask = little_endian ? 0 : current_wordsize-1;
179
180 for (;;) {
181 uint8_t bitmask;
182 uint8_t cur_byte;
183
184 if (cur_bit >= size_bits)
185 return -1;
186 cur_byte = array[pos ^ pos_xor_mask];
187 if (cur_byte == 0) {
188 cur_bit = (cur_bit + 8) & (-8);
189 pos++;
190 continue;
191 }
192 bitmask = 1 << (cur_bit & 7);
193 for (;;) {
194 if (cur_byte & bitmask)
195 return cur_bit;
196 cur_bit++;
197 if (cur_bit >= size_bits)
198 return -1;
199 bitmask <<= 1;
200 /* This check *can't be* optimized out: */
201 if (bitmask == 0)
202 break;
203 }
204 pos++;
205 }
206}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000207/*
208 * Print entry in struct xlat table, if there.
209 */
210void
Mike Frysinger54646b82015-08-19 13:29:27 -0400211printxvals(const unsigned int val, const char *dflt, const struct xlat *xlat, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000212{
Mike Frysinger54646b82015-08-19 13:29:27 -0400213 va_list args;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000214
Mike Frysinger54646b82015-08-19 13:29:27 -0400215 va_start(args, xlat);
216 for (; xlat; xlat = va_arg(args, const struct xlat *)) {
217 const char *str = xlookup(xlat, val);
218
219 if (str) {
220 tprints(str);
221 va_end(args);
222 return;
223 }
224 }
225 /* No hits -- print raw # instead. */
226 tprintf("%#x /* %s */", val, dflt);
227
228 va_end(args);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000229}
230
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100231/*
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000232 * Fetch 64bit argument at position arg_no and
233 * return the index of the next argument.
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100234 */
235int
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000236getllval(struct tcb *tcp, unsigned long long *val, int arg_no)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100237{
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000238#if SIZEOF_LONG > 4 && SIZEOF_LONG == SIZEOF_LONG_LONG
239# if SUPPORTED_PERSONALITIES > 1
240 if (current_wordsize > 4) {
241# endif
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000242 *val = tcp->u_arg[arg_no];
Chris Metcalf879dddd2013-03-01 10:41:02 +0100243 arg_no++;
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000244# if SUPPORTED_PERSONALITIES > 1
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100245 } else {
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000246# if defined(AARCH64) || defined(POWERPC64)
Dmitry V. Levin3c49b022014-08-07 00:07:28 +0000247 /* Align arg_no to the next even number. */
248 arg_no = (arg_no + 1) & 0xe;
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000249# endif /* AARCH64 || POWERPC64 */
250 *val = LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]);
Chris Metcalf879dddd2013-03-01 10:41:02 +0100251 arg_no += 2;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100252 }
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000253# endif /* SUPPORTED_PERSONALITIES > 1 */
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000254#elif SIZEOF_LONG > 4
255# error Unsupported configuration: SIZEOF_LONG > 4 && SIZEOF_LONG_LONG > SIZEOF_LONG
256#elif defined LINUX_MIPSN32
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000257 *val = tcp->ext_arg[arg_no];
Chris Metcalf879dddd2013-03-01 10:41:02 +0100258 arg_no++;
Dmitry V. Levin0b468832013-05-02 08:41:27 +0000259#elif defined X32
260 if (current_personality == 0) {
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000261 *val = tcp->ext_arg[arg_no];
Dmitry V. Levin0b468832013-05-02 08:41:27 +0000262 arg_no++;
263 } else {
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000264 *val = LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]);
Dmitry V. Levin0b468832013-05-02 08:41:27 +0000265 arg_no += 2;
266 }
Denys Vlasenkoc9d0fc02013-02-17 22:41:33 +0100267#else
Dmitry V. Levin8e096c42013-05-06 18:23:01 +0000268# if defined __ARM_EABI__ || \
269 defined LINUX_MIPSO32 || \
270 defined POWERPC || \
271 defined XTENSA
Dmitry V. Levin3c49b022014-08-07 00:07:28 +0000272 /* Align arg_no to the next even number. */
273 arg_no = (arg_no + 1) & 0xe;
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000274# endif
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000275 *val = LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]);
Chris Metcalf879dddd2013-03-01 10:41:02 +0100276 arg_no += 2;
Denys Vlasenkoc9d0fc02013-02-17 22:41:33 +0100277#endif
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000278
Chris Metcalf879dddd2013-03-01 10:41:02 +0100279 return arg_no;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100280}
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100281
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000282/*
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000283 * Print 64bit argument at position arg_no and
284 * return the index of the next argument.
285 */
286int
287printllval(struct tcb *tcp, const char *format, int arg_no)
288{
289 unsigned long long val = 0;
290
291 arg_no = getllval(tcp, &val, arg_no);
292 tprintf(format, val);
293 return arg_no;
294}
295
296/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000297 * Interpret `xlat' as an array of flags
298 * print the entries whose bits are on in `flags'
299 * return # of flags printed.
300 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200301void
Denys Vlasenko12014262011-05-30 14:00:14 +0200302addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000303{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200304 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000305 if (xlat->val && (flags & xlat->val) == xlat->val) {
306 tprintf("|%s", xlat->str);
307 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000308 }
309 }
310 if (flags) {
311 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000312 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000313}
314
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000315/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200316 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000317 * Print to static string the entries whose bits are on in `flags'
318 * Return static string.
319 */
320const char *
321sprintflags(const char *prefix, const struct xlat *xlat, int flags)
322{
323 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200324 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000325 int found = 0;
326
Denys Vlasenko52845572011-08-31 12:07:38 +0200327 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000328
329 for (; xlat->str; xlat++) {
330 if ((flags & xlat->val) == xlat->val) {
331 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200332 *outptr++ = '|';
333 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000334 found = 1;
Denys Vlasenko4f3df072012-01-29 22:38:35 +0100335 flags &= ~xlat->val;
336 if (!flags)
337 break;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000338 }
339 }
340 if (flags) {
341 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200342 *outptr++ = '|';
343 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000344 }
345
346 return outstr;
347}
348
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000349int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000350printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000351{
352 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000353 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000354
355 if (flags == 0 && xlat->val == 0) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200356 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000357 return 1;
358 }
359
360 sep = "";
361 for (n = 0; xlat->str; xlat++) {
362 if (xlat->val && (flags & xlat->val) == xlat->val) {
363 tprintf("%s%s", sep, xlat->str);
364 flags &= ~xlat->val;
365 sep = "|";
366 n++;
367 }
368 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000369
370 if (n) {
371 if (flags) {
372 tprintf("%s%#x", sep, flags);
373 n++;
374 }
375 } else {
376 if (flags) {
377 tprintf("%#x", flags);
378 if (dflt)
379 tprintf(" /* %s */", dflt);
380 } else {
381 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200382 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000383 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000384 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000385
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000386 return n;
387}
388
389void
Dmitry V. Levin332a3262015-07-05 22:09:29 +0000390printaddr(const long addr)
391{
392 if (!addr)
393 tprints("NULL");
394 else
395 tprintf("%#lx", addr);
396}
397
Dmitry V. Levinc88163e2015-07-05 22:09:29 +0000398#define DEF_PRINTNUM(name, type) \
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000399bool \
Dmitry V. Levinc88163e2015-07-05 22:09:29 +0000400printnum_ ## name(struct tcb *tcp, const long addr, const char *fmt) \
401{ \
402 type num; \
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000403 if (umove_or_printaddr(tcp, addr, &num)) \
404 return false; \
405 tprints("["); \
406 tprintf(fmt, num); \
407 tprints("]"); \
408 return true; \
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000409}
410
Dmitry V. Levin69127a32015-07-05 22:09:29 +0000411#define DEF_PRINTPAIR(name, type) \
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000412bool \
Dmitry V. Levin69127a32015-07-05 22:09:29 +0000413printpair_ ## name(struct tcb *tcp, const long addr, const char *fmt) \
414{ \
415 type pair[2]; \
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000416 if (umove_or_printaddr(tcp, addr, &pair)) \
417 return false; \
418 tprints("["); \
419 tprintf(fmt, pair[0]); \
420 tprints(", "); \
421 tprintf(fmt, pair[1]); \
422 tprints("]"); \
423 return true; \
Dmitry V. Levin69127a32015-07-05 22:09:29 +0000424}
425
Dmitry V. Levinc88163e2015-07-05 22:09:29 +0000426DEF_PRINTNUM(int, int)
Dmitry V. Levin69127a32015-07-05 22:09:29 +0000427DEF_PRINTPAIR(int, int)
Dmitry V. Levinc88163e2015-07-05 22:09:29 +0000428DEF_PRINTNUM(short, short)
Dmitry V. Levinc88163e2015-07-05 22:09:29 +0000429DEF_PRINTNUM(int64, uint64_t)
Dmitry V. Levin69127a32015-07-05 22:09:29 +0000430DEF_PRINTPAIR(int64, uint64_t)
Dmitry V. Levin2479ef02015-08-18 14:58:27 +0000431
432#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000433bool
Dmitry V. Levin2479ef02015-08-18 14:58:27 +0000434printnum_long_int(struct tcb *tcp, const long addr,
435 const char *fmt_long, const char *fmt_int)
436{
437 if (current_wordsize > sizeof(int)) {
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000438 return printnum_int64(tcp, addr, fmt_long);
Dmitry V. Levin2479ef02015-08-18 14:58:27 +0000439 } else {
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000440 return printnum_int(tcp, addr, fmt_int);
Dmitry V. Levin2479ef02015-08-18 14:58:27 +0000441 }
442}
Dmitry V. Levinc88163e2015-07-05 22:09:29 +0000443#endif
Roland McGrath9814a942005-07-04 23:28:10 +0000444
Dmitry V. Levinb1a01b82014-12-06 03:53:16 +0000445const char *
446sprinttime(time_t t)
447{
448 struct tm *tmp;
Dmitry V. Levind4a9d832015-01-08 15:08:16 +0000449 static char buf[sizeof(int) * 3 * 6];
Dmitry V. Levinb1a01b82014-12-06 03:53:16 +0000450
451 if (t == 0) {
452 strcpy(buf, "0");
453 return buf;
454 }
455 tmp = localtime(&t);
456 if (tmp)
457 snprintf(buf, sizeof buf, "%02d/%02d/%02d-%02d:%02d:%02d",
458 tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
459 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
460 else
461 snprintf(buf, sizeof buf, "%lu", (unsigned long) t);
462
463 return buf;
464}
465
Masatake YAMATOf5480672014-11-22 19:03:33 +0900466static char *
467getfdproto(struct tcb *tcp, int fd, char *buf, unsigned bufsize)
468{
Dmitry V. Levind93c4e82015-06-17 20:09:13 +0000469#ifdef HAVE_SYS_XATTR_H
Masatake YAMATOf5480672014-11-22 19:03:33 +0900470 ssize_t r;
471 char path[sizeof("/proc/%u/fd/%u") + 2 * sizeof(int)*3];
472
473 if (fd < 0)
474 return NULL;
475
476 sprintf(path, "/proc/%u/fd/%u", tcp->pid, fd);
477 r = getxattr(path, "system.sockprotoname", buf, bufsize - 1);
478 if (r <= 0)
479 return NULL;
480 else {
481 /*
482 * This is a protection for the case when the kernel
483 * side does not append a null byte to the buffer.
484 */
485 buf[r] = '\0';
486 return buf;
487 }
488#else
489 return NULL;
490#endif
491}
492
Roland McGrath9814a942005-07-04 23:28:10 +0000493void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300494printfd(struct tcb *tcp, int fd)
495{
Denys Vlasenko61ad0a42013-03-06 18:24:34 +0100496 char path[PATH_MAX + 1];
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000497 if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) {
498 static const char socket_prefix[] = "socket:[";
499 const size_t socket_prefix_len = sizeof(socket_prefix) - 1;
Dmitry V. Levinc7235992015-01-24 19:51:39 +0000500 const size_t path_len = strlen(path);
Grant Edwards8a082772011-04-07 20:25:40 +0000501
Dmitry V. Levinc7235992015-01-24 19:51:39 +0000502 tprintf("%d<", fd);
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000503 if (show_fd_path > 1 &&
504 strncmp(path, socket_prefix, socket_prefix_len) == 0 &&
Dmitry V. Levinc7235992015-01-24 19:51:39 +0000505 path[path_len - 1] == ']') {
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000506 unsigned long inodenr;
Masatake YAMATOf605e922014-12-10 12:55:06 +0900507#define PROTO_NAME_LEN 32
508 char proto_buf[PROTO_NAME_LEN];
509 const char *proto =
510 getfdproto(tcp, fd, proto_buf, PROTO_NAME_LEN);
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000511 inodenr = strtoul(path + socket_prefix_len, NULL, 10);
Masatake YAMATOf605e922014-12-10 12:55:06 +0900512 if (!print_sockaddr_by_inode(inodenr, proto)) {
Masatake YAMATOf5480672014-11-22 19:03:33 +0900513 if (proto)
514 tprintf("%s:[%lu]", proto, inodenr);
515 else
516 tprints(path);
517 }
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000518 } else {
Dmitry V. Levinc7235992015-01-24 19:51:39 +0000519 print_quoted_string(path, path_len,
520 QUOTE_OMIT_LEADING_TRAILING_QUOTES);
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000521 }
Dmitry V. Levinc7235992015-01-24 19:51:39 +0000522 tprints(">");
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000523 } else
Grant Edwards8a082772011-04-07 20:25:40 +0000524 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300525}
526
Dmitry V. Levina501f142008-11-10 23:19:13 +0000527/*
528 * Quote string `instr' of length `size'
529 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100530 *
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000531 * If QUOTE_0_TERMINATED `style' flag is set,
532 * treat `instr' as a NUL-terminated string,
533 * checking up to (`size' + 1) bytes of `instr'.
534 *
535 * If QUOTE_OMIT_LEADING_TRAILING_QUOTES `style' flag is set,
536 * do not add leading and trailing quoting symbols.
537 *
538 * Returns 0 if QUOTE_0_TERMINATED is set and NUL was seen, 1 otherwise.
539 * Note that if QUOTE_0_TERMINATED is not set, always returns 1.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000540 */
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000541static int
542string_quote(const char *instr, char *outstr, const unsigned int size,
543 const unsigned int style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000545 const unsigned char *ustr = (const unsigned char *) instr;
546 char *s = outstr;
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000547 unsigned int i;
548 int usehex, c, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000549
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000550 if (style & QUOTE_0_TERMINATED)
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200551 eol = '\0';
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000552 else
553 eol = 0x100; /* this can never match a char */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200554
555 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000556 if (xflag > 1)
557 usehex = 1;
558 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000559 /* Check for presence of symbol which require
560 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000561 for (i = 0; i < size; ++i) {
562 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000563 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200564 if (c == eol)
565 break;
Denys Vlasenko5198ed42013-03-06 23:44:23 +0100566
567 /* Force hex unless c is printable or whitespace */
568 if (c > 0x7e) {
569 usehex = 1;
570 break;
571 }
572 /* In ASCII isspace is only these chars: "\t\n\v\f\r".
573 * They happen to have ASCII codes 9,10,11,12,13.
574 */
575 if (c < ' ' && (unsigned)(c - 9) >= 5) {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000576 usehex = 1;
577 break;
578 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000579 }
580 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000581
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000582 if (!(style & QUOTE_OMIT_LEADING_TRAILING_QUOTES))
583 *s++ = '\"';
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000584
585 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000586 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000587 for (i = 0; i < size; ++i) {
588 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000589 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200590 if (c == eol)
591 goto asciz_ended;
592 *s++ = '\\';
593 *s++ = 'x';
594 *s++ = "0123456789abcdef"[c >> 4];
595 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000596 }
597 } else {
598 for (i = 0; i < size; ++i) {
599 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000600 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200601 if (c == eol)
602 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000603 switch (c) {
604 case '\"': case '\\':
605 *s++ = '\\';
606 *s++ = c;
607 break;
608 case '\f':
609 *s++ = '\\';
610 *s++ = 'f';
611 break;
612 case '\n':
613 *s++ = '\\';
614 *s++ = 'n';
615 break;
616 case '\r':
617 *s++ = '\\';
618 *s++ = 'r';
619 break;
620 case '\t':
621 *s++ = '\\';
622 *s++ = 't';
623 break;
624 case '\v':
625 *s++ = '\\';
626 *s++ = 'v';
627 break;
628 default:
Denys Vlasenko5198ed42013-03-06 23:44:23 +0100629 if (c >= ' ' && c <= 0x7e)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000630 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200631 else {
632 /* Print \octal */
633 *s++ = '\\';
634 if (i + 1 < size
635 && ustr[i + 1] >= '0'
636 && ustr[i + 1] <= '9'
637 ) {
638 /* Print \ooo */
639 *s++ = '0' + (c >> 6);
640 *s++ = '0' + ((c >> 3) & 0x7);
641 } else {
642 /* Print \[[o]o]o */
643 if ((c >> 3) != 0) {
644 if ((c >> 6) != 0)
645 *s++ = '0' + (c >> 6);
646 *s++ = '0' + ((c >> 3) & 0x7);
647 }
648 }
649 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000650 }
651 break;
652 }
653 }
654 }
655
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000656 if (!(style & QUOTE_OMIT_LEADING_TRAILING_QUOTES))
657 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000658 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000659
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200660 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000661 if (style & QUOTE_0_TERMINATED && ustr[i] == '\0') {
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200662 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
663 * but next char is NUL.
664 */
665 return 0;
666 }
667
668 return 1;
669
670 asciz_ended:
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000671 if (!(style & QUOTE_OMIT_LEADING_TRAILING_QUOTES))
672 *s++ = '\"';
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200673 *s = '\0';
674 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
675 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000676}
677
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000678#ifndef ALLOCA_CUTOFF
679# define ALLOCA_CUTOFF 4032
680#endif
681#define use_alloca(n) ((n) <= ALLOCA_CUTOFF)
682
683/*
684 * Quote string `str' of length `size' and print the result.
685 *
686 * If QUOTE_0_TERMINATED `style' flag is set,
687 * treat `str' as a NUL-terminated string and
688 * quote at most (`size' - 1) bytes.
689 *
690 * If QUOTE_OMIT_LEADING_TRAILING_QUOTES `style' flag is set,
691 * do not add leading and trailing quoting symbols.
692 *
693 * Returns 0 if QUOTE_0_TERMINATED is set and NUL was seen, 1 otherwise.
694 * Note that if QUOTE_0_TERMINATED is not set, always returns 1.
695 */
696int
697print_quoted_string(const char *str, unsigned int size,
698 const unsigned int style)
699{
700 char *buf;
701 char *outstr;
702 unsigned int alloc_size;
703 int rc;
704
705 if (size && style & QUOTE_0_TERMINATED)
706 --size;
707
708 alloc_size = 4 * size;
709 if (alloc_size / 4 != size) {
710 error_msg("Out of memory");
711 tprints("???");
712 return -1;
713 }
714 alloc_size += 1 + (style & QUOTE_OMIT_LEADING_TRAILING_QUOTES ? 0 : 2);
715
716 if (use_alloca(alloc_size)) {
717 outstr = alloca(alloc_size);
718 buf = NULL;
719 } else {
720 outstr = buf = malloc(alloc_size);
721 if (!buf) {
722 error_msg("Out of memory");
723 tprints("???");
724 return -1;
725 }
726 }
727
728 rc = string_quote(str, outstr, size, style);
729 tprints(outstr);
730
731 free(buf);
732 return rc;
733}
734
Dmitry V. Levina501f142008-11-10 23:19:13 +0000735/*
736 * Print path string specified by address `addr' and length `n'.
737 * If path length exceeds `n', append `...' to the output.
738 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000739void
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000740printpathn(struct tcb *tcp, long addr, unsigned int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000741{
Dmitry V. Levin025b3582014-11-21 22:28:34 +0000742 char path[PATH_MAX + 1];
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100743 int nul_seen;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100744
Dmitry V. Levina501f142008-11-10 23:19:13 +0000745 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200746 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000747 return;
748 }
749
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100750 /* Cap path length to the path buffer size */
Dmitry V. Levina501f142008-11-10 23:19:13 +0000751 if (n > sizeof path - 1)
752 n = sizeof path - 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000753
754 /* Fetch one byte more to find out whether path length > n. */
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100755 nul_seen = umovestr(tcp, addr, n + 1, path);
756 if (nul_seen < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000757 tprintf("%#lx", addr);
758 else {
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000759 path[n++] = '\0';
760 print_quoted_string(path, n, QUOTE_0_TERMINATED);
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100761 if (!nul_seen)
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100762 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763 }
764}
765
766void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000767printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000768{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100769 /* Size must correspond to char path[] size in printpathn */
Dmitry V. Levin025b3582014-11-21 22:28:34 +0000770 printpathn(tcp, addr, PATH_MAX);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000771}
772
Dmitry V. Levina501f142008-11-10 23:19:13 +0000773/*
774 * Print string specified by address `addr' and length `len'.
775 * If `len' < 0, treat the string as a NUL-terminated string.
776 * If string length exceeds `max_strlen', append `...' to the output.
777 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000778void
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200779printstr(struct tcb *tcp, long addr, long len)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000780{
781 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000782 static char *outstr;
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000783 unsigned int size;
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000784 unsigned int style;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100785 int ellipsis;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000786
787 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200788 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789 return;
790 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000791 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200792 if (!str) {
Dmitry V. Levin378f9c52012-03-25 22:56:53 +0000793 unsigned int outstr_size = 4 * max_strlen + /*for quotes and NUL:*/ 3;
794
795 if (outstr_size / 4 != max_strlen)
796 die_out_of_memory();
Dmitry V. Levin3e9d71f2015-05-25 20:41:02 +0000797 str = xmalloc(max_strlen + 1);
798 outstr = xmalloc(outstr_size);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000800
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000801 size = max_strlen;
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200802 if (len == -1) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000803 /*
804 * Treat as a NUL-terminated string: fetch one byte more
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000805 * because string_quote may look one byte ahead.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000806 */
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000807 if (umovestr(tcp, addr, size + 1, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000808 tprintf("%#lx", addr);
809 return;
810 }
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000811 style = QUOTE_0_TERMINATED;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000812 }
813 else {
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200814 if (size > (unsigned long)len)
815 size = (unsigned long)len;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000816 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000817 tprintf("%#lx", addr);
818 return;
819 }
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000820 style = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000821 }
822
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100823 /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
824 * or we were requested to print more than -s NUM chars)...
825 */
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000826 ellipsis = (string_quote(str, outstr, size, style) &&
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000827 (len < 0 || (unsigned long) len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000828
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100829 tprints(outstr);
830 if (ellipsis)
831 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000832}
833
John Hughes1d08dcf2001-07-10 13:48:44 +0000834void
Denys Vlasenko12014262011-05-30 14:00:14 +0200835dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000836{
Denys Vlasenko84703742012-02-25 02:38:52 +0100837#if SUPPORTED_PERSONALITIES > 1
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000838 union {
839 struct { u_int32_t base; u_int32_t len; } *iov32;
840 struct { u_int64_t base; u_int64_t len; } *iov64;
841 } iovu;
842#define iov iovu.iov64
843#define sizeof_iov \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100844 (current_wordsize == 4 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000845#define iov_iov_base(i) \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100846 (current_wordsize == 4 ? (uint64_t) iovu.iov32[i].base : iovu.iov64[i].base)
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000847#define iov_iov_len(i) \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100848 (current_wordsize == 4 ? (uint64_t) iovu.iov32[i].len : iovu.iov64[i].len)
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000849#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000850 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000851#define sizeof_iov sizeof(*iov)
852#define iov_iov_base(i) iov[i].iov_base
853#define iov_iov_len(i) iov[i].iov_len
854#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000855 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200856 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000857
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200858 size = sizeof_iov * len;
859 /* Assuming no sane program has millions of iovs */
860 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000861 || (iov = malloc(size)) == NULL) {
Dmitry V. Levindf389912015-05-25 23:33:31 +0300862 error_msg("Out of memory");
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200863 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000864 }
Denys Vlasenko7e69ed92015-03-21 19:50:53 +0100865 if (umoven(tcp, addr, size, iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000866 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000867 /* include the buffer number to make it easy to
868 * match up the trace with the source */
869 tprintf(" * %lu bytes in buffer %d\n",
870 (unsigned long)iov_iov_len(i), i);
871 dumpstr(tcp, (long) iov_iov_base(i),
872 iov_iov_len(i));
873 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000874 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200875 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000876#undef sizeof_iov
877#undef iov_iov_base
878#undef iov_iov_len
879#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000880}
John Hughes1d08dcf2001-07-10 13:48:44 +0000881
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000882void
Denys Vlasenko12014262011-05-30 14:00:14 +0200883dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000884{
885 static int strsize = -1;
886 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000887
Denys Vlasenko76325802013-02-22 14:47:39 +0100888 char outbuf[
889 (
890 (sizeof(
891 "xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx "
892 "1234567890123456") + /*in case I'm off by few:*/ 4)
893 /*align to 8 to make memset easier:*/ + 7) & -8
894 ];
895 const unsigned char *src;
896 int i;
897
898 memset(outbuf, ' ', sizeof(outbuf));
899
900 if (strsize < len + 16) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200901 free(str);
Denys Vlasenko76325802013-02-22 14:47:39 +0100902 str = malloc(len + 16);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200903 if (!str) {
904 strsize = -1;
Dmitry V. Levindf389912015-05-25 23:33:31 +0300905 error_msg("Out of memory");
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200906 return;
907 }
Denys Vlasenko76325802013-02-22 14:47:39 +0100908 strsize = len + 16;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000909 }
910
Denys Vlasenko7e69ed92015-03-21 19:50:53 +0100911 if (umoven(tcp, addr, len, str) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000912 return;
913
Denys Vlasenko76325802013-02-22 14:47:39 +0100914 /* Space-pad to 16 bytes */
915 i = len;
916 while (i & 0xf)
917 str[i++] = ' ';
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200918
Denys Vlasenko76325802013-02-22 14:47:39 +0100919 i = 0;
920 src = str;
921 while (i < len) {
922 char *dst = outbuf;
923 /* Hex dump */
924 do {
925 if (i < len) {
926 *dst++ = "0123456789abcdef"[*src >> 4];
927 *dst++ = "0123456789abcdef"[*src & 0xf];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000928 }
929 else {
Denys Vlasenko76325802013-02-22 14:47:39 +0100930 *dst++ = ' ';
931 *dst++ = ' ';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000932 }
Denys Vlasenko76325802013-02-22 14:47:39 +0100933 dst++; /* space is there by memset */
934 i++;
935 if ((i & 7) == 0)
936 dst++; /* space is there by memset */
937 src++;
938 } while (i & 0xf);
939 /* ASCII dump */
940 i -= 16;
941 src -= 16;
942 do {
943 if (*src >= ' ' && *src < 0x7f)
944 *dst++ = *src;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000945 else
Denys Vlasenko76325802013-02-22 14:47:39 +0100946 *dst++ = '.';
947 src++;
948 } while (++i & 0xf);
949 *dst = '\0';
Denys Vlasenkof90979b2013-02-22 15:00:11 +0100950 tprintf(" | %05x %s |\n", i - 16, outbuf);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000951 }
952}
953
Mike Frysinger612659e2012-02-14 14:38:28 +0100954#ifdef HAVE_PROCESS_VM_READV
955/* C library supports this, but the kernel might not. */
956static bool process_vm_readv_not_supported = 0;
957#else
958
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100959/* Need to do this since process_vm_readv() is not yet available in libc.
960 * When libc is be updated, only "static bool process_vm_readv_not_supported"
961 * line should remain.
962 */
963#if !defined(__NR_process_vm_readv)
964# if defined(I386)
965# define __NR_process_vm_readv 347
966# elif defined(X86_64)
967# define __NR_process_vm_readv 310
968# elif defined(POWERPC)
969# define __NR_process_vm_readv 351
970# endif
971#endif
972
973#if defined(__NR_process_vm_readv)
974static bool process_vm_readv_not_supported = 0;
Mike Frysinger24ee60b2012-05-04 19:37:29 -0400975/* Have to avoid duplicating with the C library headers. */
976static ssize_t strace_process_vm_readv(pid_t pid,
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100977 const struct iovec *lvec,
978 unsigned long liovcnt,
979 const struct iovec *rvec,
980 unsigned long riovcnt,
981 unsigned long flags)
982{
983 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
984}
Mike Frysinger24ee60b2012-05-04 19:37:29 -0400985#define process_vm_readv strace_process_vm_readv
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100986#else
987static bool process_vm_readv_not_supported = 1;
988# define process_vm_readv(...) (errno = ENOSYS, -1)
989#endif
Mike Frysinger612659e2012-02-14 14:38:28 +0100990
991#endif /* end of hack */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100992
Dmitry V. Levinea1fea62015-03-31 19:45:08 +0000993static ssize_t
994vm_read_mem(pid_t pid, void *laddr, long raddr, size_t len)
995{
996 const struct iovec local = {
997 .iov_base = laddr,
998 .iov_len = len
999 };
1000 const struct iovec remote = {
1001 .iov_base = (void *) raddr,
1002 .iov_len = len
1003 };
1004
1005 return process_vm_readv(pid, &local, 1, &remote, 1, 0);
1006}
1007
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001008/*
1009 * move `len' bytes of data from process `pid'
Denys Vlasenko7e69ed92015-03-21 19:50:53 +01001010 * at address `addr' to our space at `our_addr'
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001011 */
1012int
Denys Vlasenko7e69ed92015-03-21 19:50:53 +01001013umoven(struct tcb *tcp, long addr, unsigned int len, void *our_addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001014{
Denys Vlasenko7e69ed92015-03-21 19:50:53 +01001015 char *laddr = our_addr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001016 int pid = tcp->pid;
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001017 unsigned int n, m, nread;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001018 union {
1019 long val;
1020 char x[sizeof(long)];
1021 } u;
1022
Denys Vlasenko2544f982013-02-19 17:39:56 +01001023#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
Denys Vlasenko9fd4f962012-03-19 09:36:42 +01001024 if (current_wordsize < sizeof(addr))
1025 addr &= (1ul << 8 * current_wordsize) - 1;
Denys Vlasenkod2a660f2012-02-25 00:43:22 +01001026#endif
1027
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001028 if (!process_vm_readv_not_supported) {
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001029 int r = vm_read_mem(pid, laddr, addr, len);
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001030 if ((unsigned int) r == len)
Ben Noordhuis1d58fe92013-02-26 12:24:25 +01001031 return 0;
Dmitry V. Levin97005922013-02-26 21:16:22 +00001032 if (r >= 0) {
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001033 error_msg("umoven: short read (%u < %u) @0x%lx",
1034 (unsigned int) r, len, addr);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001035 return -1;
1036 }
1037 switch (errno) {
1038 case ENOSYS:
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001039 process_vm_readv_not_supported = 1;
Dmitry V. Levin97005922013-02-26 21:16:22 +00001040 break;
Dmitry V. Levinb2893c92015-03-30 15:21:55 +00001041 case EPERM:
1042 /* operation not permitted, try PTRACE_PEEKDATA */
1043 break;
Dmitry V. Levin97005922013-02-26 21:16:22 +00001044 case ESRCH:
1045 /* the process is gone */
1046 return -1;
Dmitry V. Levinb2893c92015-03-30 15:21:55 +00001047 case EFAULT: case EIO:
Dmitry V. Levin97005922013-02-26 21:16:22 +00001048 /* address space is inaccessible */
1049 return -1;
1050 default:
1051 /* all the rest is strange and should be reported */
Denys Vlasenko905e8e02013-02-26 12:30:09 +01001052 perror_msg("process_vm_readv");
Dmitry V. Levin97005922013-02-26 21:16:22 +00001053 return -1;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001054 }
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001055 }
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001056
Dmitry V. Levin97005922013-02-26 21:16:22 +00001057 nread = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001058 if (addr & (sizeof(long) - 1)) {
1059 /* addr not a multiple of sizeof(long) */
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001060 n = addr & (sizeof(long) - 1); /* residue */
1061 addr &= -sizeof(long); /* aligned address */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001062 errno = 0;
1063 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001064 switch (errno) {
1065 case 0:
1066 break;
1067 case ESRCH: case EINVAL:
1068 /* these could be seen if the process is gone */
1069 return -1;
1070 case EFAULT: case EIO: case EPERM:
1071 /* address space is inaccessible */
1072 return -1;
1073 default:
1074 /* all the rest is strange and should be reported */
1075 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx",
1076 pid, addr);
1077 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001078 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001079 m = MIN(sizeof(long) - n, len);
1080 memcpy(laddr, &u.x[n], m);
Denys Vlasenko16940922013-03-01 18:52:59 +01001081 addr += sizeof(long);
1082 laddr += m;
1083 nread += m;
1084 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085 }
1086 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001087 errno = 0;
1088 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001089 switch (errno) {
1090 case 0:
1091 break;
1092 case ESRCH: case EINVAL:
1093 /* these could be seen if the process is gone */
1094 return -1;
1095 case EFAULT: case EIO: case EPERM:
1096 /* address space is inaccessible */
1097 if (nread) {
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001098 perror_msg("umoven: short read (%u < %u) @0x%lx",
Dmitry V. Levin97005922013-02-26 21:16:22 +00001099 nread, nread + len, addr - nread);
1100 }
1101 return -1;
1102 default:
1103 /* all the rest is strange and should be reported */
1104 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx",
1105 pid, addr);
1106 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001107 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001108 m = MIN(sizeof(long), len);
1109 memcpy(laddr, u.x, m);
Denys Vlasenko16940922013-03-01 18:52:59 +01001110 addr += sizeof(long);
1111 laddr += m;
1112 nread += m;
1113 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001114 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001115
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001116 return 0;
1117}
1118
Dmitry V. Levin332a3262015-07-05 22:09:29 +00001119int
1120umoven_or_printaddr(struct tcb *tcp, const long addr, const unsigned int len,
1121 void *our_addr)
1122{
1123 if (!addr) {
1124 tprints("NULL");
1125 return -1;
1126 }
Dmitry V. Levin61b79892015-07-14 22:03:55 +00001127 if (!verbose(tcp) || (exiting(tcp) && syserror(tcp)) ||
Dmitry V. Levin332a3262015-07-05 22:09:29 +00001128 umoven(tcp, addr, len, our_addr) < 0) {
1129 tprintf("%#lx", addr);
1130 return -1;
1131 }
1132 return 0;
1133}
1134
Dmitry V. Levin13c21732015-08-26 12:49:07 +00001135int
1136umove_long_or_printaddr(struct tcb *tcp, const long addr, long *ptr)
1137{
1138 if (current_wordsize < sizeof(*ptr)) {
1139 uint32_t val32;
1140 int r = umove_or_printaddr(tcp, addr, &val32);
1141 if (!r)
1142 *ptr = (unsigned long) val32;
1143 return r;
1144 }
1145 return umove_or_printaddr(tcp, addr, ptr);
1146}
1147
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001148/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001149 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001150 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001151 *
1152 * Returns < 0 on error, > 0 if NUL was seen,
1153 * (TODO if useful: return count of bytes including NUL),
1154 * else 0 if len bytes were read but no NUL byte seen.
1155 *
1156 * Note: there is no guarantee we won't overwrite some bytes
1157 * in laddr[] _after_ terminating NUL (but, of course,
1158 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159 */
1160int
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001161umovestr(struct tcb *tcp, long addr, unsigned int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001162{
Denys Vlasenko16940922013-03-01 18:52:59 +01001163#if SIZEOF_LONG == 4
1164 const unsigned long x01010101 = 0x01010101ul;
1165 const unsigned long x80808080 = 0x80808080ul;
1166#elif SIZEOF_LONG == 8
1167 const unsigned long x01010101 = 0x0101010101010101ul;
1168 const unsigned long x80808080 = 0x8080808080808080ul;
1169#else
1170# error SIZEOF_LONG > 8
1171#endif
1172
Roland McGratheb9e2e82009-06-02 16:49:22 -07001173 int pid = tcp->pid;
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001174 unsigned int n, m, nread;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001175 union {
Denys Vlasenko16940922013-03-01 18:52:59 +01001176 unsigned long val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001177 char x[sizeof(long)];
1178 } u;
1179
Denys Vlasenko2544f982013-02-19 17:39:56 +01001180#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
Denys Vlasenko9fd4f962012-03-19 09:36:42 +01001181 if (current_wordsize < sizeof(addr))
1182 addr &= (1ul << 8 * current_wordsize) - 1;
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +00001183#endif
1184
Dmitry V. Levin97005922013-02-26 21:16:22 +00001185 nread = 0;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001186 if (!process_vm_readv_not_supported) {
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001187 const size_t page_size = get_pagesize();
1188 const size_t page_mask = page_size - 1;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001189
1190 while (len > 0) {
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001191 unsigned int chunk_len;
1192 unsigned int end_in_page;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001193
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001194 /*
1195 * Don't cross pages, otherwise we can get EFAULT
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001196 * and fail to notice that terminating NUL lies
1197 * in the existing (first) page.
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001198 */
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001199 chunk_len = len > page_size ? page_size : len;
1200 end_in_page = (addr + chunk_len) & page_mask;
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001201 if (chunk_len > end_in_page) /* crosses to the next page */
1202 chunk_len -= end_in_page;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001203
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001204 int r = vm_read_mem(pid, laddr, addr, chunk_len);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001205 if (r > 0) {
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001206 if (memchr(laddr, '\0', r))
Dmitry V. Levin97005922013-02-26 21:16:22 +00001207 return 1;
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001208 addr += r;
1209 laddr += r;
Dmitry V. Levin97005922013-02-26 21:16:22 +00001210 nread += r;
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001211 len -= r;
Dmitry V. Levin97005922013-02-26 21:16:22 +00001212 continue;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001213 }
Dmitry V. Levin97005922013-02-26 21:16:22 +00001214 switch (errno) {
1215 case ENOSYS:
1216 process_vm_readv_not_supported = 1;
1217 goto vm_readv_didnt_work;
1218 case ESRCH:
1219 /* the process is gone */
1220 return -1;
Dmitry V. Levinb2893c92015-03-30 15:21:55 +00001221 case EPERM:
1222 /* operation not permitted, try PTRACE_PEEKDATA */
1223 if (!nread)
1224 goto vm_readv_didnt_work;
1225 /* fall through */
1226 case EFAULT: case EIO:
Dmitry V. Levin97005922013-02-26 21:16:22 +00001227 /* address space is inaccessible */
1228 if (nread) {
1229 perror_msg("umovestr: short read (%d < %d) @0x%lx",
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001230 nread, nread + len, addr - nread);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001231 }
1232 return -1;
1233 default:
1234 /* all the rest is strange and should be reported */
1235 perror_msg("process_vm_readv");
1236 return -1;
1237 }
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001238 }
1239 return 0;
1240 }
1241 vm_readv_didnt_work:
1242
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001243 if (addr & (sizeof(long) - 1)) {
1244 /* addr not a multiple of sizeof(long) */
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001245 n = addr & (sizeof(long) - 1); /* residue */
1246 addr &= -sizeof(long); /* aligned address */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001247 errno = 0;
1248 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001249 switch (errno) {
1250 case 0:
1251 break;
1252 case ESRCH: case EINVAL:
1253 /* these could be seen if the process is gone */
1254 return -1;
1255 case EFAULT: case EIO: case EPERM:
1256 /* address space is inaccessible */
1257 return -1;
1258 default:
1259 /* all the rest is strange and should be reported */
1260 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx",
1261 pid, addr);
1262 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001263 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001264 m = MIN(sizeof(long) - n, len);
1265 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001266 while (n & (sizeof(long) - 1))
1267 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001268 return 1;
Denys Vlasenko16940922013-03-01 18:52:59 +01001269 addr += sizeof(long);
1270 laddr += m;
1271 nread += m;
1272 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001273 }
Denys Vlasenko16940922013-03-01 18:52:59 +01001274
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001275 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001276 errno = 0;
1277 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001278 switch (errno) {
1279 case 0:
1280 break;
1281 case ESRCH: case EINVAL:
1282 /* these could be seen if the process is gone */
1283 return -1;
1284 case EFAULT: case EIO: case EPERM:
1285 /* address space is inaccessible */
1286 if (nread) {
1287 perror_msg("umovestr: short read (%d < %d) @0x%lx",
1288 nread, nread + len, addr - nread);
1289 }
1290 return -1;
1291 default:
1292 /* all the rest is strange and should be reported */
1293 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx",
1294 pid, addr);
1295 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001296 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001297 m = MIN(sizeof(long), len);
1298 memcpy(laddr, u.x, m);
Denys Vlasenko16940922013-03-01 18:52:59 +01001299 /* "If a NUL char exists in this word" */
1300 if ((u.val - x01010101) & ~u.val & x80808080)
1301 return 1;
1302 addr += sizeof(long);
1303 laddr += m;
1304 nread += m;
1305 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001306 }
John Hughesaa09c6b2001-05-15 14:53:43 +00001307 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001308}
1309
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001310int
Denys Vlasenko752e5a02013-06-28 14:35:47 +02001311upeek(int pid, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001312{
1313 long val;
1314
Roland McGratheb9e2e82009-06-02 16:49:22 -07001315 errno = 0;
Denys Vlasenko752e5a02013-06-28 14:35:47 +02001316 val = ptrace(PTRACE_PEEKUSER, (pid_t)pid, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001317 if (val == -1 && errno) {
1318 if (errno != ESRCH) {
Denys Vlasenko752e5a02013-06-28 14:35:47 +02001319 perror_msg("upeek: PTRACE_PEEKUSER pid:%d @0x%lx)", pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001320 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001321 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001322 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001323 *res = val;
1324 return 0;
1325}