blob: f91267cf3c62200803e4895be36a49dbedf50f51 [file] [log] [blame]
Juan Cespedesd44c6b81998-09-25 14:48:42 +02001#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
Steve Fink7bafff02006-08-07 04:50:42 +02005#include <ctype.h>
Juan Cespedes5e01f651998-03-08 22:31:44 +01006#include <stdio.h>
7#include <stdlib.h>
Juan Cespedesd914a202004-11-10 00:15:33 +01008#include <string.h>
Juan Cespedes2c4a8cb1998-03-11 23:33:18 +01009#include <limits.h>
Juan Cespedes5e01f651998-03-08 22:31:44 +010010
11#include "ltrace.h"
12#include "options.h"
13
Juan Cespedesac3db291998-04-25 14:31:58 +020014static int display_char(int what);
Steve Fink6a48a6d2006-08-07 04:29:06 +020015static int display_string(enum tof type, struct process *proc,
Steve Fink7bafff02006-08-07 04:50:42 +020016 void* addr, size_t maxlen);
17static int display_value(enum tof type, struct process *proc,
18 long value, arg_type_info *info);
19static int display_unknown(enum tof type, struct process *proc, long value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010020static int display_format(enum tof type, struct process *proc, int arg_num);
Juan Cespedes5e01f651998-03-08 22:31:44 +010021
Steve Fink6a48a6d2006-08-07 04:29:06 +020022static int string_maxlength = INT_MAX;
Steve Fink1150bc42006-08-07 06:04:43 +020023static int array_maxlength = INT_MAX;
Steve Fink6a48a6d2006-08-07 04:29:06 +020024
25static long get_length(enum tof type, struct process *proc, int len_spec)
26{
27 if (len_spec > 0)
28 return len_spec;
29 return gimme_arg(type, proc, -len_spec - 1);
30}
31
Steve Fink1150bc42006-08-07 06:04:43 +020032static int display_ptrto(enum tof type, struct process *proc, long item,
33 arg_type_info * info)
34{
35 arg_type_info temp;
36 temp.type = ARGTYPE_POINTER;
37 temp.u.ptr_info.info = info;
38 return display_value(type, proc, item, &temp);
39}
40
41/*
42 * addr - A pointer to the first element of the array
43 *
44 * The function name is used to indicate that we're not actually
45 * looking at an 'array', which is a contiguous region of memory
46 * containing a sequence of elements of some type; instead, we have a
47 * pointer to that region of memory.
48 */
49static int display_arrayptr(enum tof type, struct process *proc,
50 void *addr, arg_type_info * info)
51{
52 int len = 0;
53 int i;
54 int array_len;
55
56 if (addr == NULL)
57 return fprintf(output, "NULL");
58
59 array_len = get_length(type, proc, info->u.array_info.len_spec);
60 len += fprintf(output, "[ ");
61 for (i = 0; i < opt_A && i < array_maxlength && i < array_len; i++) {
62 arg_type_info *elt_type = info->u.array_info.elt_type;
63 size_t elt_size = info->u.array_info.elt_size;
64 if (i != 0)
65 len += fprintf(output, ", ");
66 if (opt_d)
67 len += fprintf(output, "%p=", addr);
68 len +=
69 display_ptrto(type, proc, (long) addr, elt_type);
70 addr += elt_size;
71 }
72 if (i < array_len)
73 len += fprintf(output, "...");
74 len += fprintf(output, " ]");
75 return len;
76}
77
Steve Fink7bafff02006-08-07 04:50:42 +020078static int display_pointer(enum tof type, struct process *proc, long value,
79 arg_type_info * info)
80{
81 long pointed_to;
82 arg_type_info *inner = info->u.ptr_info.info;
83
Steve Fink1150bc42006-08-07 06:04:43 +020084 if (inner->type == ARGTYPE_ARRAY) {
85 return display_arrayptr(type, proc, (void*) value, inner);
86 } else {
87 if (value == 0)
88 return fprintf(output, "NULL");
89 else if (umovelong(proc, (void *) value, &pointed_to) < 0)
90 return fprintf(output, "?");
91 else
92 return display_value(type, proc, pointed_to, inner);
93 }
Steve Fink7bafff02006-08-07 04:50:42 +020094}
95
Steve Fink6a3e24d2006-08-07 05:53:19 +020096static int display_enum(enum tof type, struct process *proc,
97 arg_type_info* info, long value)
98{
99 int ii;
100 for (ii = 0; ii < info->u.enum_info.entries; ++ii) {
101 if (info->u.enum_info.values[ii] == value)
102 return fprintf(output, "%s", info->u.enum_info.keys[ii]);
103 }
104
105 return display_unknown(type, proc, value);
106}
107
Steve Fink7bafff02006-08-07 04:50:42 +0200108/* Args:
109 type - syscall or shared library function or memory
110 proc - information about the traced process
111 value - the value to display
112 info - the description of the type to display
113*/
114int display_value(enum tof type, struct process *proc,
115 long value, arg_type_info *info)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100116{
Juan Cespedes5e01f651998-03-08 22:31:44 +0100117 int tmp;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100118
Steve Fink6a48a6d2006-08-07 04:29:06 +0200119 switch (info->type) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100120 case ARGTYPE_VOID:
121 return 0;
Steve Fink6b175832006-08-07 04:37:33 +0200122 case ARGTYPE_IGNORE:
123 return 0; /* Empty gap between commas */
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100124 case ARGTYPE_INT:
Steve Fink7bafff02006-08-07 04:50:42 +0200125 return fprintf(output, "%d", (int) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100126 case ARGTYPE_UINT:
Steve Fink7bafff02006-08-07 04:50:42 +0200127 return fprintf(output, "%u", (unsigned) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100128 case ARGTYPE_LONG:
129 if (proc->mask_32bit)
Steve Fink7bafff02006-08-07 04:50:42 +0200130 return fprintf(output, "%d", (int) value);
131 else
132 return fprintf(output, "%ld", value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100133 case ARGTYPE_ULONG:
134 if (proc->mask_32bit)
Steve Fink7bafff02006-08-07 04:50:42 +0200135 return fprintf(output, "%u", (unsigned) value);
136 else
137 return fprintf(output, "%lu", (unsigned long) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100138 case ARGTYPE_OCTAL:
Steve Fink7bafff02006-08-07 04:50:42 +0200139 return fprintf(output, "0%o", (unsigned) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100140 case ARGTYPE_CHAR:
141 tmp = fprintf(output, "'");
Steve Fink7bafff02006-08-07 04:50:42 +0200142 tmp += display_char(value == -1 ? value : (char) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100143 tmp += fprintf(output, "'");
144 return tmp;
Steve Fink6fa27c32006-08-07 05:56:56 +0200145 case ARGTYPE_SHORT:
146 return fprintf(output, "%hd", (short) value);
147 case ARGTYPE_USHORT:
148 return fprintf(output, "%hu", (unsigned short) value);
149 case ARGTYPE_FLOAT: {
150 union { long l; float f; } cvt;
151 cvt.l = value;
152 return fprintf(output, "%f", cvt.f);
153 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100154 case ARGTYPE_ADDR:
Steve Fink7bafff02006-08-07 04:50:42 +0200155 if (!value)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100156 return fprintf(output, "NULL");
Steve Fink7bafff02006-08-07 04:50:42 +0200157 else
158 return fprintf(output, "0x%08lx", value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100159 case ARGTYPE_FORMAT:
Steve Fink7bafff02006-08-07 04:50:42 +0200160 fprintf(stderr, "Should never encounter a format anywhere but at the top level (for now?)\n");
161 exit(1);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100162 case ARGTYPE_STRING:
Steve Fink7bafff02006-08-07 04:50:42 +0200163 return display_string(type, proc, (void*) value,
Steve Fink6a48a6d2006-08-07 04:29:06 +0200164 string_maxlength);
165 case ARGTYPE_STRING_N:
Steve Fink7bafff02006-08-07 04:50:42 +0200166 return display_string(type, proc, (void*) value,
Steve Fink6a48a6d2006-08-07 04:29:06 +0200167 get_length(type, proc,
168 info->u.string_n_info.size_spec));
Steve Fink1150bc42006-08-07 06:04:43 +0200169 case ARGTYPE_ARRAY:
170 return fprintf(output, "<array without address>");
Steve Fink6a3e24d2006-08-07 05:53:19 +0200171 case ARGTYPE_ENUM:
172 return display_enum(type, proc, info, value);
Steve Fink7bafff02006-08-07 04:50:42 +0200173 case ARGTYPE_POINTER:
174 return display_pointer(type, proc, value, info);
175 case ARGTYPE_UNKNOWN:
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100176 default:
Steve Fink7bafff02006-08-07 04:50:42 +0200177 return display_unknown(type, proc, value);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100178 }
Steve Fink7bafff02006-08-07 04:50:42 +0200179}
180
181int display_arg(enum tof type, struct process *proc, int arg_num,
182 arg_type_info * info)
183{
184 long arg;
185
186 if (info->type == ARGTYPE_VOID) {
187 return 0;
188 } else if (info->type == ARGTYPE_FORMAT) {
189 return display_format(type, proc, arg_num);
190 } else {
191 arg = gimme_arg(type, proc, arg_num);
192 return display_value(type, proc, arg, info);
193 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100194}
195
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100196static int display_char(int what)
197{
198 switch (what) {
199 case -1:
200 return fprintf(output, "EOF");
201 case '\r':
202 return fprintf(output, "\\r");
203 case '\n':
204 return fprintf(output, "\\n");
205 case '\t':
206 return fprintf(output, "\\t");
207 case '\b':
208 return fprintf(output, "\\b");
209 case '\\':
210 return fprintf(output, "\\\\");
211 default:
Steve Fink7bafff02006-08-07 04:50:42 +0200212 if (isprint(what)) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100213 return fprintf(output, "%c", what);
Steve Fink7bafff02006-08-07 04:50:42 +0200214 } else {
215 return fprintf(output, "\\%03o", (unsigned char)what);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100216 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100217 }
218}
219
Juan Cespedes2c4a8cb1998-03-11 23:33:18 +0100220#define MIN(a,b) (((a)<(b)) ? (a) : (b))
221
Steve Fink7bafff02006-08-07 04:50:42 +0200222static int display_string(enum tof type, struct process *proc, void *addr,
223 size_t maxlength)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100224{
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100225 unsigned char *str1;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100226 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100227 int len = 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100228
Juan Cespedes5e01f651998-03-08 22:31:44 +0100229 if (!addr) {
230 return fprintf(output, "NULL");
231 }
232
Steve Fink6a48a6d2006-08-07 04:29:06 +0200233 str1 = malloc(MIN(opt_s, maxlength) + 3);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100234 if (!str1) {
235 return fprintf(output, "???");
236 }
Steve Fink6a48a6d2006-08-07 04:29:06 +0200237 umovestr(proc, addr, MIN(opt_s, maxlength) + 1, str1);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100238 len = fprintf(output, "\"");
Steve Fink6a48a6d2006-08-07 04:29:06 +0200239 for (i = 0; i < MIN(opt_s, maxlength); i++) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100240 if (str1[i]) {
241 len += display_char(str1[i]);
242 } else {
243 break;
244 }
245 }
246 len += fprintf(output, "\"");
Steve Fink6a48a6d2006-08-07 04:29:06 +0200247 if (str1[i] && (opt_s <= maxlength)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100248 len += fprintf(output, "...");
249 }
250 free(str1);
251 return len;
252}
253
Steve Fink7bafff02006-08-07 04:50:42 +0200254static int display_unknown(enum tof type, struct process *proc, long value)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100255{
Ian Wienand9a2ad352006-02-20 22:44:45 +0100256 if (proc->mask_32bit) {
Steve Fink7bafff02006-08-07 04:50:42 +0200257 if ((int)value < 1000000 && (int)value > -1000000)
258 return fprintf(output, "%d", (int)value);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100259 else
Steve Fink7bafff02006-08-07 04:50:42 +0200260 return fprintf(output, "%p", (void *)value);
261 } else if (value < 1000000 && value > -1000000) {
262 return fprintf(output, "%ld", value);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100263 } else {
Steve Fink7bafff02006-08-07 04:50:42 +0200264 return fprintf(output, "%p", (void *)value);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100265 }
266}
Juan Cespedesac3db291998-04-25 14:31:58 +0200267
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100268static int display_format(enum tof type, struct process *proc, int arg_num)
269{
270 void *addr;
271 unsigned char *str1;
Juan Cespedesac3db291998-04-25 14:31:58 +0200272 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100273 int len = 0;
Juan Cespedesac3db291998-04-25 14:31:58 +0200274
275 addr = (void *)gimme_arg(type, proc, arg_num);
276 if (!addr) {
277 return fprintf(output, "NULL");
278 }
279
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100280 str1 = malloc(MIN(opt_s, string_maxlength) + 3);
Juan Cespedesac3db291998-04-25 14:31:58 +0200281 if (!str1) {
282 return fprintf(output, "???");
283 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100284 umovestr(proc, addr, MIN(opt_s, string_maxlength) + 1, str1);
Juan Cespedesac3db291998-04-25 14:31:58 +0200285 len = fprintf(output, "\"");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100286 for (i = 0; len < MIN(opt_s, string_maxlength) + 1; i++) {
Juan Cespedesac3db291998-04-25 14:31:58 +0200287 if (str1[i]) {
288 len += display_char(str1[i]);
289 } else {
290 break;
291 }
292 }
293 len += fprintf(output, "\"");
294 if (str1[i] && (opt_s <= string_maxlength)) {
295 len += fprintf(output, "...");
296 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100297 for (i = 0; str1[i]; i++) {
298 if (str1[i] == '%') {
Juan Cespedesd914a202004-11-10 00:15:33 +0100299 int is_long = 0;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100300 while (1) {
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200301 unsigned char c = str1[++i];
Juan Cespedesac3db291998-04-25 14:31:58 +0200302 if (c == '%') {
303 break;
304 } else if (!c) {
305 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100306 } else if (strchr("lzZtj", c)) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100307 is_long++;
308 if (c == 'j')
309 is_long++;
Ian Wienand3219f322006-02-16 06:00:00 +0100310 if (is_long > 1
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100311 && (sizeof(long) < sizeof(long long)
312 || proc->mask_32bit)) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100313 len += fprintf(output, ", ...");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100314 str1[i + 1] = '\0';
Juan Cespedesd914a202004-11-10 00:15:33 +0100315 break;
316 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100317 } else if (c == 'd' || c == 'i') {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100318 if (!is_long || proc->mask_32bit)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100319 len +=
320 fprintf(output, ", %d",
321 (int)gimme_arg(type,
322 proc,
323 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100324 else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100325 len +=
326 fprintf(output, ", %ld",
327 gimme_arg(type,
328 proc,
329 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200330 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100331 } else if (c == 'u') {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100332 if (!is_long || proc->mask_32bit)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100333 len +=
334 fprintf(output, ", %u",
335 (int)gimme_arg(type,
336 proc,
337 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100338 else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100339 len +=
340 fprintf(output, ", %lu",
341 gimme_arg(type,
342 proc,
343 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200344 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100345 } else if (c == 'o') {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100346 if (!is_long || proc->mask_32bit)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100347 len +=
348 fprintf(output, ", 0%o",
349 (int)gimme_arg(type,
350 proc,
351 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100352 else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100353 len +=
354 fprintf(output, ", 0%lo",
355 gimme_arg(type,
356 proc,
357 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200358 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100359 } else if (c == 'x' || c == 'X') {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100360 if (!is_long || proc->mask_32bit)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100361 len +=
362 fprintf(output, ", %#x",
363 (int)gimme_arg(type,
364 proc,
365 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100366 else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100367 len +=
368 fprintf(output, ", %#lx",
369 gimme_arg(type,
370 proc,
371 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100372 break;
373 } else if (strchr("eEfFgGaACS", c)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100374 || (is_long
375 && (c == 'c' || c == 's'))) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100376 len += fprintf(output, ", ...");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100377 str1[i + 1] = '\0';
Juan Cespedesac3db291998-04-25 14:31:58 +0200378 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100379 } else if (c == 'c') {
Juan Cespedesac3db291998-04-25 14:31:58 +0200380 len += fprintf(output, ", '");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100381 len +=
382 display_char((int)
383 gimme_arg(type, proc,
384 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200385 len += fprintf(output, "'");
386 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100387 } else if (c == 's') {
Juan Cespedesac3db291998-04-25 14:31:58 +0200388 len += fprintf(output, ", ");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100389 len +=
390 display_string(type, proc,
Steve Fink7bafff02006-08-07 04:50:42 +0200391 (void *)gimme_arg(type,
392 proc,
393 ++arg_num),
Steve Fink6a48a6d2006-08-07 04:29:06 +0200394 string_maxlength);
Juan Cespedesac3db291998-04-25 14:31:58 +0200395 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100396 } else if (c == 'p' || c == 'n') {
397 len +=
398 fprintf(output, ", %p",
399 (void *)gimme_arg(type,
400 proc,
401 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200402 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100403 } else if (c == '*') {
404 len +=
405 fprintf(output, ", %d",
406 (int)gimme_arg(type, proc,
407 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200408 }
409 }
410 }
411 }
412 free(str1);
413 return len;
414}