blob: bb0bca028e7a2b70c6dc8868fbfb7955ab32e85c [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;
23
24static long get_length(enum tof type, struct process *proc, int len_spec)
25{
26 if (len_spec > 0)
27 return len_spec;
28 return gimme_arg(type, proc, -len_spec - 1);
29}
30
Steve Fink7bafff02006-08-07 04:50:42 +020031static int display_pointer(enum tof type, struct process *proc, long value,
32 arg_type_info * info)
33{
34 long pointed_to;
35 arg_type_info *inner = info->u.ptr_info.info;
36
37 if (value == 0)
38 return fprintf(output, "NULL");
39 else if (umovelong(proc, (void *) value, &pointed_to) < 0)
40 return fprintf(output, "?");
41 else
42 return display_value(type, proc, pointed_to, inner);
43}
44
Steve Fink6a3e24d2006-08-07 05:53:19 +020045static int display_enum(enum tof type, struct process *proc,
46 arg_type_info* info, long value)
47{
48 int ii;
49 for (ii = 0; ii < info->u.enum_info.entries; ++ii) {
50 if (info->u.enum_info.values[ii] == value)
51 return fprintf(output, "%s", info->u.enum_info.keys[ii]);
52 }
53
54 return display_unknown(type, proc, value);
55}
56
Steve Fink7bafff02006-08-07 04:50:42 +020057/* Args:
58 type - syscall or shared library function or memory
59 proc - information about the traced process
60 value - the value to display
61 info - the description of the type to display
62*/
63int display_value(enum tof type, struct process *proc,
64 long value, arg_type_info *info)
Ian Wienand2d45b1a2006-02-20 22:48:07 +010065{
Juan Cespedes5e01f651998-03-08 22:31:44 +010066 int tmp;
Juan Cespedes5e01f651998-03-08 22:31:44 +010067
Steve Fink6a48a6d2006-08-07 04:29:06 +020068 switch (info->type) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010069 case ARGTYPE_VOID:
70 return 0;
Steve Fink6b175832006-08-07 04:37:33 +020071 case ARGTYPE_IGNORE:
72 return 0; /* Empty gap between commas */
Ian Wienand2d45b1a2006-02-20 22:48:07 +010073 case ARGTYPE_INT:
Steve Fink7bafff02006-08-07 04:50:42 +020074 return fprintf(output, "%d", (int) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010075 case ARGTYPE_UINT:
Steve Fink7bafff02006-08-07 04:50:42 +020076 return fprintf(output, "%u", (unsigned) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010077 case ARGTYPE_LONG:
78 if (proc->mask_32bit)
Steve Fink7bafff02006-08-07 04:50:42 +020079 return fprintf(output, "%d", (int) value);
80 else
81 return fprintf(output, "%ld", value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010082 case ARGTYPE_ULONG:
83 if (proc->mask_32bit)
Steve Fink7bafff02006-08-07 04:50:42 +020084 return fprintf(output, "%u", (unsigned) value);
85 else
86 return fprintf(output, "%lu", (unsigned long) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010087 case ARGTYPE_OCTAL:
Steve Fink7bafff02006-08-07 04:50:42 +020088 return fprintf(output, "0%o", (unsigned) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010089 case ARGTYPE_CHAR:
90 tmp = fprintf(output, "'");
Steve Fink7bafff02006-08-07 04:50:42 +020091 tmp += display_char(value == -1 ? value : (char) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010092 tmp += fprintf(output, "'");
93 return tmp;
Steve Fink6fa27c32006-08-07 05:56:56 +020094 case ARGTYPE_SHORT:
95 return fprintf(output, "%hd", (short) value);
96 case ARGTYPE_USHORT:
97 return fprintf(output, "%hu", (unsigned short) value);
98 case ARGTYPE_FLOAT: {
99 union { long l; float f; } cvt;
100 cvt.l = value;
101 return fprintf(output, "%f", cvt.f);
102 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100103 case ARGTYPE_ADDR:
Steve Fink7bafff02006-08-07 04:50:42 +0200104 if (!value)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100105 return fprintf(output, "NULL");
Steve Fink7bafff02006-08-07 04:50:42 +0200106 else
107 return fprintf(output, "0x%08lx", value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100108 case ARGTYPE_FORMAT:
Steve Fink7bafff02006-08-07 04:50:42 +0200109 fprintf(stderr, "Should never encounter a format anywhere but at the top level (for now?)\n");
110 exit(1);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100111 case ARGTYPE_STRING:
Steve Fink7bafff02006-08-07 04:50:42 +0200112 return display_string(type, proc, (void*) value,
Steve Fink6a48a6d2006-08-07 04:29:06 +0200113 string_maxlength);
114 case ARGTYPE_STRING_N:
Steve Fink7bafff02006-08-07 04:50:42 +0200115 return display_string(type, proc, (void*) value,
Steve Fink6a48a6d2006-08-07 04:29:06 +0200116 get_length(type, proc,
117 info->u.string_n_info.size_spec));
Steve Fink6a3e24d2006-08-07 05:53:19 +0200118 case ARGTYPE_ENUM:
119 return display_enum(type, proc, info, value);
Steve Fink7bafff02006-08-07 04:50:42 +0200120 case ARGTYPE_POINTER:
121 return display_pointer(type, proc, value, info);
122 case ARGTYPE_UNKNOWN:
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100123 default:
Steve Fink7bafff02006-08-07 04:50:42 +0200124 return display_unknown(type, proc, value);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100125 }
Steve Fink7bafff02006-08-07 04:50:42 +0200126}
127
128int display_arg(enum tof type, struct process *proc, int arg_num,
129 arg_type_info * info)
130{
131 long arg;
132
133 if (info->type == ARGTYPE_VOID) {
134 return 0;
135 } else if (info->type == ARGTYPE_FORMAT) {
136 return display_format(type, proc, arg_num);
137 } else {
138 arg = gimme_arg(type, proc, arg_num);
139 return display_value(type, proc, arg, info);
140 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100141}
142
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100143static int display_char(int what)
144{
145 switch (what) {
146 case -1:
147 return fprintf(output, "EOF");
148 case '\r':
149 return fprintf(output, "\\r");
150 case '\n':
151 return fprintf(output, "\\n");
152 case '\t':
153 return fprintf(output, "\\t");
154 case '\b':
155 return fprintf(output, "\\b");
156 case '\\':
157 return fprintf(output, "\\\\");
158 default:
Steve Fink7bafff02006-08-07 04:50:42 +0200159 if (isprint(what)) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100160 return fprintf(output, "%c", what);
Steve Fink7bafff02006-08-07 04:50:42 +0200161 } else {
162 return fprintf(output, "\\%03o", (unsigned char)what);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100163 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100164 }
165}
166
Juan Cespedes2c4a8cb1998-03-11 23:33:18 +0100167#define MIN(a,b) (((a)<(b)) ? (a) : (b))
168
Steve Fink7bafff02006-08-07 04:50:42 +0200169static int display_string(enum tof type, struct process *proc, void *addr,
170 size_t maxlength)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100171{
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100172 unsigned char *str1;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100173 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100174 int len = 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100175
Juan Cespedes5e01f651998-03-08 22:31:44 +0100176 if (!addr) {
177 return fprintf(output, "NULL");
178 }
179
Steve Fink6a48a6d2006-08-07 04:29:06 +0200180 str1 = malloc(MIN(opt_s, maxlength) + 3);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100181 if (!str1) {
182 return fprintf(output, "???");
183 }
Steve Fink6a48a6d2006-08-07 04:29:06 +0200184 umovestr(proc, addr, MIN(opt_s, maxlength) + 1, str1);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100185 len = fprintf(output, "\"");
Steve Fink6a48a6d2006-08-07 04:29:06 +0200186 for (i = 0; i < MIN(opt_s, maxlength); i++) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100187 if (str1[i]) {
188 len += display_char(str1[i]);
189 } else {
190 break;
191 }
192 }
193 len += fprintf(output, "\"");
Steve Fink6a48a6d2006-08-07 04:29:06 +0200194 if (str1[i] && (opt_s <= maxlength)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100195 len += fprintf(output, "...");
196 }
197 free(str1);
198 return len;
199}
200
Steve Fink7bafff02006-08-07 04:50:42 +0200201static int display_unknown(enum tof type, struct process *proc, long value)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100202{
Ian Wienand9a2ad352006-02-20 22:44:45 +0100203 if (proc->mask_32bit) {
Steve Fink7bafff02006-08-07 04:50:42 +0200204 if ((int)value < 1000000 && (int)value > -1000000)
205 return fprintf(output, "%d", (int)value);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100206 else
Steve Fink7bafff02006-08-07 04:50:42 +0200207 return fprintf(output, "%p", (void *)value);
208 } else if (value < 1000000 && value > -1000000) {
209 return fprintf(output, "%ld", value);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100210 } else {
Steve Fink7bafff02006-08-07 04:50:42 +0200211 return fprintf(output, "%p", (void *)value);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100212 }
213}
Juan Cespedesac3db291998-04-25 14:31:58 +0200214
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100215static int display_format(enum tof type, struct process *proc, int arg_num)
216{
217 void *addr;
218 unsigned char *str1;
Juan Cespedesac3db291998-04-25 14:31:58 +0200219 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100220 int len = 0;
Juan Cespedesac3db291998-04-25 14:31:58 +0200221
222 addr = (void *)gimme_arg(type, proc, arg_num);
223 if (!addr) {
224 return fprintf(output, "NULL");
225 }
226
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100227 str1 = malloc(MIN(opt_s, string_maxlength) + 3);
Juan Cespedesac3db291998-04-25 14:31:58 +0200228 if (!str1) {
229 return fprintf(output, "???");
230 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100231 umovestr(proc, addr, MIN(opt_s, string_maxlength) + 1, str1);
Juan Cespedesac3db291998-04-25 14:31:58 +0200232 len = fprintf(output, "\"");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100233 for (i = 0; len < MIN(opt_s, string_maxlength) + 1; i++) {
Juan Cespedesac3db291998-04-25 14:31:58 +0200234 if (str1[i]) {
235 len += display_char(str1[i]);
236 } else {
237 break;
238 }
239 }
240 len += fprintf(output, "\"");
241 if (str1[i] && (opt_s <= string_maxlength)) {
242 len += fprintf(output, "...");
243 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100244 for (i = 0; str1[i]; i++) {
245 if (str1[i] == '%') {
Juan Cespedesd914a202004-11-10 00:15:33 +0100246 int is_long = 0;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100247 while (1) {
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200248 unsigned char c = str1[++i];
Juan Cespedesac3db291998-04-25 14:31:58 +0200249 if (c == '%') {
250 break;
251 } else if (!c) {
252 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100253 } else if (strchr("lzZtj", c)) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100254 is_long++;
255 if (c == 'j')
256 is_long++;
Ian Wienand3219f322006-02-16 06:00:00 +0100257 if (is_long > 1
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100258 && (sizeof(long) < sizeof(long long)
259 || proc->mask_32bit)) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100260 len += fprintf(output, ", ...");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100261 str1[i + 1] = '\0';
Juan Cespedesd914a202004-11-10 00:15:33 +0100262 break;
263 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100264 } else if (c == 'd' || c == 'i') {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100265 if (!is_long || proc->mask_32bit)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100266 len +=
267 fprintf(output, ", %d",
268 (int)gimme_arg(type,
269 proc,
270 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100271 else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100272 len +=
273 fprintf(output, ", %ld",
274 gimme_arg(type,
275 proc,
276 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200277 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100278 } else if (c == 'u') {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100279 if (!is_long || proc->mask_32bit)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100280 len +=
281 fprintf(output, ", %u",
282 (int)gimme_arg(type,
283 proc,
284 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100285 else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100286 len +=
287 fprintf(output, ", %lu",
288 gimme_arg(type,
289 proc,
290 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200291 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100292 } else if (c == 'o') {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100293 if (!is_long || proc->mask_32bit)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100294 len +=
295 fprintf(output, ", 0%o",
296 (int)gimme_arg(type,
297 proc,
298 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100299 else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100300 len +=
301 fprintf(output, ", 0%lo",
302 gimme_arg(type,
303 proc,
304 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200305 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100306 } else if (c == 'x' || c == 'X') {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100307 if (!is_long || proc->mask_32bit)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100308 len +=
309 fprintf(output, ", %#x",
310 (int)gimme_arg(type,
311 proc,
312 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100313 else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100314 len +=
315 fprintf(output, ", %#lx",
316 gimme_arg(type,
317 proc,
318 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100319 break;
320 } else if (strchr("eEfFgGaACS", c)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100321 || (is_long
322 && (c == 'c' || c == 's'))) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100323 len += fprintf(output, ", ...");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100324 str1[i + 1] = '\0';
Juan Cespedesac3db291998-04-25 14:31:58 +0200325 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100326 } else if (c == 'c') {
Juan Cespedesac3db291998-04-25 14:31:58 +0200327 len += fprintf(output, ", '");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100328 len +=
329 display_char((int)
330 gimme_arg(type, proc,
331 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200332 len += fprintf(output, "'");
333 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100334 } else if (c == 's') {
Juan Cespedesac3db291998-04-25 14:31:58 +0200335 len += fprintf(output, ", ");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100336 len +=
337 display_string(type, proc,
Steve Fink7bafff02006-08-07 04:50:42 +0200338 (void *)gimme_arg(type,
339 proc,
340 ++arg_num),
Steve Fink6a48a6d2006-08-07 04:29:06 +0200341 string_maxlength);
Juan Cespedesac3db291998-04-25 14:31:58 +0200342 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100343 } else if (c == 'p' || c == 'n') {
344 len +=
345 fprintf(output, ", %p",
346 (void *)gimme_arg(type,
347 proc,
348 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200349 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100350 } else if (c == '*') {
351 len +=
352 fprintf(output, ", %d",
353 (int)gimme_arg(type, proc,
354 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200355 }
356 }
357 }
358 }
359 free(str1);
360 return len;
361}