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