blob: 66a9093d3eb1c266d374ac12a73e1dae99585d2b [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
45/* Args:
46 type - syscall or shared library function or memory
47 proc - information about the traced process
48 value - the value to display
49 info - the description of the type to display
50*/
51int display_value(enum tof type, struct process *proc,
52 long value, arg_type_info *info)
Ian Wienand2d45b1a2006-02-20 22:48:07 +010053{
Juan Cespedes5e01f651998-03-08 22:31:44 +010054 int tmp;
Juan Cespedes5e01f651998-03-08 22:31:44 +010055
Steve Fink6a48a6d2006-08-07 04:29:06 +020056 switch (info->type) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010057 case ARGTYPE_VOID:
58 return 0;
Steve Fink6b175832006-08-07 04:37:33 +020059 case ARGTYPE_IGNORE:
60 return 0; /* Empty gap between commas */
Ian Wienand2d45b1a2006-02-20 22:48:07 +010061 case ARGTYPE_INT:
Steve Fink7bafff02006-08-07 04:50:42 +020062 return fprintf(output, "%d", (int) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010063 case ARGTYPE_UINT:
Steve Fink7bafff02006-08-07 04:50:42 +020064 return fprintf(output, "%u", (unsigned) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010065 case ARGTYPE_LONG:
66 if (proc->mask_32bit)
Steve Fink7bafff02006-08-07 04:50:42 +020067 return fprintf(output, "%d", (int) value);
68 else
69 return fprintf(output, "%ld", value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010070 case ARGTYPE_ULONG:
71 if (proc->mask_32bit)
Steve Fink7bafff02006-08-07 04:50:42 +020072 return fprintf(output, "%u", (unsigned) value);
73 else
74 return fprintf(output, "%lu", (unsigned long) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010075 case ARGTYPE_OCTAL:
Steve Fink7bafff02006-08-07 04:50:42 +020076 return fprintf(output, "0%o", (unsigned) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010077 case ARGTYPE_CHAR:
78 tmp = fprintf(output, "'");
Steve Fink7bafff02006-08-07 04:50:42 +020079 tmp += display_char(value == -1 ? value : (char) value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010080 tmp += fprintf(output, "'");
81 return tmp;
82 case ARGTYPE_ADDR:
Steve Fink7bafff02006-08-07 04:50:42 +020083 if (!value)
Ian Wienand2d45b1a2006-02-20 22:48:07 +010084 return fprintf(output, "NULL");
Steve Fink7bafff02006-08-07 04:50:42 +020085 else
86 return fprintf(output, "0x%08lx", value);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010087 case ARGTYPE_FORMAT:
Steve Fink7bafff02006-08-07 04:50:42 +020088 fprintf(stderr, "Should never encounter a format anywhere but at the top level (for now?)\n");
89 exit(1);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010090 case ARGTYPE_STRING:
Steve Fink7bafff02006-08-07 04:50:42 +020091 return display_string(type, proc, (void*) value,
Steve Fink6a48a6d2006-08-07 04:29:06 +020092 string_maxlength);
93 case ARGTYPE_STRING_N:
Steve Fink7bafff02006-08-07 04:50:42 +020094 return display_string(type, proc, (void*) value,
Steve Fink6a48a6d2006-08-07 04:29:06 +020095 get_length(type, proc,
96 info->u.string_n_info.size_spec));
Steve Fink7bafff02006-08-07 04:50:42 +020097 case ARGTYPE_POINTER:
98 return display_pointer(type, proc, value, info);
99 case ARGTYPE_UNKNOWN:
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100100 default:
Steve Fink7bafff02006-08-07 04:50:42 +0200101 return display_unknown(type, proc, value);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100102 }
Steve Fink7bafff02006-08-07 04:50:42 +0200103}
104
105int display_arg(enum tof type, struct process *proc, int arg_num,
106 arg_type_info * info)
107{
108 long arg;
109
110 if (info->type == ARGTYPE_VOID) {
111 return 0;
112 } else if (info->type == ARGTYPE_FORMAT) {
113 return display_format(type, proc, arg_num);
114 } else {
115 arg = gimme_arg(type, proc, arg_num);
116 return display_value(type, proc, arg, info);
117 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100118}
119
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100120static int display_char(int what)
121{
122 switch (what) {
123 case -1:
124 return fprintf(output, "EOF");
125 case '\r':
126 return fprintf(output, "\\r");
127 case '\n':
128 return fprintf(output, "\\n");
129 case '\t':
130 return fprintf(output, "\\t");
131 case '\b':
132 return fprintf(output, "\\b");
133 case '\\':
134 return fprintf(output, "\\\\");
135 default:
Steve Fink7bafff02006-08-07 04:50:42 +0200136 if (isprint(what)) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100137 return fprintf(output, "%c", what);
Steve Fink7bafff02006-08-07 04:50:42 +0200138 } else {
139 return fprintf(output, "\\%03o", (unsigned char)what);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100140 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100141 }
142}
143
Juan Cespedes2c4a8cb1998-03-11 23:33:18 +0100144#define MIN(a,b) (((a)<(b)) ? (a) : (b))
145
Steve Fink7bafff02006-08-07 04:50:42 +0200146static int display_string(enum tof type, struct process *proc, void *addr,
147 size_t maxlength)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100148{
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100149 unsigned char *str1;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100150 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100151 int len = 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100152
Juan Cespedes5e01f651998-03-08 22:31:44 +0100153 if (!addr) {
154 return fprintf(output, "NULL");
155 }
156
Steve Fink6a48a6d2006-08-07 04:29:06 +0200157 str1 = malloc(MIN(opt_s, maxlength) + 3);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100158 if (!str1) {
159 return fprintf(output, "???");
160 }
Steve Fink6a48a6d2006-08-07 04:29:06 +0200161 umovestr(proc, addr, MIN(opt_s, maxlength) + 1, str1);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100162 len = fprintf(output, "\"");
Steve Fink6a48a6d2006-08-07 04:29:06 +0200163 for (i = 0; i < MIN(opt_s, maxlength); i++) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100164 if (str1[i]) {
165 len += display_char(str1[i]);
166 } else {
167 break;
168 }
169 }
170 len += fprintf(output, "\"");
Steve Fink6a48a6d2006-08-07 04:29:06 +0200171 if (str1[i] && (opt_s <= maxlength)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100172 len += fprintf(output, "...");
173 }
174 free(str1);
175 return len;
176}
177
Steve Fink7bafff02006-08-07 04:50:42 +0200178static int display_unknown(enum tof type, struct process *proc, long value)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100179{
Ian Wienand9a2ad352006-02-20 22:44:45 +0100180 if (proc->mask_32bit) {
Steve Fink7bafff02006-08-07 04:50:42 +0200181 if ((int)value < 1000000 && (int)value > -1000000)
182 return fprintf(output, "%d", (int)value);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100183 else
Steve Fink7bafff02006-08-07 04:50:42 +0200184 return fprintf(output, "%p", (void *)value);
185 } else if (value < 1000000 && value > -1000000) {
186 return fprintf(output, "%ld", value);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100187 } else {
Steve Fink7bafff02006-08-07 04:50:42 +0200188 return fprintf(output, "%p", (void *)value);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100189 }
190}
Juan Cespedesac3db291998-04-25 14:31:58 +0200191
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100192static int display_format(enum tof type, struct process *proc, int arg_num)
193{
194 void *addr;
195 unsigned char *str1;
Juan Cespedesac3db291998-04-25 14:31:58 +0200196 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100197 int len = 0;
Juan Cespedesac3db291998-04-25 14:31:58 +0200198
199 addr = (void *)gimme_arg(type, proc, arg_num);
200 if (!addr) {
201 return fprintf(output, "NULL");
202 }
203
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100204 str1 = malloc(MIN(opt_s, string_maxlength) + 3);
Juan Cespedesac3db291998-04-25 14:31:58 +0200205 if (!str1) {
206 return fprintf(output, "???");
207 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100208 umovestr(proc, addr, MIN(opt_s, string_maxlength) + 1, str1);
Juan Cespedesac3db291998-04-25 14:31:58 +0200209 len = fprintf(output, "\"");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100210 for (i = 0; len < MIN(opt_s, string_maxlength) + 1; i++) {
Juan Cespedesac3db291998-04-25 14:31:58 +0200211 if (str1[i]) {
212 len += display_char(str1[i]);
213 } else {
214 break;
215 }
216 }
217 len += fprintf(output, "\"");
218 if (str1[i] && (opt_s <= string_maxlength)) {
219 len += fprintf(output, "...");
220 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100221 for (i = 0; str1[i]; i++) {
222 if (str1[i] == '%') {
Juan Cespedesd914a202004-11-10 00:15:33 +0100223 int is_long = 0;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100224 while (1) {
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200225 unsigned char c = str1[++i];
Juan Cespedesac3db291998-04-25 14:31:58 +0200226 if (c == '%') {
227 break;
228 } else if (!c) {
229 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100230 } else if (strchr("lzZtj", c)) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100231 is_long++;
232 if (c == 'j')
233 is_long++;
Ian Wienand3219f322006-02-16 06:00:00 +0100234 if (is_long > 1
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100235 && (sizeof(long) < sizeof(long long)
236 || proc->mask_32bit)) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100237 len += fprintf(output, ", ...");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100238 str1[i + 1] = '\0';
Juan Cespedesd914a202004-11-10 00:15:33 +0100239 break;
240 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100241 } else if (c == 'd' || c == 'i') {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100242 if (!is_long || proc->mask_32bit)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100243 len +=
244 fprintf(output, ", %d",
245 (int)gimme_arg(type,
246 proc,
247 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100248 else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100249 len +=
250 fprintf(output, ", %ld",
251 gimme_arg(type,
252 proc,
253 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200254 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100255 } else if (c == 'u') {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100256 if (!is_long || proc->mask_32bit)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100257 len +=
258 fprintf(output, ", %u",
259 (int)gimme_arg(type,
260 proc,
261 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100262 else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100263 len +=
264 fprintf(output, ", %lu",
265 gimme_arg(type,
266 proc,
267 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200268 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100269 } else if (c == 'o') {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100270 if (!is_long || proc->mask_32bit)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100271 len +=
272 fprintf(output, ", 0%o",
273 (int)gimme_arg(type,
274 proc,
275 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100276 else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100277 len +=
278 fprintf(output, ", 0%lo",
279 gimme_arg(type,
280 proc,
281 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200282 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100283 } else if (c == 'x' || c == 'X') {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100284 if (!is_long || proc->mask_32bit)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100285 len +=
286 fprintf(output, ", %#x",
287 (int)gimme_arg(type,
288 proc,
289 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100290 else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100291 len +=
292 fprintf(output, ", %#lx",
293 gimme_arg(type,
294 proc,
295 ++arg_num));
Juan Cespedesd914a202004-11-10 00:15:33 +0100296 break;
297 } else if (strchr("eEfFgGaACS", c)
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100298 || (is_long
299 && (c == 'c' || c == 's'))) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100300 len += fprintf(output, ", ...");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100301 str1[i + 1] = '\0';
Juan Cespedesac3db291998-04-25 14:31:58 +0200302 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100303 } else if (c == 'c') {
Juan Cespedesac3db291998-04-25 14:31:58 +0200304 len += fprintf(output, ", '");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100305 len +=
306 display_char((int)
307 gimme_arg(type, proc,
308 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200309 len += fprintf(output, "'");
310 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100311 } else if (c == 's') {
Juan Cespedesac3db291998-04-25 14:31:58 +0200312 len += fprintf(output, ", ");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100313 len +=
314 display_string(type, proc,
Steve Fink7bafff02006-08-07 04:50:42 +0200315 (void *)gimme_arg(type,
316 proc,
317 ++arg_num),
Steve Fink6a48a6d2006-08-07 04:29:06 +0200318 string_maxlength);
Juan Cespedesac3db291998-04-25 14:31:58 +0200319 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100320 } else if (c == 'p' || c == 'n') {
321 len +=
322 fprintf(output, ", %p",
323 (void *)gimme_arg(type,
324 proc,
325 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200326 break;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100327 } else if (c == '*') {
328 len +=
329 fprintf(output, ", %d",
330 (int)gimme_arg(type, proc,
331 ++arg_num));
Juan Cespedesac3db291998-04-25 14:31:58 +0200332 }
333 }
334 }
335 }
336 free(str1);
337 return len;
338}