fixed prototype memory leak
[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(value != NULL) {                                                                                             \
410                         value_destroy(value);                                                                           \
411                         free(value);                                                                                            \
412                 }                                                                                                                               \
413                 if(length != NULL) {                                                                                    \
414                         expr_destroy(length);                                                                           \
415                         free(length);                                                                                           \
416                 }                                                                                                                               \
417                 if(array_type != NULL && newly_allocated_array_type) {                  \
418                         type_destroy(array_type);                                                                       \
419                         free(array_type);                                                                                       \
420                 }                                                                                                                               \
421                 if(result != NULL) {                                                                                    \
422                         type_destroy(result);                                                                           \
423                         free(result);                                                                                           \
424                 }                                                                                                                               \
425                 dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \
426                 dict_insert(type_dieoffset_hash, &die_offset,                                   \
427                                         &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \
428                 return ret;                                                                                                             \
429         } while(0)
430
431
432         struct arg_type_info*           result                                     = NULL;
433         struct value*                           value                                      = NULL;
434         struct expr_node*                       length                                     = NULL;
435         struct arg_type_info*           array_type                                 = NULL;
436         int                                                     newly_allocated_array_type = 0;
437
438         Dwarf_Off die_offset = dwarf_dieoffset(parent);
439
440         result = calloc(1, sizeof(struct arg_type_info));
441         if (result == NULL) {
442                 complain(parent, "alloc error");
443                 CLEANUP_AND_RETURN_ERROR(NULL);
444         }
445
446         Dwarf_Die type_die;
447         if (!get_type_die(&type_die, parent)) {
448                 complain(parent, "Array has unknown type");
449                 CLEANUP_AND_RETURN_ERROR(NULL);
450         }
451
452         dict_insert(type_dieoffset_hash, &die_offset, &result);
453         array_type = get_type(&newly_allocated_array_type,
454                                                   &type_die, plib, type_dieoffset_hash);
455         if( array_type == NULL ) {
456                 complain(parent, "Couldn't figure out array's type");
457                 CLEANUP_AND_RETURN_ERROR(NULL);
458         }
459
460         Dwarf_Die subrange;
461         if (dwarf_child(parent, &subrange) != 0) {
462                 complain(parent,
463                                  "Array must have a DW_TAG_subrange_type child, but has none");
464                 CLEANUP_AND_RETURN_ERROR(NULL);
465         }
466
467         Dwarf_Die next_subrange;
468         if (dwarf_siblingof(&subrange, &next_subrange) <= 0) {
469                 complain(parent,
470                                  "Array must have exactly one DW_TAG_subrange_type child");
471                 CLEANUP_AND_RETURN_ERROR(NULL);
472         }
473
474         if (dwarf_hasattr(&subrange, DW_AT_lower_bound)) {
475                 uint64_t lower_bound;
476                 if (!get_die_numeric(&lower_bound, &subrange, DW_AT_lower_bound)) {
477                         complain(parent, "Couldn't read lower bound");
478                         CLEANUP_AND_RETURN_ERROR(NULL);
479                 }
480
481                 if (lower_bound != 0) {
482                         complain(parent,
483                                           "Array subrange has a nonzero lower bound. Don't know what to do");
484                         CLEANUP_AND_RETURN_ERROR(NULL);
485                 }
486         }
487
488         uint64_t N;
489         if (!dwarf_hasattr(&subrange, DW_AT_upper_bound)) {
490                 // no upper bound is defined. This is probably a variable-width array,
491                 // and I don't know how long it is. Let's say 0 to be safe
492                 N = 0;
493         }
494         else
495         {
496                 if (!get_die_numeric(&N, &subrange, DW_AT_upper_bound)) {
497                         complain(parent, "Couldn't read upper bound");
498                         CLEANUP_AND_RETURN_ERROR(NULL);
499                 }
500                 N++;
501         }
502
503         // I'm not checking the subrange type. It should be some sort of integer,
504         // and I don't know what it would mean for it to be something else
505
506         value = calloc(1, sizeof(struct value));
507         if (value == NULL) {
508                 complain(&subrange, "Couldn't alloc length value");
509                 CLEANUP_AND_RETURN_ERROR(NULL);
510         }
511         value_init_detached(value, NULL, type_get_simple(ARGTYPE_INT), 0);
512         value_set_word(value, N);
513
514         length = calloc(1, sizeof(struct expr_node));
515         if (length == NULL) {
516                 complain(&subrange, "Couldn't alloc length expr");
517                 CLEANUP_AND_RETURN_ERROR(NULL);
518         }
519         expr_init_const(length, value);
520
521         type_init_array(result, array_type, newly_allocated_array_type,
522                                         length, 1);
523         return result;
524
525 #undef CLEANUP_AND_RETURN_ERROR
526 }
527
528 // returns a newly-allocated art_type_info*, or NULL on error
529 static struct arg_type_info* get_structure(Dwarf_Die* parent, struct protolib* plib,
530                                                                                    struct dict* type_dieoffset_hash)
531 {
532
533 #define CLEANUP_AND_RETURN_ERROR(ret) do {                                                              \
534                 if(member_type != NULL && newly_allocated_member_type) {                \
535                         type_destroy(member_type);                                                                      \
536                         free(member_type);                                                                                      \
537                 }                                                                                                                               \
538                 if(result != NULL) {                                                                                    \
539                         type_destroy(result);                                                                           \
540                         free(result);                                                                                           \
541                 }                                                                                                                               \
542                 dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \
543                 dict_insert(type_dieoffset_hash, &die_offset,                                   \
544                                         &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \
545                 return ret;                                                                                                             \
546         } while(0)
547
548
549         struct arg_type_info*           result                                          = NULL;
550         struct arg_type_info*           member_type                                     = NULL;
551         int                                                     newly_allocated_member_type = 0;
552
553         Dwarf_Off die_offset = dwarf_dieoffset(parent);
554
555         result = calloc(1, sizeof(struct arg_type_info));
556         if (result == NULL) {
557                 complain(parent, "alloc error");
558                 CLEANUP_AND_RETURN_ERROR(NULL);
559         }
560         type_init_struct(result);
561         dict_insert(type_dieoffset_hash, &die_offset, &result);
562
563         Dwarf_Die die;
564         if (dwarf_child(parent, &die) != 0) {
565                 // no elements; we're done
566                 return result;
567         }
568
569         while(1) {
570                 member_type                                     = NULL;
571                 newly_allocated_member_type = 0;
572
573                 complain(&die, "member: 0x%02x", dwarf_tag(&die));
574
575                 if (dwarf_tag(&die) != DW_TAG_member) {
576                         complain(&die, "Structure can have ONLY DW_TAG_member");
577                         CLEANUP_AND_RETURN_ERROR(NULL);
578                 }
579
580                 Dwarf_Die type_die;
581                 if (!get_type_die(&type_die, &die)) {
582                         complain(&die, "Couldn't get type of element");
583                         CLEANUP_AND_RETURN_ERROR(NULL);
584                 }
585
586                 member_type = get_type(&newly_allocated_member_type,
587                                                            &type_die, plib, type_dieoffset_hash);
588                 if(member_type == NULL) {
589                         complain(&die, "Couldn't parse type from DWARF data");
590                         CLEANUP_AND_RETURN_ERROR(NULL);
591                 }
592                 type_struct_add(result, member_type, newly_allocated_member_type);
593
594                 NEXT_SIBLING(&die);
595         }
596
597         return result;
598 #undef CLEANUP_AND_RETURN_ERROR
599 }
600
601 // Reads the type in the die and returns the corresponding arg_type_info*. If
602 // this was newly allocated on the heap, *newly_allocated_info = true. If an
603 // error occurred, returns NULL
604 static struct arg_type_info* get_type(int* newly_allocated_result,
605                                                                           Dwarf_Die* type_die, struct protolib* plib,
606                                                                           struct dict* type_dieoffset_hash)
607 {
608
609 #define CLEANUP_AND_RETURN_ERROR(ret) do {                                                              \
610                 if(pointee != NULL && newly_allocated_pointee) {                                \
611                         type_destroy(pointee);                                                                          \
612                         free(pointee);                                                                                          \
613                 }                                                                                                                               \
614                 if(result != NULL && *newly_allocated_result) {                                 \
615                         type_destroy(result);                                                                           \
616                         free(result);                                                                                           \
617                 }                                                                                                                               \
618                 dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \
619                 dict_insert(type_dieoffset_hash, &die_offset,                                   \
620                                         &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \
621                 return ret;                                                                                                             \
622         } while(0)
623
624         struct arg_type_info*           result                                  = NULL;
625         struct arg_type_info*           pointee                                 = NULL;
626         int                                                     newly_allocated_pointee = 0;
627
628         Dwarf_Off die_offset = dwarf_dieoffset(type_die);
629
630
631     // by default, we say we allocated nothing. I set this to true later, when I
632     // allocate memory
633     *newly_allocated_result = 0;
634
635         struct arg_type_info** found_type = dict_find(type_dieoffset_hash, &die_offset);
636         if (found_type != NULL) {
637                 complain(type_die, "Read pre-computed type");
638                 return *found_type;
639         }
640
641         const char* type_name = dwarf_diename(type_die);
642         if (type_name != NULL) {
643
644                 struct named_type* already_defined_type =
645                         protolib_lookup_type(plib, type_name, true);
646
647                 if (already_defined_type != NULL) {
648                         complain(type_die,
649                                          "Type '%s' defined in a .conf file. Using that instead of DWARF",
650                                          type_name);
651                         return already_defined_type->info;
652                 }
653         }
654
655         Dwarf_Die next_die;
656
657         switch (dwarf_tag(type_die)) {
658         case DW_TAG_base_type:
659                 complain(type_die, "Storing base type");
660                 result = type_get_simple(get_base_type(type_die));
661                 dict_insert(type_dieoffset_hash, &die_offset, &result);
662                 return result;
663
664         case DW_TAG_subroutine_type:
665         case DW_TAG_inlined_subroutine:
666                 // function pointers are stored as void*. If ltrace tries to dereference
667                 // these, it'll get a segfault
668                 complain(type_die, "Storing subroutine type");
669                 result = type_get_simple(ARGTYPE_VOID);
670                 dict_insert(type_dieoffset_hash, &die_offset, &result);
671                 return result;
672
673         case DW_TAG_pointer_type:
674                 if (!get_type_die(&next_die, type_die)) {
675                         // the pointed-to type isn't defined, so I report a void*
676                         complain(type_die, "Storing void-pointer type");
677                         result = type_get_voidptr();
678                         dict_insert(type_dieoffset_hash, &die_offset, &result);
679                         return result;
680                 }
681
682                 complain(type_die, "Storing pointer type");
683
684                 *newly_allocated_result = 1;
685                 result = calloc(1, sizeof(struct arg_type_info));
686                 if (result == NULL) {
687                         complain(type_die, "alloc error");
688                         CLEANUP_AND_RETURN_ERROR(NULL);
689                 }
690                 dict_insert(type_dieoffset_hash, &die_offset, &result);
691                 pointee = get_type(&newly_allocated_pointee,
692                                                    &next_die, plib, type_dieoffset_hash);
693                 if(pointee == NULL)
694                         CLEANUP_AND_RETURN_ERROR(NULL);
695
696                 type_init_pointer(result, pointee, newly_allocated_pointee);
697                 return result;
698
699         case DW_TAG_structure_type:
700                 complain(type_die, "Storing struct type");
701                 *newly_allocated_result = 1;
702
703                 result = get_structure(type_die, plib, type_dieoffset_hash);
704                 if(result == NULL)
705                         CLEANUP_AND_RETURN_ERROR(NULL);
706                 return result;
707
708
709         case DW_TAG_typedef:
710         case DW_TAG_const_type:
711         case DW_TAG_volatile_type:
712                 // Various tags are simply pass-through, so I just keep going
713                 if (get_type_die(&next_die, type_die)) {
714                         complain(type_die, "Storing const/typedef type");
715
716                         result = get_type(newly_allocated_result, &next_die,
717                                                           plib, type_dieoffset_hash);
718                         if(result == NULL)
719                                 CLEANUP_AND_RETURN_ERROR(NULL);
720                 } else {
721                         // no type. Use 'void'. Normally I'd think this is bogus, but stdio
722                         // typedefs something to void
723                         result = type_get_simple(ARGTYPE_VOID);
724                         complain(type_die, "Storing void type");
725                 }
726                 dict_insert(type_dieoffset_hash, &die_offset, &result);
727                 return result;
728
729         case DW_TAG_enumeration_type:
730                 // We have an enumeration. This has a base type, but has a particular
731                 // lens to handle the enum
732                 *newly_allocated_result = 1;
733
734                 complain(type_die, "Storing enum int");
735                 result = get_enum(type_die, type_dieoffset_hash);
736                 if(result == NULL)
737                         CLEANUP_AND_RETURN_ERROR(NULL);
738                 return result;
739
740         case DW_TAG_array_type:
741                 *newly_allocated_result = 1;
742
743                 complain(type_die, "Storing array");
744                 result = get_array(type_die, plib, type_dieoffset_hash);
745                 if(result == NULL)
746                         CLEANUP_AND_RETURN_ERROR(NULL);
747                 return result;
748
749         case DW_TAG_union_type:
750                 result = type_get_simple(ARGTYPE_VOID);
751                 complain(type_die, "Storing union-as-void type");
752                 dict_insert(type_dieoffset_hash, &die_offset, &result);
753                 return result;
754
755         default:
756                 complain(type_die, "Unknown type tag 0x%x. Returning void", dwarf_tag(type_die));
757                 result = type_get_simple(ARGTYPE_VOID);
758                 dict_insert(type_dieoffset_hash, &die_offset, &result);
759                 return result;
760         }
761
762 #undef CLEANUP_AND_RETURN_ERROR
763 }
764
765 // fills in *proto with a prototype. Returns true on success
766 static bool get_prototype( struct prototype* result,
767                                                    Dwarf_Die* subroutine, struct protolib* plib,
768                                                    struct dict* type_dieoffset_hash)
769 {
770
771 #define CLEANUP_AND_RETURN_ERROR(ret) do {              \
772                 if(argument_type != NULL && newly_allocated_argument_type) {    \
773                         type_destroy(argument_type);            \
774                         free(argument_type);                            \
775                 }                                                                               \
776                 prototype_destroy(result);                              \
777                 return ret;                                                             \
778         } while(0)
779
780
781         struct arg_type_info*           argument_type                             = NULL;
782         int                                                     newly_allocated_argument_type = 0;
783
784         prototype_init(result);
785
786         // First, look at the return type. This is stored in a DW_AT_type tag in the
787         // subroutine DIE. If there is no such tag, this function returns void
788         Dwarf_Die return_type_die;
789         if (!get_type_die(&return_type_die, subroutine)) {
790                 result->return_info = type_get_simple(ARGTYPE_VOID);
791                 result->own_return_info = 0;
792         } else {
793                 result->return_info = calloc(1, sizeof(struct arg_type_info));
794                 if (result->return_info == NULL) {
795                         complain(subroutine, "Couldn't alloc return type");
796                         CLEANUP_AND_RETURN_ERROR(false);
797                 }
798                 result->own_return_info = 1;
799
800                 int newly_allocated_return_type;
801                 result->return_info = get_type(&newly_allocated_return_type,
802                                                                            &return_type_die, plib, type_dieoffset_hash);
803                 if(result->return_info == NULL) {
804                         complain(subroutine, "Couldn't get return type");
805                         CLEANUP_AND_RETURN_ERROR(false);
806                 }
807                 result->own_return_info = newly_allocated_return_type;
808         }
809
810
811         // Now look at the arguments
812         Dwarf_Die arg_die;
813         if (dwarf_child(subroutine, &arg_die) != 0) {
814                 // no args. We're done
815                 return true;
816         }
817
818         while(1) {
819                 if (dwarf_tag(&arg_die) == DW_TAG_formal_parameter) {
820
821                         complain(&arg_die, "arg: 0x%02x", dwarf_tag(&arg_die));
822
823                         argument_type                             = NULL;
824                         newly_allocated_argument_type = false;
825
826                         Dwarf_Die type_die;
827                         if (!get_type_die(&type_die, &arg_die)) {
828                                 complain(&arg_die, "Couldn't get the argument type die");
829                                 CLEANUP_AND_RETURN_ERROR(false);
830                         }
831
832
833                         argument_type = get_type(&newly_allocated_argument_type,
834                                                                          &type_die, plib, type_dieoffset_hash);
835                         if(argument_type==NULL) {
836                                 complain(&arg_die, "Couldn't parse arg type from DWARF data");
837                                 CLEANUP_AND_RETURN_ERROR(false);
838                         }
839
840                         struct param param;
841                         param_init_type(&param, argument_type, newly_allocated_argument_type);
842                         if (prototype_push_param(result, &param) <0) {
843                                 complain(&arg_die, "couldn't add argument to the prototype");
844                                 CLEANUP_AND_RETURN_ERROR(false);
845                         }
846
847 #ifdef DUMP_PROTOTYPES
848                         fprintf(stderr, "Adding argument:\n");
849                         dump_ltrace_tree(argument_type);
850 #endif
851                 }
852
853                 NEXT_SIBLING(&arg_die);
854         }
855
856         return true;
857 #undef CLEANUP_AND_RETURN_ERROR
858 }
859
860 static bool import_subprogram(struct protolib* plib, struct library* lib,
861                                                           struct dict* type_dieoffset_hash,
862                                                           Dwarf_Die* die)
863 {
864         // I use the linkage function name if there is one, otherwise the
865         // plain name
866         const char* function_name = NULL;
867         Dwarf_Attribute attr;
868         if (dwarf_attr(die, DW_AT_linkage_name, &attr) != NULL)
869                 function_name = dwarf_formstring(&attr);
870         if (function_name == NULL)
871                 function_name = dwarf_diename(die);
872         if (function_name == NULL) {
873                 complain(die, "Function has no name. Not importing");
874                 return true;
875         }
876
877         if (!filter_matches_symbol(options.plt_filter,    function_name, lib) &&
878                 !filter_matches_symbol(options.static_filter, function_name, lib) &&
879                 !filter_matches_symbol(options.export_filter, function_name, lib)) {
880                 complain(die, "Prototype not requested by any filter");
881                 return true;
882         }
883
884         complain(die, "subroutine_type: 0x%02x; function '%s'",
885                          dwarf_tag(die), function_name);
886
887         struct prototype* proto_already_there =
888                 protolib_lookup_prototype(plib, function_name, false);
889
890         if (proto_already_there != NULL) {
891                 complain(die, "Prototype already exists. Skipping");
892                 return true;
893         }
894
895         struct prototype proto;
896         if(!get_prototype(&proto, die, plib, type_dieoffset_hash)) {
897                 complain(die, "couldn't get prototype");
898                 return false;
899         }
900
901         const char* function_name_dup = strdup(function_name);
902         if( function_name_dup == NULL ) {
903                 complain(die, "couldn't strdup");
904                 prototype_destroy(&proto);
905                 return false;
906         }
907         protolib_add_prototype(plib, function_name_dup, 1, &proto);
908         return true;
909 }
910
911 static bool process_die_compileunit(struct protolib* plib, struct library* lib,
912                                                                         struct dict* type_dieoffset_hash,
913                                                                         Dwarf_Die* parent)
914 {
915         Dwarf_Die die;
916         if (dwarf_child(parent, &die) != 0) {
917                 // no child nodes, so nothing to do
918                 return true;
919         }
920
921         while (1) {
922                 if (dwarf_tag(&die) == DW_TAG_subprogram)
923                         if(!import_subprogram(plib, lib, type_dieoffset_hash, &die))
924                                 complain(&die, "Error importing subprogram. Skipping");
925
926                 NEXT_SIBLING(&die);
927         }
928
929         return true;
930 }
931
932 static void import(struct protolib* plib, struct library* lib, Dwfl* dwfl)
933 {
934         // A map from DIE addresses (Dwarf_Off) to type structures (struct
935         // arg_type_info*). This is created and filled in at the start of each
936         // import, and deleted when the import is complete
937         struct dict type_dieoffset_hash;
938
939         dict_init(&type_dieoffset_hash, sizeof(Dwarf_Off), sizeof(struct arg_type_info*),
940                           dwarf_die_hash, dwarf_die_eq, NULL);
941
942         Dwarf_Addr bias;
943     Dwarf_Die* die = NULL;
944     while ((die = dwfl_nextcu(dwfl, die, &bias)) != NULL) {
945         if (dwarf_tag(die) == DW_TAG_compile_unit)
946                         process_die_compileunit(plib, lib, &type_dieoffset_hash, die);
947                 else
948             complain(die, "A DW_TAG_compile_unit die expected. Skipping this one");
949     }
950
951         dict_destroy(&type_dieoffset_hash, NULL, NULL, NULL);
952 }
953
954 bool import_DWARF_prototypes(struct library* lib)
955 {
956         struct protolib*        plib = lib->protolib;
957         Dwfl*                           dwfl = lib->dwfl;
958
959         if (plib == NULL) {
960
961                 const char* soname_dup = strdup(lib->soname);
962                 if( soname_dup == NULL ) {
963                         fprintf(stderr, "couldn't strdup");
964                         return false;
965                 }
966
967                 plib = protolib_cache_default(&g_protocache, soname_dup, 1);
968                 if (plib == NULL) {
969                         fprintf(stderr, "Error loading protolib %s: %s.\n",
970                                         lib->soname, strerror(errno));
971                 }
972         }
973
974         import(plib, lib, dwfl);
975         lib->protolib = plib;
976
977         return true;
978 }