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 complain(die, format, ...) \
30 debug(DEBUG_FUNCTION, "%s() die '%s' @ 0x%lx: " format, \
31 __func__, dwarf_diename(die), dwarf_dieoffset(die), \
34 #define NEXT_SIBLING(die) \
35 int res = dwarf_siblingof(die, die); \
36 if (res == 0) continue; /* sibling exists */ \
37 if (res < 0) return false; /* error */ \
38 break /* no sibling exists */
40 static struct arg_type_info* get_type(int* newly_allocated_info,
41 Dwarf_Die* type_die, struct protolib* plib,
42 struct dict* type_dieoffset_hash);
47 // debugging functions to dump types that I already parsed
48 #ifdef DUMP_PROTOTYPES
49 static bool _dump_ltrace_tree(const struct arg_type_info* info, int indent)
52 fprintf(stderr, "%*s%p ...\n", indent*4, "", (void*)info);
57 fprintf(stderr, "%*s%p NULL\n", indent*4, "", (void*)info);
63 fprintf(stderr, "%*s%p void\n", indent*4, "", (void*)info);
75 fprintf(stderr, "%*s%p base\n", indent*4, "", (void*)info);
79 fprintf(stderr, "%*s%p array. elements not printed\n", indent*4, "",
84 fprintf(stderr, "%*s%p pointer to...\n", indent*4, "", (void*)info);
85 _dump_ltrace_tree(info->u.ptr_info.info, indent+1);
89 fprintf(stderr, "%*s%p struct...\n", indent*4, "", (void*)info);
92 struct arg_type_info *info;
94 }* elements = (struct struct_field*)info->u.entries.data;
96 for(i=0; i<info->u.entries.size; i++)
97 _dump_ltrace_tree(elements[i].info, indent+1);
101 fprintf(stderr, "%*s%p unknown type\n", indent*4, "", (void*)info);
108 static bool dump_ltrace_tree(const struct arg_type_info* info)
110 return _dump_ltrace_tree(info, 0);
115 // pulls a numerical value out of a particular attribute in a die. Returns true
116 // if successful. The result is returned in *result. Note that this is cast to
117 // (uint64_t), regardless of the actual type of the input
118 static bool get_die_numeric(uint64_t* result,
119 Dwarf_Die *die, unsigned int attr_name)
121 Dwarf_Attribute attr ;
130 if (dwarf_attr(die, attr_name, &attr) == NULL)
133 unsigned int form = dwarf_whatform(&attr);
135 #define PROCESS_NUMERIC(type) \
136 if (dwarf_form ## type(&attr, &u.type) != 0) \
138 *result = (uint64_t)u.type; \
144 PROCESS_NUMERIC(addr);
151 PROCESS_NUMERIC(udata);
154 PROCESS_NUMERIC(sdata);
157 PROCESS_NUMERIC(flag);
160 complain(die, "Unknown numeric form %d for attr_name: %d", form, attr_name);
163 #undef PROCESS_NUMERIC
166 static bool get_integer_base_type(enum arg_type* type, int byte_size, bool is_signed)
170 *type = ARGTYPE_CHAR;
174 *type = is_signed ? ARGTYPE_SHORT : ARGTYPE_USHORT;
178 *type = is_signed ? ARGTYPE_INT : ARGTYPE_UINT;
182 *type = is_signed ? ARGTYPE_LONG : ARGTYPE_ULONG;
190 // returns an ltrace ARGTYPE_XXX base type from the given die. If we dont
191 // support a particular type (or an error occurred), I regturn ARGTYPE_VOID
192 static enum arg_type get_base_type(Dwarf_Die* die)
195 if(!get_die_numeric((uint64_t*)&encoding, die, DW_AT_encoding))
198 if (encoding == DW_ATE_void)
201 if (encoding == DW_ATE_signed_char || encoding == DW_ATE_unsigned_char)
205 if (!get_die_numeric(&byte_size, die, DW_AT_byte_size))
208 if (encoding == DW_ATE_signed ||
209 encoding == DW_ATE_unsigned ||
210 encoding == DW_ATE_boolean) {
212 bool is_signed = (encoding == DW_ATE_signed);
215 if(!get_integer_base_type(&type, (int)byte_size, is_signed)) {
216 complain(die, "Unknown integer base type. Using 'void'");
222 if (encoding == DW_ATE_float) {
225 return ARGTYPE_FLOAT;
228 return ARGTYPE_DOUBLE;
231 // things like long doubles. ltrace has no support yet, so I just
238 if (encoding == DW_ATE_complex_float) {
240 case 2*sizeof(float):
241 return ARGTYPE_FLOAT;
243 case 2*sizeof(double):
244 return ARGTYPE_DOUBLE;
247 // things like long doubles. ltrace has no support yet, so I just
254 // Unknown encoding. I just say void
255 complain(die, "Unknown base type. Returning 'void'");
259 static bool get_type_die(Dwarf_Die* type_die, Dwarf_Die* die)
261 Dwarf_Attribute attr;
263 dwarf_attr(die, DW_AT_type, &attr) != NULL &&
264 dwarf_formref_die(&attr, type_die) != NULL;
269 // type_dieoffset_hash dictionary callbacks
270 static size_t dwarf_die_hash(const void* x)
272 return *(const Dwarf_Off*)x;
274 static int dwarf_die_eq(const void* a, const void* b)
276 return *(const Dwarf_Off*)a == *(const Dwarf_Off*)b;
280 // returns a newly-allocated art_type_info*, or NULL on error
281 static struct arg_type_info* get_enum(Dwarf_Die* parent, struct dict* type_dieoffset_hash)
284 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
286 free((void*)dupkey); \
287 if(value != NULL) { \
288 value_destroy(value); \
291 if(lens != NULL ) { \
292 lens_destroy(&lens->super); \
295 if(result != NULL) { \
296 type_destroy(result); \
299 dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \
300 dict_insert(type_dieoffset_hash, &die_offset, \
301 &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \
305 struct arg_type_info* result = NULL;
306 struct enum_lens* lens = NULL;
307 const char* dupkey = NULL;
308 struct value* value = NULL;
310 Dwarf_Off die_offset = dwarf_dieoffset(parent);
312 result = calloc(1, sizeof(struct arg_type_info));
313 if (result == NULL) {
314 complain(parent, "alloc error");
315 CLEANUP_AND_RETURN_ERROR(NULL);
318 dict_insert(type_dieoffset_hash, &die_offset, &result);
321 if (!get_die_numeric(&byte_size, parent, DW_AT_byte_size)) {
322 // No byte size given, assume 'int'
323 result->type = ARGTYPE_INT;
325 if(!get_integer_base_type(&result->type, (int)byte_size, true)) {
326 complain(parent, "Unknown integer base type. Using 'int'");
327 result->type = ARGTYPE_INT;
331 lens = calloc(1, sizeof(struct enum_lens));
333 complain(parent, "alloc error");
334 CLEANUP_AND_RETURN_ERROR(NULL);
336 lens_init_enum(lens);
337 result->lens = &lens->super;
338 result->own_lens = 1;
341 if (dwarf_child(parent, &die) != 0) {
342 // empty enum. we're done
343 CLEANUP_AND_RETURN_ERROR(NULL);
348 complain(&die, "enum element: 0x%02x/'%s'", dwarf_tag(&die),
349 dwarf_diename(&die));
354 if (dwarf_tag(&die) != DW_TAG_enumerator) {
355 complain(&die, "Enums can have ONLY DW_TAG_enumerator elements");
356 CLEANUP_AND_RETURN_ERROR(NULL);
359 if (!dwarf_hasattr(&die, DW_AT_const_value)) {
360 complain(&die, "Enums MUST have DW_AT_const_value values");
361 CLEANUP_AND_RETURN_ERROR(NULL);
364 const char* key = dwarf_diename(&die);
366 complain(&die, "Enums must have a DW_AT_name key");
367 CLEANUP_AND_RETURN_ERROR(NULL);
369 dupkey = strdup(key);
370 if (dupkey == NULL) {
371 complain(&die, "Couldn't duplicate enum key");
372 CLEANUP_AND_RETURN_ERROR(NULL);
375 value = calloc(1, sizeof(struct value));
377 complain(&die, "Couldn't alloc enum value");
378 CLEANUP_AND_RETURN_ERROR(NULL);
381 value_init_detached(value, NULL, type_get_simple(result->type), 0);
383 if (!get_die_numeric(&enum_value, &die, DW_AT_const_value)) {
384 complain(&die, "Couldn't get enum value");
385 CLEANUP_AND_RETURN_ERROR(NULL);
388 value_set_word(value, (long)enum_value);
390 if (lens_enum_add(lens, dupkey, 1, value, 1)) {
391 complain(&die, "Couldn't add enum element");
392 CLEANUP_AND_RETURN_ERROR(NULL);
400 #undef CLEANUP_AND_RETURN_ERROR
403 // returns a newly-allocated art_type_info*, or NULL on error
404 static struct arg_type_info* get_array( Dwarf_Die* parent, struct protolib* plib,
405 struct dict* type_dieoffset_hash)
408 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
409 if(value != NULL) { \
410 value_destroy(value); \
413 if(length != NULL) { \
414 expr_destroy(length); \
417 if(array_type != NULL && newly_allocated_array_type) { \
418 type_destroy(array_type); \
421 if(result != NULL) { \
422 type_destroy(result); \
425 dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \
426 dict_insert(type_dieoffset_hash, &die_offset, \
427 &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \
432 struct arg_type_info* result = NULL;
433 struct value* value = NULL;
434 struct expr_node* length = NULL;
435 struct arg_type_info* array_type = NULL;
436 int newly_allocated_array_type = 0;
438 Dwarf_Off die_offset = dwarf_dieoffset(parent);
440 result = calloc(1, sizeof(struct arg_type_info));
441 if (result == NULL) {
442 complain(parent, "alloc error");
443 CLEANUP_AND_RETURN_ERROR(NULL);
447 if (!get_type_die(&type_die, parent)) {
448 complain(parent, "Array has unknown type");
449 CLEANUP_AND_RETURN_ERROR(NULL);
452 dict_insert(type_dieoffset_hash, &die_offset, &result);
453 array_type = get_type(&newly_allocated_array_type,
454 &type_die, plib, type_dieoffset_hash);
455 if( array_type == NULL ) {
456 complain(parent, "Couldn't figure out array's type");
457 CLEANUP_AND_RETURN_ERROR(NULL);
461 if (dwarf_child(parent, &subrange) != 0) {
463 "Array must have a DW_TAG_subrange_type child, but has none");
464 CLEANUP_AND_RETURN_ERROR(NULL);
467 Dwarf_Die next_subrange;
468 if (dwarf_siblingof(&subrange, &next_subrange) <= 0) {
470 "Array must have exactly one DW_TAG_subrange_type child");
471 CLEANUP_AND_RETURN_ERROR(NULL);
474 if (dwarf_hasattr(&subrange, DW_AT_lower_bound)) {
475 uint64_t lower_bound;
476 if (!get_die_numeric(&lower_bound, &subrange, DW_AT_lower_bound)) {
477 complain(parent, "Couldn't read lower bound");
478 CLEANUP_AND_RETURN_ERROR(NULL);
481 if (lower_bound != 0) {
483 "Array subrange has a nonzero lower bound. Don't know what to do");
484 CLEANUP_AND_RETURN_ERROR(NULL);
489 if (!dwarf_hasattr(&subrange, DW_AT_upper_bound)) {
490 // no upper bound is defined. This is probably a variable-width array,
491 // and I don't know how long it is. Let's say 0 to be safe
496 if (!get_die_numeric(&N, &subrange, DW_AT_upper_bound)) {
497 complain(parent, "Couldn't read upper bound");
498 CLEANUP_AND_RETURN_ERROR(NULL);
503 // I'm not checking the subrange type. It should be some sort of integer,
504 // and I don't know what it would mean for it to be something else
506 value = calloc(1, sizeof(struct value));
508 complain(&subrange, "Couldn't alloc length value");
509 CLEANUP_AND_RETURN_ERROR(NULL);
511 value_init_detached(value, NULL, type_get_simple(ARGTYPE_INT), 0);
512 value_set_word(value, N);
514 length = calloc(1, sizeof(struct expr_node));
515 if (length == NULL) {
516 complain(&subrange, "Couldn't alloc length expr");
517 CLEANUP_AND_RETURN_ERROR(NULL);
519 expr_init_const(length, value);
521 type_init_array(result, array_type, newly_allocated_array_type,
525 #undef CLEANUP_AND_RETURN_ERROR
528 // returns a newly-allocated art_type_info*, or NULL on error
529 static struct arg_type_info* get_structure(Dwarf_Die* parent, struct protolib* plib,
530 struct dict* type_dieoffset_hash)
533 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
534 if(member_type != NULL && newly_allocated_member_type) { \
535 type_destroy(member_type); \
538 if(result != NULL) { \
539 type_destroy(result); \
542 dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \
543 dict_insert(type_dieoffset_hash, &die_offset, \
544 &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \
549 struct arg_type_info* result = NULL;
550 struct arg_type_info* member_type = NULL;
551 int newly_allocated_member_type = 0;
553 Dwarf_Off die_offset = dwarf_dieoffset(parent);
555 result = calloc(1, sizeof(struct arg_type_info));
556 if (result == NULL) {
557 complain(parent, "alloc error");
558 CLEANUP_AND_RETURN_ERROR(NULL);
560 type_init_struct(result);
561 dict_insert(type_dieoffset_hash, &die_offset, &result);
564 if (dwarf_child(parent, &die) != 0) {
565 // no elements; we're done
571 newly_allocated_member_type = 0;
573 complain(&die, "member: 0x%02x", dwarf_tag(&die));
575 if (dwarf_tag(&die) != DW_TAG_member) {
576 complain(&die, "Structure can have ONLY DW_TAG_member");
577 CLEANUP_AND_RETURN_ERROR(NULL);
581 if (!get_type_die(&type_die, &die)) {
582 complain(&die, "Couldn't get type of element");
583 CLEANUP_AND_RETURN_ERROR(NULL);
586 member_type = get_type(&newly_allocated_member_type,
587 &type_die, plib, type_dieoffset_hash);
588 if(member_type == NULL) {
589 complain(&die, "Couldn't parse type from DWARF data");
590 CLEANUP_AND_RETURN_ERROR(NULL);
592 type_struct_add(result, member_type, newly_allocated_member_type);
598 #undef CLEANUP_AND_RETURN_ERROR
601 // Reads the type in the die and returns the corresponding arg_type_info*. If
602 // this was newly allocated on the heap, *newly_allocated_info = true. If an
603 // error occurred, returns NULL
604 static struct arg_type_info* get_type(int* newly_allocated_result,
605 Dwarf_Die* type_die, struct protolib* plib,
606 struct dict* type_dieoffset_hash)
609 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
610 if(pointee != NULL && newly_allocated_pointee) { \
611 type_destroy(pointee); \
614 if(result != NULL && *newly_allocated_result) { \
615 type_destroy(result); \
618 dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \
619 dict_insert(type_dieoffset_hash, &die_offset, \
620 &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \
624 struct arg_type_info* result = NULL;
625 struct arg_type_info* pointee = NULL;
626 int newly_allocated_pointee = 0;
628 Dwarf_Off die_offset = dwarf_dieoffset(type_die);
631 // by default, we say we allocated nothing. I set this to true later, when I
633 *newly_allocated_result = 0;
635 struct arg_type_info** found_type = dict_find(type_dieoffset_hash, &die_offset);
636 if (found_type != NULL) {
637 complain(type_die, "Read pre-computed type");
641 const char* type_name = dwarf_diename(type_die);
642 if (type_name != NULL) {
644 struct named_type* already_defined_type =
645 protolib_lookup_type(plib, type_name, true);
647 if (already_defined_type != NULL) {
649 "Type '%s' defined in a .conf file. Using that instead of DWARF",
651 return already_defined_type->info;
657 switch (dwarf_tag(type_die)) {
658 case DW_TAG_base_type:
659 complain(type_die, "Storing base type");
660 result = type_get_simple(get_base_type(type_die));
661 dict_insert(type_dieoffset_hash, &die_offset, &result);
664 case DW_TAG_subroutine_type:
665 case DW_TAG_inlined_subroutine:
666 // function pointers are stored as void*. If ltrace tries to dereference
667 // these, it'll get a segfault
668 complain(type_die, "Storing subroutine type");
669 result = type_get_simple(ARGTYPE_VOID);
670 dict_insert(type_dieoffset_hash, &die_offset, &result);
673 case DW_TAG_pointer_type:
674 if (!get_type_die(&next_die, type_die)) {
675 // the pointed-to type isn't defined, so I report a void*
676 complain(type_die, "Storing void-pointer type");
677 result = type_get_voidptr();
678 dict_insert(type_dieoffset_hash, &die_offset, &result);
682 complain(type_die, "Storing pointer type");
684 *newly_allocated_result = 1;
685 result = calloc(1, sizeof(struct arg_type_info));
686 if (result == NULL) {
687 complain(type_die, "alloc error");
688 CLEANUP_AND_RETURN_ERROR(NULL);
690 dict_insert(type_dieoffset_hash, &die_offset, &result);
691 pointee = get_type(&newly_allocated_pointee,
692 &next_die, plib, type_dieoffset_hash);
694 CLEANUP_AND_RETURN_ERROR(NULL);
696 type_init_pointer(result, pointee, newly_allocated_pointee);
699 case DW_TAG_structure_type:
700 complain(type_die, "Storing struct type");
701 *newly_allocated_result = 1;
703 result = get_structure(type_die, plib, type_dieoffset_hash);
705 CLEANUP_AND_RETURN_ERROR(NULL);
710 case DW_TAG_const_type:
711 case DW_TAG_volatile_type:
712 // Various tags are simply pass-through, so I just keep going
713 if (get_type_die(&next_die, type_die)) {
714 complain(type_die, "Storing const/typedef type");
716 result = get_type(newly_allocated_result, &next_die,
717 plib, type_dieoffset_hash);
719 CLEANUP_AND_RETURN_ERROR(NULL);
721 // no type. Use 'void'. Normally I'd think this is bogus, but stdio
722 // typedefs something to void
723 result = type_get_simple(ARGTYPE_VOID);
724 complain(type_die, "Storing void type");
726 dict_insert(type_dieoffset_hash, &die_offset, &result);
729 case DW_TAG_enumeration_type:
730 // We have an enumeration. This has a base type, but has a particular
731 // lens to handle the enum
732 *newly_allocated_result = 1;
734 complain(type_die, "Storing enum int");
735 result = get_enum(type_die, type_dieoffset_hash);
737 CLEANUP_AND_RETURN_ERROR(NULL);
740 case DW_TAG_array_type:
741 *newly_allocated_result = 1;
743 complain(type_die, "Storing array");
744 result = get_array(type_die, plib, type_dieoffset_hash);
746 CLEANUP_AND_RETURN_ERROR(NULL);
749 case DW_TAG_union_type:
750 result = type_get_simple(ARGTYPE_VOID);
751 complain(type_die, "Storing union-as-void type");
752 dict_insert(type_dieoffset_hash, &die_offset, &result);
756 complain(type_die, "Unknown type tag 0x%x. Returning void", dwarf_tag(type_die));
757 result = type_get_simple(ARGTYPE_VOID);
758 dict_insert(type_dieoffset_hash, &die_offset, &result);
762 #undef CLEANUP_AND_RETURN_ERROR
765 // returns a newly-allocated prototype*, or NULL on error
766 static struct prototype* get_prototype( Dwarf_Die* subroutine, struct protolib* plib,
767 struct dict* type_dieoffset_hash)
770 #define CLEANUP_AND_RETURN_ERROR(ret) do { \
771 if(argument_type != NULL && newly_allocated_argument_type) { \
772 type_destroy(argument_type); \
773 free(argument_type); \
775 if(result != NULL) { \
776 prototype_destroy(result); \
783 struct prototype* result = NULL;
784 struct arg_type_info* argument_type = NULL;
785 int newly_allocated_argument_type = 0;
787 result = calloc(1, sizeof(struct prototype));
788 if (result == NULL) {
789 complain(subroutine, "couldn't alloc prototype");
790 CLEANUP_AND_RETURN_ERROR(NULL);
792 prototype_init(result);
794 // First, look at the return type. This is stored in a DW_AT_type tag in the
795 // subroutine DIE. If there is no such tag, this function returns void
796 Dwarf_Die return_type_die;
797 if (!get_type_die(&return_type_die, subroutine)) {
798 result->return_info = type_get_simple(ARGTYPE_VOID);
799 result->own_return_info = 0;
801 result->return_info = calloc(1, sizeof(struct arg_type_info));
802 if (result->return_info == NULL) {
803 complain(subroutine, "Couldn't alloc return type");
804 CLEANUP_AND_RETURN_ERROR(NULL);
806 result->own_return_info = 1;
808 int newly_allocated_return_type;
809 result->return_info = get_type(&newly_allocated_return_type,
810 &return_type_die, plib, type_dieoffset_hash);
811 if(result->return_info == NULL) {
812 complain(subroutine, "Couldn't get return type");
813 CLEANUP_AND_RETURN_ERROR(NULL);
815 result->own_return_info = newly_allocated_return_type;
819 // Now look at the arguments
821 if (dwarf_child(subroutine, &arg_die) != 0) {
822 // no args. We're done
827 if (dwarf_tag(&arg_die) == DW_TAG_formal_parameter) {
829 complain(&arg_die, "arg: 0x%02x", dwarf_tag(&arg_die));
831 argument_type = NULL;
832 newly_allocated_argument_type = false;
835 if (!get_type_die(&type_die, &arg_die)) {
836 complain(&arg_die, "Couldn't get the argument type die");
837 CLEANUP_AND_RETURN_ERROR(NULL);
841 argument_type = get_type(&newly_allocated_argument_type,
842 &type_die, plib, type_dieoffset_hash);
843 if(argument_type==NULL) {
844 complain(&arg_die, "Couldn't parse arg type from DWARF data");
845 CLEANUP_AND_RETURN_ERROR(NULL);
849 param_init_type(¶m, argument_type, newly_allocated_argument_type);
850 if (prototype_push_param(result, ¶m) <0) {
851 complain(&arg_die, "couldn't add argument to the prototype");
852 CLEANUP_AND_RETURN_ERROR(NULL);
855 #ifdef DUMP_PROTOTYPES
856 fprintf(stderr, "Adding argument:\n");
857 dump_ltrace_tree(argument_type);
861 NEXT_SIBLING(&arg_die);
865 #undef CLEANUP_AND_RETURN_ERROR
868 static bool import_subprogram(struct protolib* plib, struct library* lib,
869 struct dict* type_dieoffset_hash,
872 // I use the linkage function name if there is one, otherwise the
874 const char* function_name = NULL;
875 Dwarf_Attribute attr;
876 if (dwarf_attr(die, DW_AT_linkage_name, &attr) != NULL)
877 function_name = dwarf_formstring(&attr);
878 if (function_name == NULL)
879 function_name = dwarf_diename(die);
880 if (function_name == NULL) {
881 complain(die, "Function has no name. Not importing");
885 if (!filter_matches_symbol(options.plt_filter, function_name, lib) &&
886 !filter_matches_symbol(options.static_filter, function_name, lib) &&
887 !filter_matches_symbol(options.export_filter, function_name, lib)) {
888 complain(die, "Prototype not requested by any filter");
892 complain(die, "subroutine_type: 0x%02x; function '%s'",
893 dwarf_tag(die), function_name);
895 struct prototype* proto =
896 protolib_lookup_prototype(plib, function_name, false);
899 complain(die, "Prototype already exists. Skipping");
903 proto = get_prototype(die, plib, type_dieoffset_hash);
905 complain(die, "couldn't get prototype");
909 const char* function_name_dup = strdup(function_name);
910 if( function_name_dup == NULL ) {
911 complain(die, "couldn't strdup");
912 prototype_destroy(proto);
916 protolib_add_prototype(plib, function_name_dup, 1, proto);
920 static bool process_die_compileunit(struct protolib* plib, struct library* lib,
921 struct dict* type_dieoffset_hash,
925 if (dwarf_child(parent, &die) != 0) {
926 // no child nodes, so nothing to do
931 if (dwarf_tag(&die) == DW_TAG_subprogram)
932 if(!import_subprogram(plib, lib, type_dieoffset_hash, &die))
933 complain(&die, "Error importing subprogram. Skipping");
941 static void import(struct protolib* plib, struct library* lib, Dwfl* dwfl)
943 // A map from DIE addresses (Dwarf_Off) to type structures (struct
944 // arg_type_info*). This is created and filled in at the start of each
945 // import, and deleted when the import is complete
946 struct dict type_dieoffset_hash;
948 dict_init(&type_dieoffset_hash, sizeof(Dwarf_Off), sizeof(struct arg_type_info*),
949 dwarf_die_hash, dwarf_die_eq, NULL);
952 Dwarf_Die* die = NULL;
953 while ((die = dwfl_nextcu(dwfl, die, &bias)) != NULL) {
954 if (dwarf_tag(die) == DW_TAG_compile_unit)
955 process_die_compileunit(plib, lib, &type_dieoffset_hash, die);
957 complain(die, "A DW_TAG_compile_unit die expected. Skipping this one");
960 dict_destroy(&type_dieoffset_hash, NULL, NULL, NULL);
963 bool import_DWARF_prototypes(struct library* lib)
965 struct protolib* plib = lib->protolib;
966 Dwfl* dwfl = lib->dwfl;
970 const char* soname_dup = strdup(lib->soname);
971 if( soname_dup == NULL ) {
972 fprintf(stderr, "couldn't strdup");
976 plib = protolib_cache_default(&g_protocache, soname_dup, 1);
978 fprintf(stderr, "Error loading protolib %s: %s.\n",
979 lib->soname, strerror(errno));
983 import(plib, lib, dwfl);
984 lib->protolib = plib;