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