tizen 2.0
[external/ltrace.git] / display_args.c
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <limits.h>
6
7 #include "common.h"
8
9 static int display_char(int what);
10 static int display_string(enum tof type, Process *proc,
11                           void* addr, size_t maxlen);
12 static int display_value(enum tof type, Process *proc,
13                          long value, arg_type_info *info,
14                          void *st, arg_type_info* st_info);
15 static int display_unknown(enum tof type, Process *proc, long value);
16 static int display_format(enum tof type, Process *proc, int arg_num);
17
18 static int string_maxlength = INT_MAX;
19 static int array_maxlength = INT_MAX;
20
21 static long
22 get_length(enum tof type, Process *proc, int len_spec,
23                        void *st, arg_type_info* st_info) {
24         long len;
25         arg_type_info info;
26
27         if (len_spec > 0)
28                 return len_spec;
29         if (type == LT_TOF_STRUCT) {
30                 umovelong (proc, st + st_info->u.struct_info.offset[-len_spec-1],
31                            &len, st_info->u.struct_info.fields[-len_spec-1]);
32                 return len;
33         }
34
35         info.type = ARGTYPE_INT;
36         return gimme_arg(type, proc, -len_spec-1, &info);
37 }
38
39 static int
40 display_ptrto(enum tof type, Process *proc, long item,
41                          arg_type_info * info,
42                          void *st, arg_type_info* st_info) {
43         arg_type_info temp;
44         temp.type = ARGTYPE_POINTER;
45         temp.u.ptr_info.info = info;
46         return display_value(type, proc, item, &temp, st, st_info);
47 }
48
49 /*
50  * addr - A pointer to the first element of the array
51  *
52  * The function name is used to indicate that we're not actually
53  * looking at an 'array', which is a contiguous region of memory
54  * containing a sequence of elements of some type; instead, we have a
55  * pointer to that region of memory.
56  */
57 static int
58 display_arrayptr(enum tof type, Process *proc,
59                             void *addr, arg_type_info * info,
60                             void *st, arg_type_info* st_info) {
61         int len = 0;
62         int i;
63         int array_len;
64
65         if (addr == NULL)
66                 return fprintf(options.output, "NULL");
67
68         array_len = get_length(type, proc, info->u.array_info.len_spec,
69                         st, st_info);
70         len += fprintf(options.output, "[ ");
71         for (i = 0; i < options.arraylen && i < array_maxlength && i < array_len; i++) {
72                 arg_type_info *elt_type = info->u.array_info.elt_type;
73                 size_t elt_size = info->u.array_info.elt_size;
74                 if (i != 0)
75                         len += fprintf(options.output, ", ");
76                 if (options.debug)
77                         len += fprintf(options.output, "%p=", addr);
78                 len +=
79                         display_ptrto(type, proc, (long) addr, elt_type, st, st_info);
80                 addr += elt_size;
81         }
82         if (i < array_len)
83                 len += fprintf(options.output, "...");
84         len += fprintf(options.output, " ]");
85         return len;
86 }
87
88 /* addr - A pointer to the beginning of the memory region occupied by
89  *        the struct (aka a pointer to the struct)
90  */
91 static int
92 display_structptr(enum tof type, Process *proc,
93                              void *addr, arg_type_info * info) {
94         int i;
95         arg_type_info *field;
96         int len = 0;
97
98         if (addr == NULL)
99                 return fprintf(options.output, "NULL");
100
101         len += fprintf(options.output, "{ ");
102         for (i = 0; (field = info->u.struct_info.fields[i]) != NULL; i++) {
103                 if (i != 0)
104                         len += fprintf(options.output, ", ");
105                 if (options.debug)
106                         len +=
107                                 fprintf(options.output, "%p=",
108                                                 addr + info->u.struct_info.offset[i]);
109                 len +=
110                         display_ptrto(LT_TOF_STRUCT, proc,
111                                         (long) addr + info->u.struct_info.offset[i],
112                                         field, addr, info);
113         }
114         len += fprintf(options.output, " }");
115
116         return len;
117 }
118
119 static int
120 display_pointer(enum tof type, Process *proc, long value,
121                            arg_type_info * info,
122                            void *st, arg_type_info* st_info) {
123         long pointed_to;
124         arg_type_info *inner = info->u.ptr_info.info;
125
126         if (inner->type == ARGTYPE_ARRAY) {
127                 return display_arrayptr(type, proc, (void*) value, inner,
128                                 st, st_info);
129         } else if (inner->type == ARGTYPE_STRUCT) {
130                 return display_structptr(type, proc, (void *) value, inner);
131         } else {
132                 if (value == 0)
133                         return fprintf(options.output, "NULL");
134                 else if (umovelong (proc, (void *) value, &pointed_to,
135                                     info->u.ptr_info.info) < 0)
136                         return fprintf(options.output, "?");
137                 else
138                         return display_value(type, proc, pointed_to, inner,
139                                         st, st_info);
140         }
141 }
142
143 static int
144 display_enum(enum tof type, Process *proc,
145                 arg_type_info* info, long value) {
146         int ii;
147         for (ii = 0; ii < info->u.enum_info.entries; ++ii) {
148                 if (info->u.enum_info.values[ii] == value)
149                         return fprintf(options.output, "%s", info->u.enum_info.keys[ii]);
150         }
151
152         return display_unknown(type, proc, value);
153 }
154
155 /* Args:
156    type - syscall or shared library function or memory
157    proc - information about the traced process
158    value - the value to display
159    info - the description of the type to display
160    st - if the current value is a struct member, the address of the struct
161    st_info - type of the above struct
162
163    Those last two parameters are used for structs containing arrays or
164    strings whose length is given by another structure element.
165 */
166 int
167 display_value(enum tof type, Process *proc,
168                 long value, arg_type_info *info,
169                 void *st, arg_type_info* st_info) {
170         int tmp;
171
172         switch (info->type) {
173         case ARGTYPE_VOID:
174                 return 0;
175         case ARGTYPE_INT:
176                 return fprintf(options.output, "%d", (int) value);
177         case ARGTYPE_UINT:
178                 return fprintf(options.output, "%u", (unsigned) value);
179         case ARGTYPE_LONG:
180                 if (proc->mask_32bit)
181                         return fprintf(options.output, "%d", (int) value);
182                 else
183                         return fprintf(options.output, "%ld", value);
184         case ARGTYPE_ULONG:
185                 if (proc->mask_32bit)
186                         return fprintf(options.output, "%u", (unsigned) value);
187                 else
188                         return fprintf(options.output, "%lu", (unsigned long) value);
189         case ARGTYPE_OCTAL:
190                 return fprintf(options.output, "0%o", (unsigned) value);
191         case ARGTYPE_CHAR:
192                 tmp = fprintf(options.output, "'");
193                 tmp += display_char(value == -1 ? value : (char) value);
194                 tmp += fprintf(options.output, "'");
195                 return tmp;
196         case ARGTYPE_SHORT:
197                 return fprintf(options.output, "%hd", (short) value);
198         case ARGTYPE_USHORT:
199                 return fprintf(options.output, "%hu", (unsigned short) value);
200         case ARGTYPE_FLOAT: {
201                 union { long l; float f; double d; } cvt;
202                 cvt.l = value;
203                 return fprintf(options.output, "%f", cvt.f);
204         }
205         case ARGTYPE_DOUBLE: {
206                 union { long l; float f; double d; } cvt;
207                 cvt.l = value;
208                 return fprintf(options.output, "%lf", cvt.d);
209         }
210         case ARGTYPE_ADDR:
211                 if (!value)
212                         return fprintf(options.output, "NULL");
213                 else
214                         return fprintf(options.output, "0x%08lx", value);
215         case ARGTYPE_FORMAT:
216                 fprintf(stderr, "Should never encounter a format anywhere but at the top level (for now?)\n");
217                 exit(1);
218         case ARGTYPE_STRING:
219                 return display_string(type, proc, (void*) value,
220                                       string_maxlength);
221         case ARGTYPE_STRING_N:
222                 return display_string(type, proc, (void*) value,
223                                       get_length(type, proc,
224                                                  info->u.string_n_info.size_spec, st, st_info));
225         case ARGTYPE_ARRAY:
226                 return fprintf(options.output, "<array without address>");
227         case ARGTYPE_ENUM:
228                 return display_enum(type, proc, info, value);
229         case ARGTYPE_STRUCT:
230                 return fprintf(options.output, "<struct without address>");
231         case ARGTYPE_POINTER:
232                 return display_pointer(type, proc, value, info,
233                                        st, st_info);
234         case ARGTYPE_UNKNOWN:
235         default:
236                 return display_unknown(type, proc, value);
237         }
238 }
239
240 int
241 display_arg(enum tof type, Process *proc, int arg_num, arg_type_info * info) {
242         long arg;
243
244         if (info->type == ARGTYPE_VOID) {
245                 return 0;
246         } else if (info->type == ARGTYPE_FORMAT) {
247                 return display_format(type, proc, arg_num);
248         } else {
249                 arg = gimme_arg(type, proc, arg_num, info);
250                 return display_value(type, proc, arg, info, NULL, NULL);
251         }
252 }
253
254 static int
255 display_char(int what) {
256         switch (what) {
257         case -1:
258                 return fprintf(options.output, "EOF");
259         case '\r':
260                 return fprintf(options.output, "\\r");
261         case '\n':
262                 return fprintf(options.output, "\\n");
263         case '\t':
264                 return fprintf(options.output, "\\t");
265         case '\b':
266                 return fprintf(options.output, "\\b");
267         case '\\':
268                 return fprintf(options.output, "\\\\");
269         default:
270                 if (isprint(what)) {
271                         return fprintf(options.output, "%c", what);
272                 } else {
273                         return fprintf(options.output, "\\%03o", (unsigned char)what);
274                 }
275         }
276 }
277
278 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
279
280 static int
281 display_string(enum tof type, Process *proc, void *addr,
282                           size_t maxlength) {
283         unsigned char *str1;
284         int i;
285         int len = 0;
286
287         if (!addr) {
288                 return fprintf(options.output, "NULL");
289         }
290
291         str1 = malloc(MIN(options.strlen, maxlength) + 3);
292         if (!str1) {
293                 return fprintf(options.output, "???");
294         }
295         umovestr(proc, addr, MIN(options.strlen, maxlength) + 1, str1);
296         len = fprintf(options.output, "\"");
297         for (i = 0; i < MIN(options.strlen, maxlength); i++) {
298                 if (str1[i]) {
299                         len += display_char(str1[i]);
300                 } else {
301                         break;
302                 }
303         }
304         len += fprintf(options.output, "\"");
305         if (str1[i] && (options.strlen <= maxlength)) {
306                 len += fprintf(options.output, "...");
307         }
308         free(str1);
309         return len;
310 }
311
312 static int
313 display_unknown(enum tof type, Process *proc, long value) {
314         if (proc->mask_32bit) {
315                 if ((int)value < 1000000 && (int)value > -1000000)
316                         return fprintf(options.output, "%d", (int)value);
317                 else
318                         return fprintf(options.output, "%p", (void *)value);
319         } else if (value < 1000000 && value > -1000000) {
320                 return fprintf(options.output, "%ld", value);
321         } else {
322                 return fprintf(options.output, "%p", (void *)value);
323         }
324 }
325
326 static int
327 display_format(enum tof type, Process *proc, int arg_num) {
328         void *addr;
329         unsigned char *str1;
330         int i;
331         int len = 0;
332         arg_type_info info;
333
334         info.type = ARGTYPE_POINTER;
335         addr = (void *)gimme_arg(type, proc, arg_num, &info);
336         if (!addr) {
337                 return fprintf(options.output, "NULL");
338         }
339
340         str1 = malloc(MIN(options.strlen, string_maxlength) + 3);
341         if (!str1) {
342                 return fprintf(options.output, "???");
343         }
344         umovestr(proc, addr, MIN(options.strlen, string_maxlength) + 1, str1);
345         len = fprintf(options.output, "\"");
346         for (i = 0; len < MIN(options.strlen, string_maxlength) + 1; i++) {
347                 if (str1[i]) {
348                         len += display_char(str1[i]);
349                 } else {
350                         break;
351                 }
352         }
353         len += fprintf(options.output, "\"");
354         if (str1[i] && (options.strlen <= string_maxlength)) {
355                 len += fprintf(options.output, "...");
356         }
357         for (i = 0; str1[i]; i++) {
358                 if (str1[i] == '%') {
359                         int is_long = 0;
360                         while (1) {
361                                 unsigned char c = str1[++i];
362                                 if (c == '%') {
363                                         break;
364                                 } else if (!c) {
365                                         break;
366                                 } else if (strchr("lzZtj", c)) {
367                                         is_long++;
368                                         if (c == 'j')
369                                                 is_long++;
370                                         if (is_long > 1
371                                             && (sizeof(long) < sizeof(long long)
372                                                 || proc->mask_32bit)) {
373                                                 len += fprintf(options.output, ", ...");
374                                                 str1[i + 1] = '\0';
375                                                 break;
376                                         }
377                                 } else if (c == 'd' || c == 'i') {
378                                         info.type = ARGTYPE_LONG;
379                                         if (!is_long || proc->mask_32bit)
380                                                 len +=
381                                                     fprintf(options.output, ", %d",
382                                                             (int)gimme_arg(type, proc, ++arg_num, &info));
383                                         else
384                                                 len +=
385                                                     fprintf(options.output, ", %ld",
386                                                             gimme_arg(type, proc, ++arg_num, &info));
387                                         break;
388                                 } else if (c == 'u') {
389                                         info.type = ARGTYPE_LONG;
390                                         if (!is_long || proc->mask_32bit)
391                                                 len +=
392                                                     fprintf(options.output, ", %u",
393                                                             (int)gimme_arg(type, proc, ++arg_num, &info));
394                                         else
395                                                 len +=
396                                                     fprintf(options.output, ", %lu",
397                                                             gimme_arg(type, proc, ++arg_num, &info));
398                                         break;
399                                 } else if (c == 'o') {
400                                         info.type = ARGTYPE_LONG;
401                                         if (!is_long || proc->mask_32bit)
402                                                 len +=
403                                                     fprintf(options.output, ", 0%o",
404                                                             (int)gimme_arg(type, proc, ++arg_num, &info));
405                                         else
406                                                 len +=
407                                                     fprintf(options.output, ", 0%lo",
408                                                             gimme_arg(type, proc, ++arg_num, &info));
409                                         break;
410                                 } else if (c == 'x' || c == 'X') {
411                                         info.type = ARGTYPE_LONG;
412                                         if (!is_long || proc->mask_32bit)
413                                                 len +=
414                                                     fprintf(options.output, ", %#x",
415                                                             (int)gimme_arg(type, proc, ++arg_num, &info));
416                                         else
417                                                 len +=
418                                                     fprintf(options.output, ", %#lx",
419                                                             gimme_arg(type, proc, ++arg_num, &info));
420                                         break;
421                                 } else if (strchr("eEfFgGaACS", c)
422                                            || (is_long
423                                                && (c == 'c' || c == 's'))) {
424                                         len += fprintf(options.output, ", ...");
425                                         str1[i + 1] = '\0';
426                                         break;
427                                 } else if (c == 'c') {
428                                         info.type = ARGTYPE_LONG;
429                                         len += fprintf(options.output, ", '");
430                                         len +=
431                                             display_char((int)
432                                                          gimme_arg(type, proc, ++arg_num, &info));
433                                         len += fprintf(options.output, "'");
434                                         break;
435                                 } else if (c == 's') {
436                                         info.type = ARGTYPE_POINTER;
437                                         len += fprintf(options.output, ", ");
438                                         len +=
439                                             display_string(type, proc,
440                                                            (void *)gimme_arg(type, proc, ++arg_num, &info),
441                                                            string_maxlength);
442                                         break;
443                                 } else if (c == 'p' || c == 'n') {
444                                         info.type = ARGTYPE_POINTER;
445                                         len +=
446                                             fprintf(options.output, ", %p",
447                                                     (void *)gimme_arg(type, proc, ++arg_num, &info));
448                                         break;
449                                 } else if (c == '*') {
450                                         info.type = ARGTYPE_LONG;
451                                         len +=
452                                             fprintf(options.output, ", %d",
453                                                     (int)gimme_arg(type, proc, ++arg_num, &info));
454                                 }
455                         }
456                 }
457         }
458         free(str1);
459         return len;
460 }