added a bit more diagnostic printing
[platform/upstream/ltrace.git] / dwarf_prototypes.c
1 /* Copyright Dima Kogan <dima@secretsauce.net>
2  *
3  * This program is free software; you can redistribute it and/or modify it under
4  * the terms of version 2 of the GNU General Public License as published by the
5  * Free Software Foundation.
6  *
7  */
8 #include <stdio.h>
9 #include <elfutils/libdwfl.h>
10 #include <dwarf.h>
11 #include <stdlib.h>
12 #include <errno.h>
13 #include <string.h>
14
15 #include "config.h"
16 #include "prototype.h"
17 #include "type.h"
18 #include "param.h"
19 #include "dict.h"
20 #include "lens.h"
21 #include "lens_enum.h"
22 #include "value.h"
23 #include "expr.h"
24 #include "library.h"
25 #include "options.h"
26 #include "filter.h"
27 #include "debug.h"
28
29 #define complain(die, format, ...)                                                              \
30         debug(DEBUG_FUNCTION, "%s() die '%s' @ 0x%lx: " format,         \
31                   __func__, dwarf_diename(die), dwarf_dieoffset(die),   \
32                   ##__VA_ARGS__)
33
34 #define NEXT_SIBLING(die)                                                               \
35         int res = dwarf_siblingof(die, die);                            \
36         if (res == 0) continue;     /* sibling exists    */     \
37         if (res < 0)  return false; /* error             */     \
38         break                       /* no sibling exists */
39
40 static struct arg_type_info* get_type(int* newly_allocated_info,
41                                                                           Dwarf_Die* type_die, struct protolib* plib,
42                                                                           struct dict* type_dieoffset_hash);
43
44
45
46
47 // debugging functions to dump types that I already parsed
48 #ifdef DUMP_PROTOTYPES
49 static bool _dump_ltrace_tree(const struct arg_type_info* info, int indent)
50 {
51         if (indent > 7) {
52                 fprintf(stderr, "%*s%p ...\n", indent*4, "", (void*)info);
53                 return true;
54         }
55
56         if (info == NULL) {
57                 fprintf(stderr, "%*s%p NULL\n", indent*4, "", (void*)info);
58                 return true;
59         }
60
61         switch (info->type) {
62         case ARGTYPE_VOID:
63                 fprintf(stderr, "%*s%p void\n", indent*4, "", (void*)info);
64                 break;
65
66         case ARGTYPE_INT:
67         case ARGTYPE_UINT:
68         case ARGTYPE_LONG:
69         case ARGTYPE_ULONG:
70         case ARGTYPE_CHAR:
71         case ARGTYPE_SHORT:
72         case ARGTYPE_USHORT:
73         case ARGTYPE_FLOAT:
74         case ARGTYPE_DOUBLE:
75                 fprintf(stderr, "%*s%p base\n", indent*4, "", (void*)info);
76                 break;
77
78         case ARGTYPE_ARRAY:
79                 fprintf(stderr, "%*s%p array. elements not printed\n", indent*4, "",
80                                 (void*)info);
81                 break;
82
83         case ARGTYPE_POINTER:
84                 fprintf(stderr, "%*s%p pointer to...\n", indent*4, "", (void*)info);
85                 _dump_ltrace_tree(info->u.ptr_info.info, indent+1);
86                 break;
87
88         case ARGTYPE_STRUCT:
89                 fprintf(stderr, "%*s%p struct...\n", indent*4, "", (void*)info);
90                 struct struct_field
91                 {
92                         struct arg_type_info *info;
93                         int own_info;
94                 }* elements = (struct struct_field*)info->u.entries.data;
95                 unsigned int i;
96                 for(i=0; i<info->u.entries.size; i++)
97                         _dump_ltrace_tree(elements[i].info, indent+1);
98                 break;
99
100         default:
101                 fprintf(stderr, "%*s%p unknown type\n", indent*4, "", (void*)info);
102                 return false;;
103         }
104
105         return true;
106 }
107
108 static bool dump_ltrace_tree(const struct arg_type_info* info)
109 {
110         return _dump_ltrace_tree(info, 0);
111 }
112 #endif
113
114
115 // pulls a numerical value out of a particular attribute in a die. Returns true
116 // if successful. The result is returned in *result. Note that this is cast to
117 // (uint64_t), regardless of the actual type of the input
118 static bool get_die_numeric(uint64_t* result,
119                                                         Dwarf_Die *die, unsigned int attr_name)
120 {
121         Dwarf_Attribute attr ;
122
123         union {
124                 Dwarf_Word              udata;
125                 Dwarf_Sword     sdata;
126                 Dwarf_Addr              addr;
127                 bool                    flag;
128         } u;
129
130         if (dwarf_attr(die, attr_name, &attr) == NULL)
131                 return false;
132
133         unsigned int form = dwarf_whatform(&attr);
134
135 #define PROCESS_NUMERIC(type)                                           \
136         if (dwarf_form ## type(&attr, &u.type) != 0)    \
137                 return false;                                                           \
138         *result = (uint64_t)u.type;                                             \
139         return true
140
141
142         switch (form) {
143         case DW_FORM_addr:
144                 PROCESS_NUMERIC(addr);
145
146         case DW_FORM_data1:
147         case DW_FORM_data2:
148         case DW_FORM_data4:
149         case DW_FORM_data8:
150         case DW_FORM_udata:
151                 PROCESS_NUMERIC(udata);
152
153         case DW_FORM_sdata:
154                 PROCESS_NUMERIC(sdata);
155
156         case DW_FORM_flag:
157                 PROCESS_NUMERIC(flag);
158
159         default:
160                 complain(die, "Unknown numeric form %d for attr_name: %d", form, attr_name);
161                 return false;
162         }
163 #undef PROCESS_NUMERIC
164 }
165
166 static bool get_integer_base_type(enum arg_type* type, int byte_size, bool is_signed)
167 {
168         switch (byte_size) {
169         case sizeof(char):
170                 *type = ARGTYPE_CHAR;
171                 return true;
172
173         case sizeof(short):
174                 *type = is_signed ? ARGTYPE_SHORT : ARGTYPE_USHORT;
175                 return true;
176
177         case sizeof(int):
178                 *type = is_signed ? ARGTYPE_INT : ARGTYPE_UINT;
179                 return true;
180
181         case sizeof(long):
182                 *type = is_signed ? ARGTYPE_LONG : ARGTYPE_ULONG;
183                 return true;
184
185         default:
186                 return false;
187         }
188 }
189
190 // returns an ltrace ARGTYPE_XXX base type from the given die. If we dont
191 // support a particular type (or an error occurred), I regturn ARGTYPE_VOID
192 static enum arg_type get_base_type(Dwarf_Die* die)
193 {
194         int64_t encoding;
195         if(!get_die_numeric((uint64_t*)&encoding, die, DW_AT_encoding))
196                 return ARGTYPE_VOID;
197
198         if (encoding == DW_ATE_void)
199                 return ARGTYPE_VOID;
200
201         if (encoding == DW_ATE_signed_char || encoding == DW_ATE_unsigned_char)
202                 return ARGTYPE_CHAR;
203
204                 uint64_t byte_size;
205                 if (!get_die_numeric(&byte_size, die, DW_AT_byte_size))
206                         return ARGTYPE_VOID;
207
208         if (encoding == DW_ATE_signed   ||
209                 encoding == DW_ATE_unsigned ||
210                 encoding == DW_ATE_boolean) {
211
212                 bool is_signed = (encoding == DW_ATE_signed);
213
214                 enum arg_type type;
215                 if(!get_integer_base_type(&type, (int)byte_size, is_signed)) {
216                         complain(die, "Unknown integer base type. Using 'void'");
217                         return ARGTYPE_VOID;
218                 }
219                 return type;
220         }
221
222         if (encoding == DW_ATE_float) {
223                 switch (byte_size) {
224                 case sizeof(float):
225                         return ARGTYPE_FLOAT;
226
227                 case sizeof(double):
228                         return ARGTYPE_DOUBLE;
229
230                 default:
231                         // things like long doubles. ltrace has no support yet, so I just
232                         // say "void"
233                         return ARGTYPE_VOID;
234                 }
235         }
236
237 #if 0
238         if (encoding == DW_ATE_complex_float) {
239                 switch (byte_size) {
240                 case 2*sizeof(float):
241                         return ARGTYPE_FLOAT;
242
243                 case 2*sizeof(double):
244                         return ARGTYPE_DOUBLE;
245
246                 default:
247                         // things like long doubles. ltrace has no support yet, so I just
248                         // say "void"
249                         return ARGTYPE_VOID;
250                 }
251         }
252 #endif
253
254         // Unknown encoding. I just say void
255         complain(die, "Unknown base type. Returning 'void'");
256         return ARGTYPE_VOID;
257 }
258
259 static bool get_type_die(Dwarf_Die* type_die, Dwarf_Die* die)
260 {
261         Dwarf_Attribute attr;
262         return
263                 dwarf_attr(die, DW_AT_type, &attr) != NULL &&
264                 dwarf_formref_die(&attr, type_die) != NULL;
265 }
266
267
268
269 // type_dieoffset_hash dictionary callbacks
270 static size_t dwarf_die_hash(const void* x)
271 {
272         return *(const Dwarf_Off*)x;
273 }
274 static int dwarf_die_eq(const void* a, const void* b)
275 {
276         return *(const Dwarf_Off*)a == *(const Dwarf_Off*)b;
277 }
278
279
280 // returns a newly-allocated art_type_info*, or NULL on error
281 static struct arg_type_info* get_enum(Dwarf_Die* parent, struct dict* type_dieoffset_hash)
282 {
283
284 #define CLEANUP_AND_RETURN_ERROR(ret) do {                                                              \
285                 if(dupkey != NULL)                                                                                              \
286                         free((void*)dupkey);                                                                            \
287                 if(value != NULL) {                                                                                             \
288                         value_destroy(value);                                                                           \
289                         free(value);                                                                                            \
290                 }                                                                                                                               \
291                 if(lens != NULL ) {                                                                                             \
292                         lens_destroy(&lens->super);                                                                     \
293                         free(lens);                                                                                                     \
294                 }                                                                                                                               \
295                 if(result != NULL) {                                                                                    \
296                         type_destroy(result);                                                                           \
297                         free(result);                                                                                           \
298                 }                                                                                                                               \
299                 dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \
300                 dict_insert(type_dieoffset_hash, &die_offset,                                   \
301                                         &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \
302                 return ret;                                                                                                             \
303         } while(0)
304
305         struct arg_type_info*           result = NULL;
306         struct enum_lens*                       lens   = NULL;
307         const char*                                     dupkey = NULL;
308         struct value*                           value  = NULL;
309
310         Dwarf_Off die_offset = dwarf_dieoffset(parent);
311
312         result = calloc(1, sizeof(struct arg_type_info));
313         if (result == NULL) {
314                 complain(parent, "alloc error");
315                 CLEANUP_AND_RETURN_ERROR(NULL);
316         }
317
318         dict_insert(type_dieoffset_hash, &die_offset, &result);
319
320         uint64_t byte_size;
321         if (!get_die_numeric(&byte_size, parent, DW_AT_byte_size)) {
322                 // No byte size given, assume 'int'
323                 result->type = ARGTYPE_INT;
324         } else {
325                 if(!get_integer_base_type(&result->type, (int)byte_size, true)) {
326                         complain(parent, "Unknown integer base type. Using 'int'");
327                         result->type = ARGTYPE_INT;
328                 }
329         }
330
331         lens = calloc(1, sizeof(struct enum_lens));
332         if (lens == NULL) {
333                 complain(parent, "alloc error");
334                 CLEANUP_AND_RETURN_ERROR(NULL);
335         }
336         lens_init_enum(lens);
337         result->lens            = &lens->super;
338         result->own_lens = 1;
339
340         Dwarf_Die die;
341         if (dwarf_child(parent, &die) != 0) {
342                 // empty enum. we're done
343                 CLEANUP_AND_RETURN_ERROR(NULL);
344         }
345
346
347         while(1) {
348                 complain(&die, "enum element: 0x%02x/'%s'", dwarf_tag(&die),
349                                  dwarf_diename(&die));
350
351                 dupkey = NULL;
352                 value  = NULL;
353
354                 if (dwarf_tag(&die) != DW_TAG_enumerator) {
355                         complain(&die, "Enums can have ONLY DW_TAG_enumerator elements");
356                         CLEANUP_AND_RETURN_ERROR(NULL);
357                 }
358
359                 if (!dwarf_hasattr(&die, DW_AT_const_value)) {
360                         complain(&die, "Enums MUST have DW_AT_const_value values");
361                         CLEANUP_AND_RETURN_ERROR(NULL);
362                 }
363
364                 const char* key = dwarf_diename(&die);
365                 if (key == NULL) {
366                         complain(&die, "Enums must have a DW_AT_name key");
367                         CLEANUP_AND_RETURN_ERROR(NULL);
368                 }
369                 dupkey = strdup(key);
370                 if (dupkey == NULL) {
371                         complain(&die, "Couldn't duplicate enum key");
372                         CLEANUP_AND_RETURN_ERROR(NULL);
373                 }
374
375                 value = calloc(1, sizeof(struct value));
376                 if (value == NULL) {
377                         complain(&die, "Couldn't alloc enum value");
378                         CLEANUP_AND_RETURN_ERROR(NULL);
379                 }
380
381                 value_init_detached(value, NULL, type_get_simple(result->type), 0);
382                 uint64_t enum_value;
383                 if (!get_die_numeric(&enum_value, &die, DW_AT_const_value)) {
384                         complain(&die, "Couldn't get enum value");
385                         CLEANUP_AND_RETURN_ERROR(NULL);
386                 }
387
388                 value_set_word(value, (long)enum_value);
389
390                 if (lens_enum_add(lens, dupkey, 1, value, 1)) {
391                         complain(&die, "Couldn't add enum element");
392                         CLEANUP_AND_RETURN_ERROR(NULL);
393                 }
394
395                 NEXT_SIBLING(&die);
396         }
397
398         return result;
399
400 #undef CLEANUP_AND_RETURN_ERROR
401 }
402
403 // returns a newly-allocated art_type_info*, or NULL on error
404 static struct arg_type_info* get_array( Dwarf_Die* parent, struct protolib* plib,
405                                                                                 struct dict* type_dieoffset_hash)
406 {
407
408 #define CLEANUP_AND_RETURN_ERROR(ret) do {                                                              \
409                 if(length != NULL) {                                                                                    \
410                         expr_destroy(length);                                                                           \
411                         free(length);                                                                                           \
412                 }                                                                                                                               \
413                 if(array_type != NULL && newly_allocated_array_type) {                  \
414                         type_destroy(array_type);                                                                       \
415                         free(array_type);                                                                                       \
416                 }                                                                                                                               \
417                 if(result != NULL) {                                                                                    \
418                         type_destroy(result);                                                                           \
419                         free(result);                                                                                           \
420                 }                                                                                                                               \
421                 dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \
422                 dict_insert(type_dieoffset_hash, &die_offset,                                   \
423                                         &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \
424                 return ret;                                                                                                             \
425         } while(0)
426
427
428         struct arg_type_info*           result                                     = NULL;
429         struct expr_node*                       length                                     = NULL;
430         struct arg_type_info*           array_type                                 = NULL;
431         int                                                     newly_allocated_array_type = 0;
432
433         Dwarf_Off die_offset = dwarf_dieoffset(parent);
434
435         result = calloc(1, sizeof(struct arg_type_info));
436         if (result == NULL) {
437                 complain(parent, "alloc error");
438                 CLEANUP_AND_RETURN_ERROR(NULL);
439         }
440
441         Dwarf_Die type_die;
442         if (!get_type_die(&type_die, parent)) {
443                 complain(parent, "Array has unknown type");
444                 CLEANUP_AND_RETURN_ERROR(NULL);
445         }
446
447         dict_insert(type_dieoffset_hash, &die_offset, &result);
448         array_type = get_type(&newly_allocated_array_type,
449                                                   &type_die, plib, type_dieoffset_hash);
450         if( array_type == NULL ) {
451                 complain(parent, "Couldn't figure out array's type");
452                 CLEANUP_AND_RETURN_ERROR(NULL);
453         }
454
455         Dwarf_Die subrange;
456         if (dwarf_child(parent, &subrange) != 0) {
457                 complain(parent,
458                                  "Array must have a DW_TAG_subrange_type child, but has none");
459                 CLEANUP_AND_RETURN_ERROR(NULL);
460         }
461
462         Dwarf_Die next_subrange;
463         if (dwarf_siblingof(&subrange, &next_subrange) <= 0) {
464                 complain(parent,
465                                  "Array must have exactly one DW_TAG_subrange_type child");
466                 CLEANUP_AND_RETURN_ERROR(NULL);
467         }
468
469         if (dwarf_hasattr(&subrange, DW_AT_lower_bound)) {
470                 uint64_t lower_bound;
471                 if (!get_die_numeric(&lower_bound, &subrange, DW_AT_lower_bound)) {
472                         complain(parent, "Couldn't read lower bound");
473                         CLEANUP_AND_RETURN_ERROR(NULL);
474                 }
475
476                 if (lower_bound != 0) {
477                         complain(parent,
478                                           "Array subrange has a nonzero lower bound. Don't know what to do");
479                         CLEANUP_AND_RETURN_ERROR(NULL);
480                 }
481         }
482
483         uint64_t N;
484         if (!dwarf_hasattr(&subrange, DW_AT_upper_bound)) {
485                 // no upper bound is defined. This is probably a variable-width array,
486                 // and I don't know how long it is. Let's say 0 to be safe
487                 N = 0;
488         }
489         else
490         {
491                 if (!get_die_numeric(&N, &subrange, DW_AT_upper_bound)) {
492                         complain(parent, "Couldn't read upper bound");
493                         CLEANUP_AND_RETURN_ERROR(NULL);
494                 }
495                 N++;
496         }
497
498         // I'm not checking the subrange type. It should be some sort of integer,
499         // and I don't know what it would mean for it to be something else
500         length = calloc(1, sizeof(struct expr_node));
501         if (length == NULL) {
502                 complain(&subrange, "Couldn't alloc length expr");
503                 CLEANUP_AND_RETURN_ERROR(NULL);
504         }
505         expr_init_const_word(length, N, type_get_simple(ARGTYPE_INT), 0);
506
507         type_init_array(result, array_type, newly_allocated_array_type,
508                                         length, 1);
509         return result;
510
511 #undef CLEANUP_AND_RETURN_ERROR
512 }
513
514 // returns a newly-allocated art_type_info*, or NULL on error
515 static struct arg_type_info* get_structure(Dwarf_Die* parent, struct protolib* plib,
516                                                                                    struct dict* type_dieoffset_hash)
517 {
518
519 #define CLEANUP_AND_RETURN_ERROR(ret) do {                                                              \
520                 if(member_type != NULL && newly_allocated_member_type) {                \
521                         type_destroy(member_type);                                                                      \
522                         free(member_type);                                                                                      \
523                 }                                                                                                                               \
524                 if(result != NULL) {                                                                                    \
525                         type_destroy(result);                                                                           \
526                         free(result);                                                                                           \
527                 }                                                                                                                               \
528                 dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \
529                 dict_insert(type_dieoffset_hash, &die_offset,                                   \
530                                         &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \
531                 return ret;                                                                                                             \
532         } while(0)
533
534
535         struct arg_type_info*           result                                          = NULL;
536         struct arg_type_info*           member_type                                     = NULL;
537         int                                                     newly_allocated_member_type = 0;
538
539         Dwarf_Off die_offset = dwarf_dieoffset(parent);
540
541         result = calloc(1, sizeof(struct arg_type_info));
542         if (result == NULL) {
543                 complain(parent, "alloc error");
544                 CLEANUP_AND_RETURN_ERROR(NULL);
545         }
546         type_init_struct(result);
547         dict_insert(type_dieoffset_hash, &die_offset, &result);
548
549         Dwarf_Die die;
550         if (dwarf_child(parent, &die) != 0) {
551                 // no elements; we're done
552                 return result;
553         }
554
555         while(1) {
556                 member_type                                     = NULL;
557                 newly_allocated_member_type = 0;
558
559                 complain(&die, "member: 0x%02x", dwarf_tag(&die));
560
561                 if (dwarf_tag(&die) != DW_TAG_member) {
562                         complain(&die, "Structure can have ONLY DW_TAG_member");
563                         CLEANUP_AND_RETURN_ERROR(NULL);
564                 }
565
566                 Dwarf_Die type_die;
567                 if (!get_type_die(&type_die, &die)) {
568                         complain(&die, "Couldn't get type of element");
569                         CLEANUP_AND_RETURN_ERROR(NULL);
570                 }
571
572                 member_type = get_type(&newly_allocated_member_type,
573                                                            &type_die, plib, type_dieoffset_hash);
574                 if(member_type == NULL) {
575                         complain(&die, "Couldn't parse type from DWARF data");
576                         CLEANUP_AND_RETURN_ERROR(NULL);
577                 }
578                 type_struct_add(result, member_type, newly_allocated_member_type);
579
580                 NEXT_SIBLING(&die);
581         }
582
583         return result;
584 #undef CLEANUP_AND_RETURN_ERROR
585 }
586
587 // Reads the type in the die and returns the corresponding arg_type_info*. If
588 // this was newly allocated on the heap, *newly_allocated_info = true. If an
589 // error occurred, returns NULL
590 static struct arg_type_info* get_type(int* newly_allocated_result,
591                                                                           Dwarf_Die* type_die, struct protolib* plib,
592                                                                           struct dict* type_dieoffset_hash)
593 {
594
595 #define CLEANUP_AND_RETURN_ERROR(ret) do {                                                              \
596                 if(pointee != NULL && newly_allocated_pointee) {                                \
597                         type_destroy(pointee);                                                                          \
598                         free(pointee);                                                                                          \
599                 }                                                                                                                               \
600                 if(result != NULL && *newly_allocated_result) {                                 \
601                         type_destroy(result);                                                                           \
602                         free(result);                                                                                           \
603                 }                                                                                                                               \
604                 dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \
605                 dict_insert(type_dieoffset_hash, &die_offset,                                   \
606                                         &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \
607                 return ret;                                                                                                             \
608         } while(0)
609
610         struct arg_type_info*           result                                  = NULL;
611         struct arg_type_info*           pointee                                 = NULL;
612         int                                                     newly_allocated_pointee = 0;
613
614         Dwarf_Off die_offset = dwarf_dieoffset(type_die);
615
616
617     // by default, we say we allocated nothing. I set this to true later, when I
618     // allocate memory
619     *newly_allocated_result = 0;
620
621         struct arg_type_info** found_type = dict_find(type_dieoffset_hash, &die_offset);
622         if (found_type != NULL) {
623                 complain(type_die, "Read pre-computed type");
624                 return *found_type;
625         }
626
627         const char* type_name = dwarf_diename(type_die);
628         if (type_name != NULL) {
629
630                 struct named_type* already_defined_type =
631                         protolib_lookup_type(plib, type_name, true);
632
633                 if (already_defined_type != NULL) {
634                         complain(type_die,
635                                          "Type '%s' defined in a .conf file. Using that instead of DWARF",
636                                          type_name);
637                         return already_defined_type->info;
638                 }
639         }
640
641         Dwarf_Die next_die;
642
643         switch (dwarf_tag(type_die)) {
644         case DW_TAG_base_type:
645                 complain(type_die, "Storing base type");
646                 result = type_get_simple(get_base_type(type_die));
647                 dict_insert(type_dieoffset_hash, &die_offset, &result);
648                 return result;
649
650         case DW_TAG_subroutine_type:
651         case DW_TAG_inlined_subroutine:
652                 // function pointers are stored as void*. If ltrace tries to dereference
653                 // these, it'll get a segfault
654                 complain(type_die, "Storing subroutine type");
655                 result = type_get_simple(ARGTYPE_VOID);
656                 dict_insert(type_dieoffset_hash, &die_offset, &result);
657                 return result;
658
659         case DW_TAG_pointer_type:
660                 if (!get_type_die(&next_die, type_die)) {
661                         // the pointed-to type isn't defined, so I report a void*
662                         complain(type_die, "Storing void-pointer type");
663                         result = type_get_voidptr();
664                         dict_insert(type_dieoffset_hash, &die_offset, &result);
665                         return result;
666                 }
667
668                 complain(type_die, "Storing pointer type");
669
670                 *newly_allocated_result = 1;
671                 result = calloc(1, sizeof(struct arg_type_info));
672                 if (result == NULL) {
673                         complain(type_die, "alloc error");
674                         CLEANUP_AND_RETURN_ERROR(NULL);
675                 }
676                 dict_insert(type_dieoffset_hash, &die_offset, &result);
677                 pointee = get_type(&newly_allocated_pointee,
678                                                    &next_die, plib, type_dieoffset_hash);
679                 if(pointee == NULL)
680                         CLEANUP_AND_RETURN_ERROR(NULL);
681
682                 type_init_pointer(result, pointee, newly_allocated_pointee);
683                 return result;
684
685         case DW_TAG_structure_type:
686                 complain(type_die, "Storing struct type");
687                 *newly_allocated_result = 1;
688
689                 result = get_structure(type_die, plib, type_dieoffset_hash);
690                 if(result == NULL)
691                         CLEANUP_AND_RETURN_ERROR(NULL);
692                 return result;
693
694
695         case DW_TAG_typedef:
696         case DW_TAG_const_type:
697         case DW_TAG_volatile_type:
698                 // Various tags are simply pass-through, so I just keep going
699                 if (get_type_die(&next_die, type_die)) {
700                         complain(type_die, "Storing const/typedef type");
701
702                         result = get_type(newly_allocated_result, &next_die,
703                                                           plib, type_dieoffset_hash);
704                         if(result == NULL)
705                                 CLEANUP_AND_RETURN_ERROR(NULL);
706                 } else {
707                         // no type. Use 'void'. Normally I'd think this is bogus, but stdio
708                         // typedefs something to void
709                         result = type_get_simple(ARGTYPE_VOID);
710                         complain(type_die, "Storing void type");
711                 }
712                 dict_insert(type_dieoffset_hash, &die_offset, &result);
713                 return result;
714
715         case DW_TAG_enumeration_type:
716                 // We have an enumeration. This has a base type, but has a particular
717                 // lens to handle the enum
718                 *newly_allocated_result = 1;
719
720                 complain(type_die, "Storing enum int");
721                 result = get_enum(type_die, type_dieoffset_hash);
722                 if(result == NULL)
723                         CLEANUP_AND_RETURN_ERROR(NULL);
724                 return result;
725
726         case DW_TAG_array_type:
727                 *newly_allocated_result = 1;
728
729                 complain(type_die, "Storing array");
730                 result = get_array(type_die, plib, type_dieoffset_hash);
731                 if(result == NULL)
732                         CLEANUP_AND_RETURN_ERROR(NULL);
733                 return result;
734
735         case DW_TAG_union_type:
736                 result = type_get_simple(ARGTYPE_VOID);
737                 complain(type_die, "Storing union-as-void type");
738                 dict_insert(type_dieoffset_hash, &die_offset, &result);
739                 return result;
740
741         default:
742                 complain(type_die, "Unknown type tag 0x%x. Returning void", dwarf_tag(type_die));
743                 result = type_get_simple(ARGTYPE_VOID);
744                 dict_insert(type_dieoffset_hash, &die_offset, &result);
745                 return result;
746         }
747
748 #undef CLEANUP_AND_RETURN_ERROR
749 }
750
751 // fills in *proto with a prototype. Returns true on success
752 static bool get_prototype( struct prototype* result,
753                                                    Dwarf_Die* subroutine, struct protolib* plib,
754                                                    struct dict* type_dieoffset_hash)
755 {
756
757 #define CLEANUP_AND_RETURN_ERROR(ret) do {              \
758                 if(argument_type != NULL && newly_allocated_argument_type) {    \
759                         type_destroy(argument_type);            \
760                         free(argument_type);                            \
761                 }                                                                               \
762                 prototype_destroy(result);                              \
763                 return ret;                                                             \
764         } while(0)
765
766
767         struct arg_type_info*           argument_type                             = NULL;
768         int                                                     newly_allocated_argument_type = 0;
769
770         prototype_init(result);
771
772         // First, look at the return type. This is stored in a DW_AT_type tag in the
773         // subroutine DIE. If there is no such tag, this function returns void
774         Dwarf_Die return_type_die;
775         if (!get_type_die(&return_type_die, subroutine)) {
776                 result->return_info = type_get_simple(ARGTYPE_VOID);
777                 result->own_return_info = 0;
778         } else {
779                 int newly_allocated_return_type;
780                 result->return_info = get_type(&newly_allocated_return_type,
781                                                                            &return_type_die, plib, type_dieoffset_hash);
782                 if(result->return_info == NULL) {
783                         complain(subroutine, "Couldn't get return type");
784                         CLEANUP_AND_RETURN_ERROR(false);
785                 }
786                 result->own_return_info = newly_allocated_return_type;
787         }
788
789
790         // Now look at the arguments
791         Dwarf_Die arg_die;
792         if (dwarf_child(subroutine, &arg_die) != 0) {
793                 // no args. We're done
794                 return true;
795         }
796
797         while(1) {
798                 if (dwarf_tag(&arg_die) == DW_TAG_formal_parameter) {
799
800                         complain(&arg_die, "arg: 0x%02x", dwarf_tag(&arg_die));
801
802                         argument_type                             = NULL;
803                         newly_allocated_argument_type = false;
804
805                         Dwarf_Die type_die;
806                         if (!get_type_die(&type_die, &arg_die)) {
807                                 complain(&arg_die, "Couldn't get the argument type die");
808                                 CLEANUP_AND_RETURN_ERROR(false);
809                         }
810
811
812                         argument_type = get_type(&newly_allocated_argument_type,
813                                                                          &type_die, plib, type_dieoffset_hash);
814                         if(argument_type==NULL) {
815                                 complain(&arg_die, "Couldn't parse arg type from DWARF data");
816                                 CLEANUP_AND_RETURN_ERROR(false);
817                         }
818
819                         struct param param;
820                         param_init_type(&param, argument_type, newly_allocated_argument_type);
821                         if (prototype_push_param(result, &param) <0) {
822                                 complain(&arg_die, "couldn't add argument to the prototype");
823                                 CLEANUP_AND_RETURN_ERROR(false);
824                         }
825
826 #ifdef DUMP_PROTOTYPES
827                         fprintf(stderr, "Adding argument:\n");
828                         dump_ltrace_tree(argument_type);
829 #endif
830                 }
831
832                 NEXT_SIBLING(&arg_die);
833         }
834
835         return true;
836 #undef CLEANUP_AND_RETURN_ERROR
837 }
838
839 static bool import_subprogram(struct protolib* plib, struct library* lib,
840                                                           struct dict* type_dieoffset_hash,
841                                                           Dwarf_Die* die)
842 {
843         // I use the linkage function name if there is one, otherwise the
844         // plain name
845         const char* function_name = NULL;
846         Dwarf_Attribute attr;
847         if (dwarf_attr(die, DW_AT_linkage_name, &attr) != NULL)
848                 function_name = dwarf_formstring(&attr);
849         if (function_name == NULL)
850                 function_name = dwarf_diename(die);
851         if (function_name == NULL) {
852                 complain(die, "Function has no name. Not importing");
853                 return true;
854         }
855
856         if (!filter_matches_symbol(options.plt_filter,    function_name, lib) &&
857                 !filter_matches_symbol(options.static_filter, function_name, lib) &&
858                 !filter_matches_symbol(options.export_filter, function_name, lib)) {
859                 complain(die, "Prototype not requested by any filter");
860                 return true;
861         }
862
863         complain(die, "subroutine_type: 0x%02x; function '%s'",
864                          dwarf_tag(die), function_name);
865
866         struct prototype* proto_already_there =
867                 protolib_lookup_prototype(plib, function_name, false);
868
869         if (proto_already_there != NULL) {
870                 complain(die, "Prototype already exists. Skipping");
871                 return true;
872         }
873
874         struct prototype proto;
875         if(!get_prototype(&proto, die, plib, type_dieoffset_hash)) {
876                 complain(die, "couldn't get prototype");
877                 return false;
878         }
879
880         const char* function_name_dup = strdup(function_name);
881         if( function_name_dup == NULL ) {
882                 complain(die, "couldn't strdup");
883                 prototype_destroy(&proto);
884                 return false;
885         }
886         protolib_add_prototype(plib, function_name_dup, 1, &proto);
887         return true;
888 }
889
890 static bool process_die_compileunit(struct protolib* plib, struct library* lib,
891                                                                         struct dict* type_dieoffset_hash,
892                                                                         Dwarf_Die* parent)
893 {
894         Dwarf_Die die;
895         if (dwarf_child(parent, &die) != 0) {
896                 // no child nodes, so nothing to do
897                 return true;
898         }
899
900         while (1) {
901                 if (dwarf_tag(&die) == DW_TAG_subprogram)
902                         if(!import_subprogram(plib, lib, type_dieoffset_hash, &die))
903                                 complain(&die, "Error importing subprogram. Skipping");
904
905                 NEXT_SIBLING(&die);
906         }
907
908         return true;
909 }
910
911 static void import(struct protolib* plib, struct library* lib, Dwfl* dwfl)
912 {
913         // A map from DIE addresses (Dwarf_Off) to type structures (struct
914         // arg_type_info*). This is created and filled in at the start of each
915         // import, and deleted when the import is complete
916         struct dict type_dieoffset_hash;
917
918         dict_init(&type_dieoffset_hash, sizeof(Dwarf_Off), sizeof(struct arg_type_info*),
919                           dwarf_die_hash, dwarf_die_eq, NULL);
920
921         Dwarf_Addr bias;
922     Dwarf_Die* die = NULL;
923     while ((die = dwfl_nextcu(dwfl, die, &bias)) != NULL) {
924         if (dwarf_tag(die) == DW_TAG_compile_unit)
925                         process_die_compileunit(plib, lib, &type_dieoffset_hash, die);
926                 else
927             complain(die, "A DW_TAG_compile_unit die expected. Skipping this one");
928     }
929
930         dict_destroy(&type_dieoffset_hash, NULL, NULL, NULL);
931 }
932
933 bool import_DWARF_prototypes(struct library* lib)
934 {
935         struct protolib*        plib = lib->protolib;
936         Dwfl*                           dwfl = lib->dwfl;
937
938         debug(DEBUG_FUNCTION, "Importing DWARF prototypes from '%s'", lib->soname);
939         if (plib == NULL) {
940
941                 const char* soname_dup = strdup(lib->soname);
942                 if( soname_dup == NULL ) {
943                         fprintf(stderr, "couldn't strdup");
944                         return false;
945                 }
946
947                 plib = protolib_cache_default(&g_protocache, soname_dup, 1);
948                 if (plib == NULL) {
949                         fprintf(stderr, "Error loading protolib %s: %s.\n",
950                                         lib->soname, strerror(errno));
951                 }
952         }
953
954         import(plib, lib, dwfl);
955         lib->protolib = plib;
956
957         return true;
958 }