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
32 #define complain(die, format, ...) \
33 fprintf(stderr, "%s() die '%s' @ 0x%lx: " format "\n", \
34 __func__, dwarf_diename(die), dwarf_dieoffset(die), \
37 #define complain(die, format, ...)
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 */
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);
52 static bool _dump_dwarf_tree(Dwarf_Die* die, int indent)
55 fprintf(stderr, "%*sprocessing unit: 0x%02x/'%s'\n", indent*4, "",
56 dwarf_tag(die), dwarf_diename(die));
59 if (dwarf_child(die, &child) == 0) {
60 if (!_dump_dwarf_tree(&child, indent+1))
70 static bool dump_dwarf_tree(Dwarf_Die* die)
72 return _dump_dwarf_tree(die, 0);
76 #ifdef DUMP_PROTOTYPES
77 static bool _dump_ltrace_tree(const struct arg_type_info* info, int indent)
80 fprintf(stderr, "%*s%p ...\n", indent*4, "", (void*)info);
85 fprintf(stderr, "%*s%p NULL\n", indent*4, "", (void*)info);
91 fprintf(stderr, "%*s%p void\n", indent*4, "", (void*)info);
103 fprintf(stderr, "%*s%p base\n", indent*4, "", (void*)info);
107 fprintf(stderr, "%*s%p array. elements not printed\n", indent*4, "",
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);
117 fprintf(stderr, "%*s%p struct...\n", indent*4, "", (void*)info);
120 struct arg_type_info *info;
122 }* elements = (struct struct_field*)info->u.entries.data;
124 for(i=0; i<info->u.entries.size; i++)
125 _dump_ltrace_tree(elements[i].info, indent+1);
129 fprintf(stderr, "%*s%p unknown type\n", indent*4, "", (void*)info);
136 static bool dump_ltrace_tree(const struct arg_type_info* info)
138 return _dump_ltrace_tree(info, 0);
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)
149 Dwarf_Attribute attr ;
158 if (dwarf_attr(die, attr_name, &attr) == NULL)
161 unsigned int form = dwarf_whatform(&attr);
163 #define PROCESS_NUMERIC(type) \
164 if (dwarf_form ## type(&attr, &u.type) != 0) \
166 *result = (uint64_t)u.type; \
172 PROCESS_NUMERIC(addr);
179 PROCESS_NUMERIC(udata);
182 PROCESS_NUMERIC(sdata);
185 PROCESS_NUMERIC(flag);
188 complain(die, "Unknown numeric form %d for attr_name: %d", form, attr_name);
191 #undef PROCESS_NUMERIC
194 static bool get_integer_base_type(enum arg_type* type, int byte_size, bool is_signed)
198 *type = ARGTYPE_CHAR;
202 *type = is_signed ? ARGTYPE_SHORT : ARGTYPE_USHORT;
206 *type = is_signed ? ARGTYPE_INT : ARGTYPE_UINT;
210 *type = is_signed ? ARGTYPE_LONG : ARGTYPE_ULONG;
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)
223 if(!get_die_numeric((uint64_t*)&encoding, die, DW_AT_encoding))
226 if (encoding == DW_ATE_void)
229 if (encoding == DW_ATE_signed_char || encoding == DW_ATE_unsigned_char)
233 if (!get_die_numeric(&byte_size, die, DW_AT_byte_size))
236 if (encoding == DW_ATE_signed ||
237 encoding == DW_ATE_unsigned ||
238 encoding == DW_ATE_boolean) {
240 bool is_signed = (encoding == DW_ATE_signed);
243 if(!get_integer_base_type(&type, (int)byte_size, is_signed)) {
244 complain(die, "Unknown integer base type. Using 'void'");
250 if (encoding == DW_ATE_float) {
253 return ARGTYPE_FLOAT;
256 return ARGTYPE_DOUBLE;
259 // things like long doubles. ltrace has no support yet, so I just
266 if (encoding == DW_ATE_complex_float) {
268 case 2*sizeof(float):
269 return ARGTYPE_FLOAT;
271 case 2*sizeof(double):
272 return ARGTYPE_DOUBLE;
275 // things like long doubles. ltrace has no support yet, so I just
282 // Unknown encoding. I just say void
283 complain(die, "Unknown base type. Returning 'void'");
287 static bool get_type_die(Dwarf_Die* type_die, Dwarf_Die* die)
289 Dwarf_Attribute attr;
291 dwarf_attr(die, DW_AT_type, &attr) != NULL &&
292 dwarf_formref_die(&attr, type_die) != NULL;
297 // type_dieoffset_hash dictionary callbacks
298 static size_t dwarf_die_hash(const void* x)
300 return *(const Dwarf_Off*)x;
302 static int dwarf_die_eq(const void* a, const void* b)
304 return *(const Dwarf_Off*)a == *(const Dwarf_Off*)b;
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)
312 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
314 free((void*)dupkey); \
315 if(value != NULL) { \
316 value_destroy(value); \
319 if(lens != NULL ) { \
320 lens_destroy(&lens->super); \
323 if(result != NULL) { \
324 type_destroy(result); \
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)}); \
333 struct arg_type_info* result = NULL;
334 struct enum_lens* lens = NULL;
335 const char* dupkey = NULL;
336 struct value* value = NULL;
338 Dwarf_Off die_offset = dwarf_dieoffset(parent);
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);
346 dict_insert(type_dieoffset_hash, &die_offset, &result);
349 if (!get_die_numeric(&byte_size, parent, DW_AT_byte_size)) {
350 // No byte size given, assume 'int'
351 result->type = ARGTYPE_INT;
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;
359 lens = calloc(1, sizeof(struct enum_lens));
361 complain(parent, "alloc error");
362 CLEANUP_AND_RETURN_ERROR(NULL);
364 lens_init_enum(lens);
365 result->lens = &lens->super;
366 result->own_lens = 1;
369 if (dwarf_child(parent, &die) != 0) {
370 // empty enum. we're done
371 CLEANUP_AND_RETURN_ERROR(NULL);
376 complain(&die, "enum element: 0x%02x/'%s'", dwarf_tag(&die),
377 dwarf_diename(&die));
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);
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);
392 const char* key = dwarf_diename(&die);
394 complain(&die, "Enums must have a DW_AT_name key");
395 CLEANUP_AND_RETURN_ERROR(NULL);
397 dupkey = strdup(key);
398 if (dupkey == NULL) {
399 complain(&die, "Couldn't duplicate enum key");
400 CLEANUP_AND_RETURN_ERROR(NULL);
403 value = calloc(1, sizeof(struct value));
405 complain(&die, "Couldn't alloc enum value");
406 CLEANUP_AND_RETURN_ERROR(NULL);
409 value_init_detached(value, NULL, type_get_simple(result->type), 0);
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);
416 value_set_word(value, (long)enum_value);
418 if (lens_enum_add(lens, dupkey, 1, value, 1)) {
419 complain(&die, "Couldn't add enum element");
420 CLEANUP_AND_RETURN_ERROR(NULL);
428 #undef CLEANUP_AND_RETURN_ERROR
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)
436 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
437 if(value != NULL) { \
438 value_destroy(value); \
441 if(length != NULL) { \
442 expr_destroy(length); \
445 if(array_type != NULL && newly_allocated_array_type) { \
446 type_destroy(array_type); \
449 if(result != NULL) { \
450 type_destroy(result); \
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)}); \
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;
466 Dwarf_Off die_offset = dwarf_dieoffset(parent);
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);
475 if (!get_type_die(&type_die, parent)) {
476 complain(parent, "Array has unknown type");
477 CLEANUP_AND_RETURN_ERROR(NULL);
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);
489 if (dwarf_child(parent, &subrange) != 0) {
491 "Array must have a DW_TAG_subrange_type child, but has none");
492 CLEANUP_AND_RETURN_ERROR(NULL);
495 Dwarf_Die next_subrange;
496 if (dwarf_siblingof(&subrange, &next_subrange) <= 0) {
498 "Array must have exactly one DW_TAG_subrange_type child");
499 CLEANUP_AND_RETURN_ERROR(NULL);
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);
509 if (lower_bound != 0) {
511 "Array subrange has a nonzero lower bound. Don't know what to do");
512 CLEANUP_AND_RETURN_ERROR(NULL);
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
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);
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
534 value = calloc(1, sizeof(struct value));
536 complain(&subrange, "Couldn't alloc length value");
537 CLEANUP_AND_RETURN_ERROR(NULL);
539 value_init_detached(value, NULL, type_get_simple(ARGTYPE_INT), 0);
540 value_set_word(value, N);
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);
547 expr_init_const(length, value);
549 type_init_array(result, array_type, newly_allocated_array_type,
553 #undef CLEANUP_AND_RETURN_ERROR
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)
561 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
562 if(member_type != NULL && newly_allocated_member_type) { \
563 type_destroy(member_type); \
566 if(result != NULL) { \
567 type_destroy(result); \
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)}); \
577 struct arg_type_info* result = NULL;
578 struct arg_type_info* member_type = NULL;
579 int newly_allocated_member_type = 0;
581 Dwarf_Off die_offset = dwarf_dieoffset(parent);
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);
588 type_init_struct(result);
589 dict_insert(type_dieoffset_hash, &die_offset, &result);
592 if (dwarf_child(parent, &die) != 0) {
593 // no elements; we're done
599 newly_allocated_member_type = 0;
601 complain(&die, "member: 0x%02x", dwarf_tag(&die));
603 if (dwarf_tag(&die) != DW_TAG_member) {
604 complain(&die, "Structure can have ONLY DW_TAG_member");
605 CLEANUP_AND_RETURN_ERROR(NULL);
609 if (!get_type_die(&type_die, &die)) {
610 complain(&die, "Couldn't get type of element");
611 CLEANUP_AND_RETURN_ERROR(NULL);
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);
620 type_struct_add(result, member_type, newly_allocated_member_type);
626 #undef CLEANUP_AND_RETURN_ERROR
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)
637 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
638 if(pointee != NULL && newly_allocated_pointee) { \
639 type_destroy(pointee); \
642 if(result != NULL && *newly_allocated_result) { \
643 type_destroy(result); \
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)}); \
652 struct arg_type_info* result = NULL;
653 struct arg_type_info* pointee = NULL;
654 int newly_allocated_pointee = 0;
656 Dwarf_Off die_offset = dwarf_dieoffset(type_die);
659 // by default, we say we allocated nothing. I set this to true later, when I
661 *newly_allocated_result = 0;
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");
669 const char* type_name = dwarf_diename(type_die);
670 if (type_name != NULL) {
672 struct named_type* already_defined_type =
673 protolib_lookup_type(plib, type_name, true);
675 if (already_defined_type != NULL) {
677 "Type '%s' defined in a .conf file. Using that instead of DWARF",
679 return already_defined_type->info;
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);
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);
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);
710 complain(type_die, "Storing pointer type");
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);
718 dict_insert(type_dieoffset_hash, &die_offset, &result);
719 pointee = get_type(&newly_allocated_pointee,
720 &next_die, plib, type_dieoffset_hash);
722 CLEANUP_AND_RETURN_ERROR(NULL);
724 type_init_pointer(result, pointee, newly_allocated_pointee);
727 case DW_TAG_structure_type:
728 complain(type_die, "Storing struct type");
729 *newly_allocated_result = 1;
731 result = get_structure(type_die, plib, type_dieoffset_hash);
733 CLEANUP_AND_RETURN_ERROR(NULL);
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");
744 result = get_type(newly_allocated_result, &next_die,
745 plib, type_dieoffset_hash);
747 CLEANUP_AND_RETURN_ERROR(NULL);
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");
754 dict_insert(type_dieoffset_hash, &die_offset, &result);
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;
762 complain(type_die, "Storing enum int");
763 result = get_enum(type_die, type_dieoffset_hash);
765 CLEANUP_AND_RETURN_ERROR(NULL);
768 case DW_TAG_array_type:
769 *newly_allocated_result = 1;
771 complain(type_die, "Storing array");
772 result = get_array(type_die, plib, type_dieoffset_hash);
774 CLEANUP_AND_RETURN_ERROR(NULL);
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);
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);
790 #undef CLEANUP_AND_RETURN_ERROR
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)
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); \
803 if(result != NULL) { \
804 prototype_destroy(result); \
811 struct prototype* result = NULL;
812 struct arg_type_info* argument_type = NULL;
813 int newly_allocated_argument_type = 0;
815 result = calloc(1, sizeof(struct prototype));
816 if (result == NULL) {
817 complain(die, "couldn't alloc prototype");
818 CLEANUP_AND_RETURN_ERROR(NULL);
820 prototype_init(result);
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;
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);
834 result->own_return_info = 1;
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);
843 result->own_return_info = newly_allocated_return_type;
847 // Now look at the arguments
849 if (dwarf_child(subroutine, &arg_die) != 0) {
850 // no args. We're done
855 if (dwarf_tag(&arg_die) == DW_TAG_formal_parameter) {
857 complain(&arg_die, "arg: 0x%02x", dwarf_tag(&arg_die));
859 argument_type = NULL;
860 newly_allocated_argument_type = false;
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);
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);
877 param_init_type(¶m, argument_type, newly_allocated_argument_type);
878 if (prototype_push_param(result, ¶m) <0) {
879 complain(&arg_die, "couldn't add argument to the prototype");
880 CLEANUP_AND_RETURN_ERROR(NULL);
883 #ifdef DUMP_PROTOTYPES
884 fprintf(stderr, "Adding argument:\n");
885 dump_ltrace_tree(argument_type);
889 NEXT_SIBLING(&arg_die);
893 #undef CLEANUP_AND_RETURN_ERROR
896 static bool import_subprogram(struct protolib* plib, struct library* lib,
897 struct dict* type_dieoffset_hash,
900 // I use the linkage function name if there is one, otherwise the
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");
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");
920 complain(die, "subroutine_type: 0x%02x; function '%s'",
921 dwarf_tag(die), function_name);
923 struct prototype* proto =
924 protolib_lookup_prototype(plib, function_name, false);
927 complain(die, "Prototype already exists. Skipping");
931 proto = get_prototype(die, plib, type_dieoffset_hash);
933 complain(die, "couldn't get prototype");
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);
944 protolib_add_prototype(plib, function_name_dup, 1, proto);
948 static bool process_die_compileunit(struct protolib* plib, struct library* lib,
949 struct dict* type_dieoffset_hash,
953 if (dwarf_child(parent, &die) != 0) {
954 // no child nodes, so nothing to do
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");
969 static void import(struct protolib* plib, struct library* lib, Dwfl* dwfl)
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;
976 dict_init(&type_dieoffset_hash, sizeof(Dwarf_Off), sizeof(struct arg_type_info*),
977 dwarf_die_hash, dwarf_die_eq, NULL);
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);
985 complain(die, "A DW_TAG_compile_unit die expected. Skipping this one");
988 dict_destroy(&type_dieoffset_hash, NULL, NULL, NULL);
991 bool import_DWARF_prototypes(struct library* lib)
993 struct protolib* plib = lib->protolib;
994 Dwfl* dwfl = lib->dwfl;
998 const char* soname_dup = strdup(lib->soname);
999 if( soname_dup == NULL ) {
1000 fprintf(stderr, "couldn't strdup");
1004 plib = protolib_cache_default(&g_protocache, soname_dup, 1);
1006 fprintf(stderr, "Error loading protolib %s: %s.\n",
1007 lib->soname, strerror(errno));
1011 import(plib, lib, dwfl);
1012 lib->protolib = plib;
1018 - I handle static functions now. Should I? Those do not have DW_AT_external==1
1020 - should process existing prototypes to make sure they match
1022 - what do function pointers look like? I'm doing void*
1026 - all my *allocs leak