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