1 /* Copyright Dima Kogan <dima@secretsauce.net>
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.
9 #include <elfutils/libdwfl.h>
16 #include "prototype.h"
21 #include "lens_enum.h"
29 //#define DUMP_PROTOTYPES
31 #define complain(die, format, ...) \
32 debug(DEBUG_FUNCTION, "%s() die '%s' @ 0x%lx: " format, \
33 __func__, dwarf_diename(die), dwarf_dieoffset(die), \
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 */
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);
48 static bool _dump_dwarf_tree(Dwarf_Die* die, int indent)
51 fprintf(stderr, "%*sprocessing unit: 0x%02x/'%s'\n", indent*4, "",
52 dwarf_tag(die), dwarf_diename(die));
55 if (dwarf_child(die, &child) == 0) {
56 if (!_dump_dwarf_tree(&child, indent+1))
66 static bool dump_dwarf_tree(Dwarf_Die* die)
68 return _dump_dwarf_tree(die, 0);
72 #ifdef DUMP_PROTOTYPES
73 static bool _dump_ltrace_tree(const struct arg_type_info* info, int indent)
76 fprintf(stderr, "%*s%p ...\n", indent*4, "", (void*)info);
81 fprintf(stderr, "%*s%p NULL\n", indent*4, "", (void*)info);
87 fprintf(stderr, "%*s%p void\n", indent*4, "", (void*)info);
99 fprintf(stderr, "%*s%p base\n", indent*4, "", (void*)info);
103 fprintf(stderr, "%*s%p array. elements not printed\n", indent*4, "",
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);
113 fprintf(stderr, "%*s%p struct...\n", indent*4, "", (void*)info);
116 struct arg_type_info *info;
118 }* elements = (struct struct_field*)info->u.entries.data;
120 for(i=0; i<info->u.entries.size; i++)
121 _dump_ltrace_tree(elements[i].info, indent+1);
125 fprintf(stderr, "%*s%p unknown type\n", indent*4, "", (void*)info);
132 static bool dump_ltrace_tree(const struct arg_type_info* info)
134 return _dump_ltrace_tree(info, 0);
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)
145 Dwarf_Attribute attr ;
154 if (dwarf_attr(die, attr_name, &attr) == NULL)
157 unsigned int form = dwarf_whatform(&attr);
159 #define PROCESS_NUMERIC(type) \
160 if (dwarf_form ## type(&attr, &u.type) != 0) \
162 *result = (uint64_t)u.type; \
168 PROCESS_NUMERIC(addr);
175 PROCESS_NUMERIC(udata);
178 PROCESS_NUMERIC(sdata);
181 PROCESS_NUMERIC(flag);
184 complain(die, "Unknown numeric form %d for attr_name: %d", form, attr_name);
187 #undef PROCESS_NUMERIC
190 static bool get_integer_base_type(enum arg_type* type, int byte_size, bool is_signed)
194 *type = ARGTYPE_CHAR;
198 *type = is_signed ? ARGTYPE_SHORT : ARGTYPE_USHORT;
202 *type = is_signed ? ARGTYPE_INT : ARGTYPE_UINT;
206 *type = is_signed ? ARGTYPE_LONG : ARGTYPE_ULONG;
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)
219 if(!get_die_numeric((uint64_t*)&encoding, die, DW_AT_encoding))
222 if (encoding == DW_ATE_void)
225 if (encoding == DW_ATE_signed_char || encoding == DW_ATE_unsigned_char)
229 if (!get_die_numeric(&byte_size, die, DW_AT_byte_size))
232 if (encoding == DW_ATE_signed ||
233 encoding == DW_ATE_unsigned ||
234 encoding == DW_ATE_boolean) {
236 bool is_signed = (encoding == DW_ATE_signed);
239 if(!get_integer_base_type(&type, (int)byte_size, is_signed)) {
240 complain(die, "Unknown integer base type. Using 'void'");
246 if (encoding == DW_ATE_float) {
249 return ARGTYPE_FLOAT;
252 return ARGTYPE_DOUBLE;
255 // things like long doubles. ltrace has no support yet, so I just
262 if (encoding == DW_ATE_complex_float) {
264 case 2*sizeof(float):
265 return ARGTYPE_FLOAT;
267 case 2*sizeof(double):
268 return ARGTYPE_DOUBLE;
271 // things like long doubles. ltrace has no support yet, so I just
278 // Unknown encoding. I just say void
279 complain(die, "Unknown base type. Returning 'void'");
283 static bool get_type_die(Dwarf_Die* type_die, Dwarf_Die* die)
285 Dwarf_Attribute attr;
287 dwarf_attr(die, DW_AT_type, &attr) != NULL &&
288 dwarf_formref_die(&attr, type_die) != NULL;
293 // type_dieoffset_hash dictionary callbacks
294 static size_t dwarf_die_hash(const void* x)
296 return *(const Dwarf_Off*)x;
298 static int dwarf_die_eq(const void* a, const void* b)
300 return *(const Dwarf_Off*)a == *(const Dwarf_Off*)b;
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)
308 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
310 free((void*)dupkey); \
311 if(value != NULL) { \
312 value_destroy(value); \
315 if(lens != NULL ) { \
316 lens_destroy(&lens->super); \
319 if(result != NULL) { \
320 type_destroy(result); \
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)}); \
329 struct arg_type_info* result = NULL;
330 struct enum_lens* lens = NULL;
331 const char* dupkey = NULL;
332 struct value* value = NULL;
334 Dwarf_Off die_offset = dwarf_dieoffset(parent);
336 result = calloc(1, sizeof(struct arg_type_info));
337 if (result == NULL) {
338 complain(parent, "alloc error");
339 CLEANUP_AND_RETURN_ERROR(NULL);
342 dict_insert(type_dieoffset_hash, &die_offset, &result);
345 if (!get_die_numeric(&byte_size, parent, DW_AT_byte_size)) {
346 // No byte size given, assume 'int'
347 result->type = ARGTYPE_INT;
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;
355 lens = calloc(1, sizeof(struct enum_lens));
357 complain(parent, "alloc error");
358 CLEANUP_AND_RETURN_ERROR(NULL);
360 lens_init_enum(lens);
361 result->lens = &lens->super;
362 result->own_lens = 1;
365 if (dwarf_child(parent, &die) != 0) {
366 // empty enum. we're done
367 CLEANUP_AND_RETURN_ERROR(NULL);
372 complain(&die, "enum element: 0x%02x/'%s'", dwarf_tag(&die),
373 dwarf_diename(&die));
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);
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);
388 const char* key = dwarf_diename(&die);
390 complain(&die, "Enums must have a DW_AT_name key");
391 CLEANUP_AND_RETURN_ERROR(NULL);
393 dupkey = strdup(key);
394 if (dupkey == NULL) {
395 complain(&die, "Couldn't duplicate enum key");
396 CLEANUP_AND_RETURN_ERROR(NULL);
399 value = calloc(1, sizeof(struct value));
401 complain(&die, "Couldn't alloc enum value");
402 CLEANUP_AND_RETURN_ERROR(NULL);
405 value_init_detached(value, NULL, type_get_simple(result->type), 0);
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);
412 value_set_word(value, (long)enum_value);
414 if (lens_enum_add(lens, dupkey, 1, value, 1)) {
415 complain(&die, "Couldn't add enum element");
416 CLEANUP_AND_RETURN_ERROR(NULL);
424 #undef CLEANUP_AND_RETURN_ERROR
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)
432 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
433 if(value != NULL) { \
434 value_destroy(value); \
437 if(length != NULL) { \
438 expr_destroy(length); \
441 if(array_type != NULL && newly_allocated_array_type) { \
442 type_destroy(array_type); \
445 if(result != NULL) { \
446 type_destroy(result); \
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)}); \
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;
462 Dwarf_Off die_offset = dwarf_dieoffset(parent);
464 result = calloc(1, sizeof(struct arg_type_info));
465 if (result == NULL) {
466 complain(parent, "alloc error");
467 CLEANUP_AND_RETURN_ERROR(NULL);
471 if (!get_type_die(&type_die, parent)) {
472 complain(parent, "Array has unknown type");
473 CLEANUP_AND_RETURN_ERROR(NULL);
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);
485 if (dwarf_child(parent, &subrange) != 0) {
487 "Array must have a DW_TAG_subrange_type child, but has none");
488 CLEANUP_AND_RETURN_ERROR(NULL);
491 Dwarf_Die next_subrange;
492 if (dwarf_siblingof(&subrange, &next_subrange) <= 0) {
494 "Array must have exactly one DW_TAG_subrange_type child");
495 CLEANUP_AND_RETURN_ERROR(NULL);
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);
505 if (lower_bound != 0) {
507 "Array subrange has a nonzero lower bound. Don't know what to do");
508 CLEANUP_AND_RETURN_ERROR(NULL);
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
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);
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
530 value = calloc(1, sizeof(struct value));
532 complain(&subrange, "Couldn't alloc length value");
533 CLEANUP_AND_RETURN_ERROR(NULL);
535 value_init_detached(value, NULL, type_get_simple(ARGTYPE_INT), 0);
536 value_set_word(value, N);
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);
543 expr_init_const(length, value);
545 type_init_array(result, array_type, newly_allocated_array_type,
549 #undef CLEANUP_AND_RETURN_ERROR
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)
557 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
558 if(member_type != NULL && newly_allocated_member_type) { \
559 type_destroy(member_type); \
562 if(result != NULL) { \
563 type_destroy(result); \
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)}); \
573 struct arg_type_info* result = NULL;
574 struct arg_type_info* member_type = NULL;
575 int newly_allocated_member_type = 0;
577 Dwarf_Off die_offset = dwarf_dieoffset(parent);
579 result = calloc(1, sizeof(struct arg_type_info));
580 if (result == NULL) {
581 complain(parent, "alloc error");
582 CLEANUP_AND_RETURN_ERROR(NULL);
584 type_init_struct(result);
585 dict_insert(type_dieoffset_hash, &die_offset, &result);
588 if (dwarf_child(parent, &die) != 0) {
589 // no elements; we're done
595 newly_allocated_member_type = 0;
597 complain(&die, "member: 0x%02x", dwarf_tag(&die));
599 if (dwarf_tag(&die) != DW_TAG_member) {
600 complain(&die, "Structure can have ONLY DW_TAG_member");
601 CLEANUP_AND_RETURN_ERROR(NULL);
605 if (!get_type_die(&type_die, &die)) {
606 complain(&die, "Couldn't get type of element");
607 CLEANUP_AND_RETURN_ERROR(NULL);
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);
616 type_struct_add(result, member_type, newly_allocated_member_type);
622 #undef CLEANUP_AND_RETURN_ERROR
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)
633 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
634 if(pointee != NULL && newly_allocated_pointee) { \
635 type_destroy(pointee); \
638 if(result != NULL && *newly_allocated_result) { \
639 type_destroy(result); \
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)}); \
648 struct arg_type_info* result = NULL;
649 struct arg_type_info* pointee = NULL;
650 int newly_allocated_pointee = 0;
652 Dwarf_Off die_offset = dwarf_dieoffset(type_die);
655 // by default, we say we allocated nothing. I set this to true later, when I
657 *newly_allocated_result = 0;
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");
665 const char* type_name = dwarf_diename(type_die);
666 if (type_name != NULL) {
668 struct named_type* already_defined_type =
669 protolib_lookup_type(plib, type_name, true);
671 if (already_defined_type != NULL) {
673 "Type '%s' defined in a .conf file. Using that instead of DWARF",
675 return already_defined_type->info;
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);
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);
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);
706 complain(type_die, "Storing pointer type");
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);
714 dict_insert(type_dieoffset_hash, &die_offset, &result);
715 pointee = get_type(&newly_allocated_pointee,
716 &next_die, plib, type_dieoffset_hash);
718 CLEANUP_AND_RETURN_ERROR(NULL);
720 type_init_pointer(result, pointee, newly_allocated_pointee);
723 case DW_TAG_structure_type:
724 complain(type_die, "Storing struct type");
725 *newly_allocated_result = 1;
727 result = get_structure(type_die, plib, type_dieoffset_hash);
729 CLEANUP_AND_RETURN_ERROR(NULL);
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");
740 result = get_type(newly_allocated_result, &next_die,
741 plib, type_dieoffset_hash);
743 CLEANUP_AND_RETURN_ERROR(NULL);
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");
750 dict_insert(type_dieoffset_hash, &die_offset, &result);
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;
758 complain(type_die, "Storing enum int");
759 result = get_enum(type_die, type_dieoffset_hash);
761 CLEANUP_AND_RETURN_ERROR(NULL);
764 case DW_TAG_array_type:
765 *newly_allocated_result = 1;
767 complain(type_die, "Storing array");
768 result = get_array(type_die, plib, type_dieoffset_hash);
770 CLEANUP_AND_RETURN_ERROR(NULL);
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);
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);
786 #undef CLEANUP_AND_RETURN_ERROR
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)
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); \
799 if(result != NULL) { \
800 prototype_destroy(result); \
807 struct prototype* result = NULL;
808 struct arg_type_info* argument_type = NULL;
809 int newly_allocated_argument_type = 0;
811 result = calloc(1, sizeof(struct prototype));
812 if (result == NULL) {
813 complain(subroutine, "couldn't alloc prototype");
814 CLEANUP_AND_RETURN_ERROR(NULL);
816 prototype_init(result);
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;
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);
830 result->own_return_info = 1;
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);
839 result->own_return_info = newly_allocated_return_type;
843 // Now look at the arguments
845 if (dwarf_child(subroutine, &arg_die) != 0) {
846 // no args. We're done
851 if (dwarf_tag(&arg_die) == DW_TAG_formal_parameter) {
853 complain(&arg_die, "arg: 0x%02x", dwarf_tag(&arg_die));
855 argument_type = NULL;
856 newly_allocated_argument_type = false;
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);
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);
873 param_init_type(¶m, argument_type, newly_allocated_argument_type);
874 if (prototype_push_param(result, ¶m) <0) {
875 complain(&arg_die, "couldn't add argument to the prototype");
876 CLEANUP_AND_RETURN_ERROR(NULL);
879 #ifdef DUMP_PROTOTYPES
880 fprintf(stderr, "Adding argument:\n");
881 dump_ltrace_tree(argument_type);
885 NEXT_SIBLING(&arg_die);
889 #undef CLEANUP_AND_RETURN_ERROR
892 static bool import_subprogram(struct protolib* plib, struct library* lib,
893 struct dict* type_dieoffset_hash,
896 // I use the linkage function name if there is one, otherwise the
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");
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");
916 complain(die, "subroutine_type: 0x%02x; function '%s'",
917 dwarf_tag(die), function_name);
919 struct prototype* proto =
920 protolib_lookup_prototype(plib, function_name, false);
923 complain(die, "Prototype already exists. Skipping");
927 proto = get_prototype(die, plib, type_dieoffset_hash);
929 complain(die, "couldn't get prototype");
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);
940 protolib_add_prototype(plib, function_name_dup, 1, proto);
944 static bool process_die_compileunit(struct protolib* plib, struct library* lib,
945 struct dict* type_dieoffset_hash,
949 if (dwarf_child(parent, &die) != 0) {
950 // no child nodes, so nothing to do
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");
965 static void import(struct protolib* plib, struct library* lib, Dwfl* dwfl)
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;
972 dict_init(&type_dieoffset_hash, sizeof(Dwarf_Off), sizeof(struct arg_type_info*),
973 dwarf_die_hash, dwarf_die_eq, NULL);
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);
981 complain(die, "A DW_TAG_compile_unit die expected. Skipping this one");
984 dict_destroy(&type_dieoffset_hash, NULL, NULL, NULL);
987 bool import_DWARF_prototypes(struct library* lib)
989 struct protolib* plib = lib->protolib;
990 Dwfl* dwfl = lib->dwfl;
994 const char* soname_dup = strdup(lib->soname);
995 if( soname_dup == NULL ) {
996 fprintf(stderr, "couldn't strdup");
1000 plib = protolib_cache_default(&g_protocache, soname_dup, 1);
1002 fprintf(stderr, "Error loading protolib %s: %s.\n",
1003 lib->soname, strerror(errno));
1007 import(plib, lib, dwfl);
1008 lib->protolib = plib;
1014 - I handle static functions now. Should I? Those do not have DW_AT_external==1
1016 - should process existing prototypes to make sure they match
1018 - what do function pointers look like? I'm doing void*
1022 - all my *allocs leak