blob: 09ce6d0bc35349c7176a0981343bb6ceeec13aa5 [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. Levined92d872016-04-28 18:32:45 +0000124xlookup64(const struct xlat *xlat, const uint64_t 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{
Dmitry V. Levin43242e62016-04-28 18:37:54 +0000135 const uint64_t val1 = *(const uint64_t *) a;
136 const uint64_t val2 = ((const struct xlat *) b)->val;
Dmitry V. Levin4176d532014-09-21 22:42:45 +0000137 return (val1 > val2) ? 1 : (val1 < val2) ? -1 : 0;
138}
139
140const char *
Dmitry V. Levin43242e62016-04-28 18:37:54 +0000141xlat_search(const struct xlat *xlat, const size_t nmemb, const uint64_t val)
Dmitry V. Levin4176d532014-09-21 22:42:45 +0000142{
143 const struct xlat *e =
Dmitry V. Levin43242e62016-04-28 18:37:54 +0000144 bsearch((const void*) &val,
Dmitry V. Levin4176d532014-09-21 22:42:45 +0000145 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
Dmitry V. Levin6974c912015-11-26 18:25:34 +0000240# ifdef X86_64
241 if (current_personality != 1) {
242# else
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000243 if (current_wordsize > 4) {
Dmitry V. Levin6974c912015-11-26 18:25:34 +0000244# endif
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000245# endif
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000246 *val = tcp->u_arg[arg_no];
Chris Metcalf879dddd2013-03-01 10:41:02 +0100247 arg_no++;
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000248# if SUPPORTED_PERSONALITIES > 1
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100249 } else {
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000250# if defined(AARCH64) || defined(POWERPC64)
Dmitry V. Levin3c49b022014-08-07 00:07:28 +0000251 /* Align arg_no to the next even number. */
252 arg_no = (arg_no + 1) & 0xe;
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000253# endif /* AARCH64 || POWERPC64 */
254 *val = LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]);
Chris Metcalf879dddd2013-03-01 10:41:02 +0100255 arg_no += 2;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100256 }
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000257# endif /* SUPPORTED_PERSONALITIES > 1 */
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000258#elif SIZEOF_LONG > 4
259# error Unsupported configuration: SIZEOF_LONG > 4 && SIZEOF_LONG_LONG > SIZEOF_LONG
260#elif defined LINUX_MIPSN32
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000261 *val = tcp->ext_arg[arg_no];
Chris Metcalf879dddd2013-03-01 10:41:02 +0100262 arg_no++;
Dmitry V. Levin0b468832013-05-02 08:41:27 +0000263#elif defined X32
264 if (current_personality == 0) {
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000265 *val = tcp->ext_arg[arg_no];
Dmitry V. Levin0b468832013-05-02 08:41:27 +0000266 arg_no++;
267 } else {
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000268 *val = LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]);
Dmitry V. Levin0b468832013-05-02 08:41:27 +0000269 arg_no += 2;
270 }
Denys Vlasenkoc9d0fc02013-02-17 22:41:33 +0100271#else
Dmitry V. Levin8e096c42013-05-06 18:23:01 +0000272# if defined __ARM_EABI__ || \
273 defined LINUX_MIPSO32 || \
274 defined POWERPC || \
275 defined XTENSA
Dmitry V. Levin3c49b022014-08-07 00:07:28 +0000276 /* Align arg_no to the next even number. */
277 arg_no = (arg_no + 1) & 0xe;
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000278# endif
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000279 *val = LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]);
Chris Metcalf879dddd2013-03-01 10:41:02 +0100280 arg_no += 2;
Denys Vlasenkoc9d0fc02013-02-17 22:41:33 +0100281#endif
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000282
Chris Metcalf879dddd2013-03-01 10:41:02 +0100283 return arg_no;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100284}
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100285
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000286/*
Dmitry V. Levin1ea64732015-01-10 00:08:58 +0000287 * Print 64bit argument at position arg_no and
288 * return the index of the next argument.
289 */
290int
291printllval(struct tcb *tcp, const char *format, int arg_no)
292{
293 unsigned long long val = 0;
294
295 arg_no = getllval(tcp, &val, arg_no);
296 tprintf(format, val);
297 return arg_no;
298}
299
300/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000301 * Interpret `xlat' as an array of flags
302 * print the entries whose bits are on in `flags'
303 * return # of flags printed.
304 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200305void
Dmitry V. Levinc9146eb2016-04-28 18:19:27 +0000306addflags(const struct xlat *xlat, uint64_t flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000307{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200308 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000309 if (xlat->val && (flags & xlat->val) == xlat->val) {
310 tprintf("|%s", xlat->str);
311 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000312 }
313 }
314 if (flags) {
Dmitry V. Levinc9146eb2016-04-28 18:19:27 +0000315 tprintf("|%#" PRIx64, flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000316 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000317}
318
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000319/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200320 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000321 * Print to static string the entries whose bits are on in `flags'
322 * Return static string.
323 */
324const char *
325sprintflags(const char *prefix, const struct xlat *xlat, int flags)
326{
327 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200328 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000329 int found = 0;
330
Denys Vlasenko52845572011-08-31 12:07:38 +0200331 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000332
Dmitry V. Levin71af1152015-11-15 20:44:13 +0000333 if (flags == 0 && xlat->val == 0 && xlat->str) {
334 strcpy(outptr, xlat->str);
335 return outstr;
336 }
337
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000338 for (; xlat->str; xlat++) {
Dmitry V. Levin71af1152015-11-15 20:44:13 +0000339 if (xlat->val && (flags & xlat->val) == xlat->val) {
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000340 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200341 *outptr++ = '|';
342 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000343 found = 1;
Denys Vlasenko4f3df072012-01-29 22:38:35 +0100344 flags &= ~xlat->val;
345 if (!flags)
346 break;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000347 }
348 }
349 if (flags) {
350 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200351 *outptr++ = '|';
352 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000353 }
354
355 return outstr;
356}
357
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000358int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000359printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000360{
361 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000362 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000363
Mike Frysinger79bddff2015-10-31 00:47:59 -0400364 if (flags == 0 && xlat->val == 0 && xlat->str) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200365 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000366 return 1;
367 }
368
369 sep = "";
370 for (n = 0; xlat->str; xlat++) {
371 if (xlat->val && (flags & xlat->val) == xlat->val) {
372 tprintf("%s%s", sep, xlat->str);
373 flags &= ~xlat->val;
374 sep = "|";
375 n++;
376 }
377 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000378
379 if (n) {
380 if (flags) {
381 tprintf("%s%#x", sep, flags);
382 n++;
383 }
384 } else {
385 if (flags) {
386 tprintf("%#x", flags);
387 if (dflt)
388 tprintf(" /* %s */", dflt);
389 } else {
390 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200391 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000392 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000393 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000394
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000395 return n;
396}
397
398void
Dmitry V. Levin332a3262015-07-05 22:09:29 +0000399printaddr(const long addr)
400{
401 if (!addr)
402 tprints("NULL");
403 else
404 tprintf("%#lx", addr);
405}
406
Dmitry V. Levinc88163e2015-07-05 22:09:29 +0000407#define DEF_PRINTNUM(name, type) \
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000408bool \
Dmitry V. Levinc88163e2015-07-05 22:09:29 +0000409printnum_ ## name(struct tcb *tcp, const long addr, const char *fmt) \
410{ \
411 type num; \
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000412 if (umove_or_printaddr(tcp, addr, &num)) \
413 return false; \
414 tprints("["); \
415 tprintf(fmt, num); \
416 tprints("]"); \
417 return true; \
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000418}
419
Dmitry V. Levin69127a32015-07-05 22:09:29 +0000420#define DEF_PRINTPAIR(name, type) \
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000421bool \
Dmitry V. Levin69127a32015-07-05 22:09:29 +0000422printpair_ ## name(struct tcb *tcp, const long addr, const char *fmt) \
423{ \
424 type pair[2]; \
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000425 if (umove_or_printaddr(tcp, addr, &pair)) \
426 return false; \
427 tprints("["); \
428 tprintf(fmt, pair[0]); \
429 tprints(", "); \
430 tprintf(fmt, pair[1]); \
431 tprints("]"); \
432 return true; \
Dmitry V. Levin69127a32015-07-05 22:09:29 +0000433}
434
Dmitry V. Levinc88163e2015-07-05 22:09:29 +0000435DEF_PRINTNUM(int, int)
Dmitry V. Levin69127a32015-07-05 22:09:29 +0000436DEF_PRINTPAIR(int, int)
Dmitry V. Levinc88163e2015-07-05 22:09:29 +0000437DEF_PRINTNUM(short, short)
Dmitry V. Levinc88163e2015-07-05 22:09:29 +0000438DEF_PRINTNUM(int64, uint64_t)
Dmitry V. Levin69127a32015-07-05 22:09:29 +0000439DEF_PRINTPAIR(int64, uint64_t)
Dmitry V. Levin2479ef02015-08-18 14:58:27 +0000440
441#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000442bool
Dmitry V. Levin2479ef02015-08-18 14:58:27 +0000443printnum_long_int(struct tcb *tcp, const long addr,
444 const char *fmt_long, const char *fmt_int)
445{
446 if (current_wordsize > sizeof(int)) {
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000447 return printnum_int64(tcp, addr, fmt_long);
Dmitry V. Levin2479ef02015-08-18 14:58:27 +0000448 } else {
Dmitry V. Levind77f6692015-08-18 21:57:27 +0000449 return printnum_int(tcp, addr, fmt_int);
Dmitry V. Levin2479ef02015-08-18 14:58:27 +0000450 }
451}
Dmitry V. Levinc88163e2015-07-05 22:09:29 +0000452#endif
Roland McGrath9814a942005-07-04 23:28:10 +0000453
Dmitry V. Levinb1a01b82014-12-06 03:53:16 +0000454const char *
455sprinttime(time_t t)
456{
457 struct tm *tmp;
Dmitry V. Levind4a9d832015-01-08 15:08:16 +0000458 static char buf[sizeof(int) * 3 * 6];
Dmitry V. Levinb1a01b82014-12-06 03:53:16 +0000459
460 if (t == 0) {
461 strcpy(buf, "0");
462 return buf;
463 }
464 tmp = localtime(&t);
465 if (tmp)
466 snprintf(buf, sizeof buf, "%02d/%02d/%02d-%02d:%02d:%02d",
467 tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
468 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
469 else
470 snprintf(buf, sizeof buf, "%lu", (unsigned long) t);
471
472 return buf;
473}
474
Masatake YAMATOf5480672014-11-22 19:03:33 +0900475static char *
476getfdproto(struct tcb *tcp, int fd, char *buf, unsigned bufsize)
477{
Dmitry V. Levind93c4e82015-06-17 20:09:13 +0000478#ifdef HAVE_SYS_XATTR_H
Masatake YAMATOf5480672014-11-22 19:03:33 +0900479 ssize_t r;
480 char path[sizeof("/proc/%u/fd/%u") + 2 * sizeof(int)*3];
481
482 if (fd < 0)
483 return NULL;
484
485 sprintf(path, "/proc/%u/fd/%u", tcp->pid, fd);
486 r = getxattr(path, "system.sockprotoname", buf, bufsize - 1);
487 if (r <= 0)
488 return NULL;
489 else {
490 /*
491 * This is a protection for the case when the kernel
492 * side does not append a null byte to the buffer.
493 */
494 buf[r] = '\0';
495 return buf;
496 }
497#else
498 return NULL;
499#endif
500}
501
Roland McGrath9814a942005-07-04 23:28:10 +0000502void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300503printfd(struct tcb *tcp, int fd)
504{
Denys Vlasenko61ad0a42013-03-06 18:24:34 +0100505 char path[PATH_MAX + 1];
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000506 if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) {
507 static const char socket_prefix[] = "socket:[";
508 const size_t socket_prefix_len = sizeof(socket_prefix) - 1;
Dmitry V. Levinc7235992015-01-24 19:51:39 +0000509 const size_t path_len = strlen(path);
Grant Edwards8a082772011-04-07 20:25:40 +0000510
Dmitry V. Levinc7235992015-01-24 19:51:39 +0000511 tprintf("%d<", fd);
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000512 if (show_fd_path > 1 &&
513 strncmp(path, socket_prefix, socket_prefix_len) == 0 &&
Dmitry V. Levinc7235992015-01-24 19:51:39 +0000514 path[path_len - 1] == ']') {
Dmitry V. Levin3c17d1b2016-02-01 23:14:59 +0000515 unsigned long inode =
Dmitry V. Levinea8b8e32016-01-23 16:35:02 +0000516 strtoul(path + socket_prefix_len, NULL, 10);
Dmitry V. Levin3c17d1b2016-02-01 23:14:59 +0000517
518 if (!print_sockaddr_by_inode_cached(inode)) {
519 char buf[256];
520 const char *proto =
521 getfdproto(tcp, fd, buf, sizeof(buf));
522 if (!print_sockaddr_by_inode(inode, proto))
523 tprints(path);
524 }
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000525 } else {
Dmitry V. Levinc7235992015-01-24 19:51:39 +0000526 print_quoted_string(path, path_len,
527 QUOTE_OMIT_LEADING_TRAILING_QUOTES);
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000528 }
Dmitry V. Levinc7235992015-01-24 19:51:39 +0000529 tprints(">");
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000530 } else
Grant Edwards8a082772011-04-07 20:25:40 +0000531 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300532}
533
Dmitry V. Levina501f142008-11-10 23:19:13 +0000534/*
535 * Quote string `instr' of length `size'
536 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100537 *
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000538 * If QUOTE_0_TERMINATED `style' flag is set,
539 * treat `instr' as a NUL-terminated string,
540 * checking up to (`size' + 1) bytes of `instr'.
541 *
542 * If QUOTE_OMIT_LEADING_TRAILING_QUOTES `style' flag is set,
543 * do not add leading and trailing quoting symbols.
544 *
545 * Returns 0 if QUOTE_0_TERMINATED is set and NUL was seen, 1 otherwise.
546 * Note that if QUOTE_0_TERMINATED is not set, always returns 1.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000547 */
Dmitry V. Levin3c17d1b2016-02-01 23:14:59 +0000548int
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000549string_quote(const char *instr, char *outstr, const unsigned int size,
550 const unsigned int style)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000551{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000552 const unsigned char *ustr = (const unsigned char *) instr;
553 char *s = outstr;
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000554 unsigned int i;
555 int usehex, c, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000556
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000557 if (style & QUOTE_0_TERMINATED)
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200558 eol = '\0';
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000559 else
560 eol = 0x100; /* this can never match a char */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200561
562 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000563 if (xflag > 1)
564 usehex = 1;
565 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000566 /* Check for presence of symbol which require
567 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000568 for (i = 0; i < size; ++i) {
569 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000570 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200571 if (c == eol)
572 break;
Denys Vlasenko5198ed42013-03-06 23:44:23 +0100573
574 /* Force hex unless c is printable or whitespace */
575 if (c > 0x7e) {
576 usehex = 1;
577 break;
578 }
579 /* In ASCII isspace is only these chars: "\t\n\v\f\r".
580 * They happen to have ASCII codes 9,10,11,12,13.
581 */
582 if (c < ' ' && (unsigned)(c - 9) >= 5) {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000583 usehex = 1;
584 break;
585 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000586 }
587 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000588
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000589 if (!(style & QUOTE_OMIT_LEADING_TRAILING_QUOTES))
590 *s++ = '\"';
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000591
592 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000593 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000594 for (i = 0; i < size; ++i) {
595 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000596 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200597 if (c == eol)
598 goto asciz_ended;
599 *s++ = '\\';
600 *s++ = 'x';
601 *s++ = "0123456789abcdef"[c >> 4];
602 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000603 }
604 } else {
605 for (i = 0; i < size; ++i) {
606 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000607 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200608 if (c == eol)
609 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000610 switch (c) {
611 case '\"': case '\\':
612 *s++ = '\\';
613 *s++ = c;
614 break;
615 case '\f':
616 *s++ = '\\';
617 *s++ = 'f';
618 break;
619 case '\n':
620 *s++ = '\\';
621 *s++ = 'n';
622 break;
623 case '\r':
624 *s++ = '\\';
625 *s++ = 'r';
626 break;
627 case '\t':
628 *s++ = '\\';
629 *s++ = 't';
630 break;
631 case '\v':
632 *s++ = '\\';
633 *s++ = 'v';
634 break;
635 default:
Denys Vlasenko5198ed42013-03-06 23:44:23 +0100636 if (c >= ' ' && c <= 0x7e)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000637 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200638 else {
639 /* Print \octal */
640 *s++ = '\\';
641 if (i + 1 < size
642 && ustr[i + 1] >= '0'
643 && ustr[i + 1] <= '9'
644 ) {
645 /* Print \ooo */
646 *s++ = '0' + (c >> 6);
647 *s++ = '0' + ((c >> 3) & 0x7);
648 } else {
649 /* Print \[[o]o]o */
650 if ((c >> 3) != 0) {
651 if ((c >> 6) != 0)
652 *s++ = '0' + (c >> 6);
653 *s++ = '0' + ((c >> 3) & 0x7);
654 }
655 }
656 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000657 }
658 break;
659 }
660 }
661 }
662
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000663 if (!(style & QUOTE_OMIT_LEADING_TRAILING_QUOTES))
664 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000665 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000666
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200667 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000668 if (style & QUOTE_0_TERMINATED && ustr[i] == '\0') {
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200669 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
670 * but next char is NUL.
671 */
672 return 0;
673 }
674
675 return 1;
676
677 asciz_ended:
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000678 if (!(style & QUOTE_OMIT_LEADING_TRAILING_QUOTES))
679 *s++ = '\"';
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200680 *s = '\0';
681 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
682 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000683}
684
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000685#ifndef ALLOCA_CUTOFF
686# define ALLOCA_CUTOFF 4032
687#endif
688#define use_alloca(n) ((n) <= ALLOCA_CUTOFF)
689
690/*
691 * Quote string `str' of length `size' and print the result.
692 *
693 * If QUOTE_0_TERMINATED `style' flag is set,
694 * treat `str' as a NUL-terminated string and
695 * quote at most (`size' - 1) bytes.
696 *
697 * If QUOTE_OMIT_LEADING_TRAILING_QUOTES `style' flag is set,
698 * do not add leading and trailing quoting symbols.
699 *
700 * Returns 0 if QUOTE_0_TERMINATED is set and NUL was seen, 1 otherwise.
701 * Note that if QUOTE_0_TERMINATED is not set, always returns 1.
702 */
703int
704print_quoted_string(const char *str, unsigned int size,
705 const unsigned int style)
706{
707 char *buf;
708 char *outstr;
709 unsigned int alloc_size;
710 int rc;
711
712 if (size && style & QUOTE_0_TERMINATED)
713 --size;
714
715 alloc_size = 4 * size;
716 if (alloc_size / 4 != size) {
717 error_msg("Out of memory");
718 tprints("???");
719 return -1;
720 }
721 alloc_size += 1 + (style & QUOTE_OMIT_LEADING_TRAILING_QUOTES ? 0 : 2);
722
723 if (use_alloca(alloc_size)) {
724 outstr = alloca(alloc_size);
725 buf = NULL;
726 } else {
727 outstr = buf = malloc(alloc_size);
728 if (!buf) {
729 error_msg("Out of memory");
730 tprints("???");
731 return -1;
732 }
733 }
734
735 rc = string_quote(str, outstr, size, style);
736 tprints(outstr);
737
738 free(buf);
739 return rc;
740}
741
Dmitry V. Levina501f142008-11-10 23:19:13 +0000742/*
743 * Print path string specified by address `addr' and length `n'.
744 * If path length exceeds `n', append `...' to the output.
745 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000746void
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000747printpathn(struct tcb *tcp, long addr, unsigned int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000748{
Dmitry V. Levin025b3582014-11-21 22:28:34 +0000749 char path[PATH_MAX + 1];
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100750 int nul_seen;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100751
Dmitry V. Levina501f142008-11-10 23:19:13 +0000752 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200753 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000754 return;
755 }
756
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100757 /* Cap path length to the path buffer size */
Dmitry V. Levina501f142008-11-10 23:19:13 +0000758 if (n > sizeof path - 1)
759 n = sizeof path - 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000760
761 /* Fetch one byte more to find out whether path length > n. */
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100762 nul_seen = umovestr(tcp, addr, n + 1, path);
763 if (nul_seen < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000764 tprintf("%#lx", addr);
765 else {
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000766 path[n++] = '\0';
767 print_quoted_string(path, n, QUOTE_0_TERMINATED);
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100768 if (!nul_seen)
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100769 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000770 }
771}
772
773void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000774printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100776 /* Size must correspond to char path[] size in printpathn */
Dmitry V. Levin025b3582014-11-21 22:28:34 +0000777 printpathn(tcp, addr, PATH_MAX);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000778}
779
Dmitry V. Levina501f142008-11-10 23:19:13 +0000780/*
781 * Print string specified by address `addr' and length `len'.
782 * If `len' < 0, treat the string as a NUL-terminated string.
783 * If string length exceeds `max_strlen', append `...' to the output.
784 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000785void
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200786printstr(struct tcb *tcp, long addr, long len)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000787{
788 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789 static char *outstr;
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000790 unsigned int size;
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000791 unsigned int style;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100792 int ellipsis;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000793
794 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200795 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000796 return;
797 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000798 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200799 if (!str) {
Dmitry V. Levin378f9c52012-03-25 22:56:53 +0000800 unsigned int outstr_size = 4 * max_strlen + /*for quotes and NUL:*/ 3;
801
802 if (outstr_size / 4 != max_strlen)
803 die_out_of_memory();
Dmitry V. Levin3e9d71f2015-05-25 20:41:02 +0000804 str = xmalloc(max_strlen + 1);
805 outstr = xmalloc(outstr_size);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000806 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000807
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000808 size = max_strlen;
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200809 if (len == -1) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000810 /*
811 * Treat as a NUL-terminated string: fetch one byte more
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000812 * because string_quote may look one byte ahead.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000813 */
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000814 if (umovestr(tcp, addr, size + 1, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000815 tprintf("%#lx", addr);
816 return;
817 }
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000818 style = QUOTE_0_TERMINATED;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000819 }
820 else {
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200821 if (size > (unsigned long)len)
822 size = (unsigned long)len;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000823 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000824 tprintf("%#lx", addr);
825 return;
826 }
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000827 style = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000828 }
829
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100830 /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
831 * or we were requested to print more than -s NUM chars)...
832 */
Dmitry V. Levin513e96e2015-01-26 01:17:08 +0000833 ellipsis = (string_quote(str, outstr, size, style) &&
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000834 (len < 0 || (unsigned long) len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000835
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100836 tprints(outstr);
837 if (ellipsis)
838 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000839}
840
John Hughes1d08dcf2001-07-10 13:48:44 +0000841void
Dmitry V. Levin05a0af62016-01-20 00:17:02 +0000842dumpiov_upto(struct tcb *tcp, int len, long addr, unsigned long data_size)
John Hughes1d08dcf2001-07-10 13:48:44 +0000843{
Denys Vlasenko84703742012-02-25 02:38:52 +0100844#if SUPPORTED_PERSONALITIES > 1
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000845 union {
Dmitry V. Levin08941942016-01-16 22:50:09 +0000846 struct { uint32_t base; uint32_t len; } *iov32;
847 struct { uint64_t base; uint64_t len; } *iov64;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000848 } iovu;
849#define iov iovu.iov64
850#define sizeof_iov \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100851 (current_wordsize == 4 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000852#define iov_iov_base(i) \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100853 (current_wordsize == 4 ? (uint64_t) iovu.iov32[i].base : iovu.iov64[i].base)
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000854#define iov_iov_len(i) \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100855 (current_wordsize == 4 ? (uint64_t) iovu.iov32[i].len : iovu.iov64[i].len)
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000856#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000857 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000858#define sizeof_iov sizeof(*iov)
859#define iov_iov_base(i) iov[i].iov_base
860#define iov_iov_len(i) iov[i].iov_len
861#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000862 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200863 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000864
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200865 size = sizeof_iov * len;
866 /* Assuming no sane program has millions of iovs */
867 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000868 || (iov = malloc(size)) == NULL) {
Dmitry V. Levindf389912015-05-25 23:33:31 +0300869 error_msg("Out of memory");
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200870 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000871 }
Denys Vlasenko7e69ed92015-03-21 19:50:53 +0100872 if (umoven(tcp, addr, size, iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000873 for (i = 0; i < len; i++) {
Dmitry V. Levin05a0af62016-01-20 00:17:02 +0000874 unsigned long iov_len = iov_iov_len(i);
875 if (iov_len > data_size)
876 iov_len = data_size;
877 if (!iov_len)
878 break;
879 data_size -= iov_len;
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000880 /* include the buffer number to make it easy to
881 * match up the trace with the source */
Dmitry V. Levin05a0af62016-01-20 00:17:02 +0000882 tprintf(" * %lu bytes in buffer %d\n", iov_len, i);
883 dumpstr(tcp, (long) iov_iov_base(i), iov_len);
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000884 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000885 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200886 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000887#undef sizeof_iov
888#undef iov_iov_base
889#undef iov_iov_len
890#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000891}
John Hughes1d08dcf2001-07-10 13:48:44 +0000892
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000893void
Denys Vlasenko12014262011-05-30 14:00:14 +0200894dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000895{
896 static int strsize = -1;
897 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000898
Denys Vlasenko76325802013-02-22 14:47:39 +0100899 char outbuf[
900 (
901 (sizeof(
902 "xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx "
903 "1234567890123456") + /*in case I'm off by few:*/ 4)
904 /*align to 8 to make memset easier:*/ + 7) & -8
905 ];
906 const unsigned char *src;
907 int i;
908
909 memset(outbuf, ' ', sizeof(outbuf));
910
911 if (strsize < len + 16) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200912 free(str);
Denys Vlasenko76325802013-02-22 14:47:39 +0100913 str = malloc(len + 16);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200914 if (!str) {
915 strsize = -1;
Dmitry V. Levindf389912015-05-25 23:33:31 +0300916 error_msg("Out of memory");
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200917 return;
918 }
Denys Vlasenko76325802013-02-22 14:47:39 +0100919 strsize = len + 16;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000920 }
921
Denys Vlasenko7e69ed92015-03-21 19:50:53 +0100922 if (umoven(tcp, addr, len, str) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000923 return;
924
Denys Vlasenko76325802013-02-22 14:47:39 +0100925 /* Space-pad to 16 bytes */
926 i = len;
927 while (i & 0xf)
928 str[i++] = ' ';
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200929
Denys Vlasenko76325802013-02-22 14:47:39 +0100930 i = 0;
931 src = str;
932 while (i < len) {
933 char *dst = outbuf;
934 /* Hex dump */
935 do {
936 if (i < len) {
937 *dst++ = "0123456789abcdef"[*src >> 4];
938 *dst++ = "0123456789abcdef"[*src & 0xf];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000939 }
940 else {
Denys Vlasenko76325802013-02-22 14:47:39 +0100941 *dst++ = ' ';
942 *dst++ = ' ';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000943 }
Denys Vlasenko76325802013-02-22 14:47:39 +0100944 dst++; /* space is there by memset */
945 i++;
946 if ((i & 7) == 0)
947 dst++; /* space is there by memset */
948 src++;
949 } while (i & 0xf);
950 /* ASCII dump */
951 i -= 16;
952 src -= 16;
953 do {
954 if (*src >= ' ' && *src < 0x7f)
955 *dst++ = *src;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000956 else
Denys Vlasenko76325802013-02-22 14:47:39 +0100957 *dst++ = '.';
958 src++;
959 } while (++i & 0xf);
960 *dst = '\0';
Denys Vlasenkof90979b2013-02-22 15:00:11 +0100961 tprintf(" | %05x %s |\n", i - 16, outbuf);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962 }
963}
964
Mike Frysinger612659e2012-02-14 14:38:28 +0100965#ifdef HAVE_PROCESS_VM_READV
966/* C library supports this, but the kernel might not. */
967static bool process_vm_readv_not_supported = 0;
968#else
969
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100970/* Need to do this since process_vm_readv() is not yet available in libc.
971 * When libc is be updated, only "static bool process_vm_readv_not_supported"
972 * line should remain.
973 */
974#if !defined(__NR_process_vm_readv)
975# if defined(I386)
976# define __NR_process_vm_readv 347
977# elif defined(X86_64)
978# define __NR_process_vm_readv 310
979# elif defined(POWERPC)
980# define __NR_process_vm_readv 351
981# endif
982#endif
983
984#if defined(__NR_process_vm_readv)
985static bool process_vm_readv_not_supported = 0;
Mike Frysinger24ee60b2012-05-04 19:37:29 -0400986/* Have to avoid duplicating with the C library headers. */
987static ssize_t strace_process_vm_readv(pid_t pid,
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100988 const struct iovec *lvec,
989 unsigned long liovcnt,
990 const struct iovec *rvec,
991 unsigned long riovcnt,
992 unsigned long flags)
993{
994 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
995}
Mike Frysinger24ee60b2012-05-04 19:37:29 -0400996#define process_vm_readv strace_process_vm_readv
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100997#else
998static bool process_vm_readv_not_supported = 1;
999# define process_vm_readv(...) (errno = ENOSYS, -1)
1000#endif
Mike Frysinger612659e2012-02-14 14:38:28 +01001001
1002#endif /* end of hack */
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001003
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001004static ssize_t
1005vm_read_mem(pid_t pid, void *laddr, long raddr, size_t len)
1006{
1007 const struct iovec local = {
1008 .iov_base = laddr,
1009 .iov_len = len
1010 };
1011 const struct iovec remote = {
1012 .iov_base = (void *) raddr,
1013 .iov_len = len
1014 };
1015
1016 return process_vm_readv(pid, &local, 1, &remote, 1, 0);
1017}
1018
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001019/*
1020 * move `len' bytes of data from process `pid'
Denys Vlasenko7e69ed92015-03-21 19:50:53 +01001021 * at address `addr' to our space at `our_addr'
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001022 */
1023int
Denys Vlasenko7e69ed92015-03-21 19:50:53 +01001024umoven(struct tcb *tcp, long addr, unsigned int len, void *our_addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025{
Denys Vlasenko7e69ed92015-03-21 19:50:53 +01001026 char *laddr = our_addr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001027 int pid = tcp->pid;
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001028 unsigned int n, m, nread;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001029 union {
1030 long val;
1031 char x[sizeof(long)];
1032 } u;
1033
Denys Vlasenko2544f982013-02-19 17:39:56 +01001034#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
Denys Vlasenko9fd4f962012-03-19 09:36:42 +01001035 if (current_wordsize < sizeof(addr))
1036 addr &= (1ul << 8 * current_wordsize) - 1;
Denys Vlasenkod2a660f2012-02-25 00:43:22 +01001037#endif
1038
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001039 if (!process_vm_readv_not_supported) {
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001040 int r = vm_read_mem(pid, laddr, addr, len);
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001041 if ((unsigned int) r == len)
Ben Noordhuis1d58fe92013-02-26 12:24:25 +01001042 return 0;
Dmitry V. Levin97005922013-02-26 21:16:22 +00001043 if (r >= 0) {
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001044 error_msg("umoven: short read (%u < %u) @0x%lx",
1045 (unsigned int) r, len, addr);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001046 return -1;
1047 }
1048 switch (errno) {
1049 case ENOSYS:
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001050 process_vm_readv_not_supported = 1;
Dmitry V. Levin97005922013-02-26 21:16:22 +00001051 break;
Dmitry V. Levinb2893c92015-03-30 15:21:55 +00001052 case EPERM:
1053 /* operation not permitted, try PTRACE_PEEKDATA */
1054 break;
Dmitry V. Levin97005922013-02-26 21:16:22 +00001055 case ESRCH:
1056 /* the process is gone */
1057 return -1;
Dmitry V. Levinb2893c92015-03-30 15:21:55 +00001058 case EFAULT: case EIO:
Dmitry V. Levin97005922013-02-26 21:16:22 +00001059 /* address space is inaccessible */
1060 return -1;
1061 default:
1062 /* all the rest is strange and should be reported */
Denys Vlasenko905e8e02013-02-26 12:30:09 +01001063 perror_msg("process_vm_readv");
Dmitry V. Levin97005922013-02-26 21:16:22 +00001064 return -1;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001065 }
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001066 }
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001067
Dmitry V. Levin97005922013-02-26 21:16:22 +00001068 nread = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001069 if (addr & (sizeof(long) - 1)) {
1070 /* addr not a multiple of sizeof(long) */
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001071 n = addr & (sizeof(long) - 1); /* residue */
1072 addr &= -sizeof(long); /* aligned address */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001073 errno = 0;
1074 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001075 switch (errno) {
1076 case 0:
1077 break;
1078 case ESRCH: case EINVAL:
1079 /* these could be seen if the process is gone */
1080 return -1;
1081 case EFAULT: case EIO: case EPERM:
1082 /* address space is inaccessible */
1083 return -1;
1084 default:
1085 /* all the rest is strange and should be reported */
1086 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx",
1087 pid, addr);
1088 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001089 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001090 m = MIN(sizeof(long) - n, len);
1091 memcpy(laddr, &u.x[n], m);
Denys Vlasenko16940922013-03-01 18:52:59 +01001092 addr += sizeof(long);
1093 laddr += m;
1094 nread += m;
1095 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001096 }
1097 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001098 errno = 0;
1099 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001100 switch (errno) {
1101 case 0:
1102 break;
1103 case ESRCH: case EINVAL:
1104 /* these could be seen if the process is gone */
1105 return -1;
1106 case EFAULT: case EIO: case EPERM:
1107 /* address space is inaccessible */
1108 if (nread) {
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001109 perror_msg("umoven: short read (%u < %u) @0x%lx",
Dmitry V. Levin97005922013-02-26 21:16:22 +00001110 nread, nread + len, addr - nread);
1111 }
1112 return -1;
1113 default:
1114 /* all the rest is strange and should be reported */
1115 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx",
1116 pid, addr);
1117 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001118 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001119 m = MIN(sizeof(long), len);
1120 memcpy(laddr, u.x, m);
Denys Vlasenko16940922013-03-01 18:52:59 +01001121 addr += sizeof(long);
1122 laddr += m;
1123 nread += m;
1124 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001125 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001126
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001127 return 0;
1128}
1129
Dmitry V. Levin332a3262015-07-05 22:09:29 +00001130int
1131umoven_or_printaddr(struct tcb *tcp, const long addr, const unsigned int len,
1132 void *our_addr)
1133{
1134 if (!addr) {
1135 tprints("NULL");
1136 return -1;
1137 }
Dmitry V. Levin61b79892015-07-14 22:03:55 +00001138 if (!verbose(tcp) || (exiting(tcp) && syserror(tcp)) ||
Dmitry V. Levin332a3262015-07-05 22:09:29 +00001139 umoven(tcp, addr, len, our_addr) < 0) {
1140 tprintf("%#lx", addr);
1141 return -1;
1142 }
1143 return 0;
1144}
1145
Dmitry V. Levin13c21732015-08-26 12:49:07 +00001146int
Dmitry V. Levin09a1a5a2015-09-14 23:02:29 +00001147umove_ulong_or_printaddr(struct tcb *tcp, const long addr, unsigned long *ptr)
Dmitry V. Levin13c21732015-08-26 12:49:07 +00001148{
1149 if (current_wordsize < sizeof(*ptr)) {
1150 uint32_t val32;
1151 int r = umove_or_printaddr(tcp, addr, &val32);
1152 if (!r)
1153 *ptr = (unsigned long) val32;
1154 return r;
1155 }
1156 return umove_or_printaddr(tcp, addr, ptr);
1157}
1158
Dmitry V. Levinb172a942015-09-15 02:17:32 +00001159int
1160umove_ulong_array_or_printaddr(struct tcb *tcp, const long addr,
1161 unsigned long *ptr, size_t n)
1162{
1163 if (current_wordsize < sizeof(*ptr)) {
1164 uint32_t ptr32[n];
1165 int r = umove_or_printaddr(tcp, addr, &ptr32);
1166 if (!r) {
1167 size_t i;
1168
1169 for (i = 0; i < n; ++i)
1170 ptr[i] = (unsigned long) ptr32[i];
1171 }
1172 return r;
1173 }
1174 return umoven_or_printaddr(tcp, addr, n * sizeof(*ptr), ptr);
1175}
1176
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001177/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001178 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001180 *
1181 * Returns < 0 on error, > 0 if NUL was seen,
1182 * (TODO if useful: return count of bytes including NUL),
1183 * else 0 if len bytes were read but no NUL byte seen.
1184 *
1185 * Note: there is no guarantee we won't overwrite some bytes
1186 * in laddr[] _after_ terminating NUL (but, of course,
1187 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001188 */
1189int
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001190umovestr(struct tcb *tcp, long addr, unsigned int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191{
Denys Vlasenko16940922013-03-01 18:52:59 +01001192#if SIZEOF_LONG == 4
1193 const unsigned long x01010101 = 0x01010101ul;
1194 const unsigned long x80808080 = 0x80808080ul;
1195#elif SIZEOF_LONG == 8
1196 const unsigned long x01010101 = 0x0101010101010101ul;
1197 const unsigned long x80808080 = 0x8080808080808080ul;
1198#else
1199# error SIZEOF_LONG > 8
1200#endif
1201
Roland McGratheb9e2e82009-06-02 16:49:22 -07001202 int pid = tcp->pid;
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001203 unsigned int n, m, nread;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001204 union {
Denys Vlasenko16940922013-03-01 18:52:59 +01001205 unsigned long val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001206 char x[sizeof(long)];
1207 } u;
1208
Denys Vlasenko2544f982013-02-19 17:39:56 +01001209#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
Denys Vlasenko9fd4f962012-03-19 09:36:42 +01001210 if (current_wordsize < sizeof(addr))
1211 addr &= (1ul << 8 * current_wordsize) - 1;
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +00001212#endif
1213
Dmitry V. Levin97005922013-02-26 21:16:22 +00001214 nread = 0;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001215 if (!process_vm_readv_not_supported) {
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001216 const size_t page_size = get_pagesize();
1217 const size_t page_mask = page_size - 1;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001218
1219 while (len > 0) {
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001220 unsigned int chunk_len;
1221 unsigned int end_in_page;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001222
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001223 /*
1224 * Don't cross pages, otherwise we can get EFAULT
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001225 * and fail to notice that terminating NUL lies
1226 * in the existing (first) page.
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001227 */
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001228 chunk_len = len > page_size ? page_size : len;
1229 end_in_page = (addr + chunk_len) & page_mask;
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001230 if (chunk_len > end_in_page) /* crosses to the next page */
1231 chunk_len -= end_in_page;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001232
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001233 int r = vm_read_mem(pid, laddr, addr, chunk_len);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001234 if (r > 0) {
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001235 if (memchr(laddr, '\0', r))
Dmitry V. Levin97005922013-02-26 21:16:22 +00001236 return 1;
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001237 addr += r;
1238 laddr += r;
Dmitry V. Levin97005922013-02-26 21:16:22 +00001239 nread += r;
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001240 len -= r;
Dmitry V. Levin97005922013-02-26 21:16:22 +00001241 continue;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001242 }
Dmitry V. Levin97005922013-02-26 21:16:22 +00001243 switch (errno) {
1244 case ENOSYS:
1245 process_vm_readv_not_supported = 1;
1246 goto vm_readv_didnt_work;
1247 case ESRCH:
1248 /* the process is gone */
1249 return -1;
Dmitry V. Levinb2893c92015-03-30 15:21:55 +00001250 case EPERM:
1251 /* operation not permitted, try PTRACE_PEEKDATA */
1252 if (!nread)
1253 goto vm_readv_didnt_work;
1254 /* fall through */
1255 case EFAULT: case EIO:
Dmitry V. Levin97005922013-02-26 21:16:22 +00001256 /* address space is inaccessible */
1257 if (nread) {
1258 perror_msg("umovestr: short read (%d < %d) @0x%lx",
Dmitry V. Levinea1fea62015-03-31 19:45:08 +00001259 nread, nread + len, addr - nread);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001260 }
1261 return -1;
1262 default:
1263 /* all the rest is strange and should be reported */
1264 perror_msg("process_vm_readv");
1265 return -1;
1266 }
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001267 }
1268 return 0;
1269 }
1270 vm_readv_didnt_work:
1271
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001272 if (addr & (sizeof(long) - 1)) {
1273 /* addr not a multiple of sizeof(long) */
Dmitry V. Levin97e59962015-01-14 08:05:45 +00001274 n = addr & (sizeof(long) - 1); /* residue */
1275 addr &= -sizeof(long); /* aligned address */
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 return -1;
1287 default:
1288 /* all the rest is strange and should be reported */
1289 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx",
1290 pid, addr);
1291 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001292 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001293 m = MIN(sizeof(long) - n, len);
1294 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001295 while (n & (sizeof(long) - 1))
1296 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001297 return 1;
Denys Vlasenko16940922013-03-01 18:52:59 +01001298 addr += sizeof(long);
1299 laddr += m;
1300 nread += m;
1301 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001302 }
Denys Vlasenko16940922013-03-01 18:52:59 +01001303
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001304 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001305 errno = 0;
1306 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001307 switch (errno) {
1308 case 0:
1309 break;
1310 case ESRCH: case EINVAL:
1311 /* these could be seen if the process is gone */
1312 return -1;
1313 case EFAULT: case EIO: case EPERM:
1314 /* address space is inaccessible */
1315 if (nread) {
1316 perror_msg("umovestr: short read (%d < %d) @0x%lx",
1317 nread, nread + len, addr - nread);
1318 }
1319 return -1;
1320 default:
1321 /* all the rest is strange and should be reported */
1322 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx",
1323 pid, addr);
1324 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001325 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001326 m = MIN(sizeof(long), len);
1327 memcpy(laddr, u.x, m);
Denys Vlasenko16940922013-03-01 18:52:59 +01001328 /* "If a NUL char exists in this word" */
1329 if ((u.val - x01010101) & ~u.val & x80808080)
1330 return 1;
1331 addr += sizeof(long);
1332 laddr += m;
1333 nread += m;
1334 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001335 }
John Hughesaa09c6b2001-05-15 14:53:43 +00001336 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001337}