diff options
author | Dima Kogan <dima@secretsauce.net> | 2014-04-30 03:35:13 -0700 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-08-22 20:38:25 +0900 |
commit | 1cf72c97626b03d56e9a6f0dd6090228e23a56ec (patch) | |
tree | 556748c1750b3f6bbd954e457f8f68db554f47de | |
parent | 8a5eaa17e9ce6ba947c710deb88cff3c533a53ec (diff) | |
download | ltrace-1cf72c97626b03d56e9a6f0dd6090228e23a56ec.tar.gz ltrace-1cf72c97626b03d56e9a6f0dd6090228e23a56ec.tar.bz2 ltrace-1cf72c97626b03d56e9a6f0dd6090228e23a56ec.zip |
reworked error and memory handling
I now longer exit() on the slightest sign of trouble, nor do I leak all my heap
memory allocations
-rw-r--r-- | dwarf_prototypes.c | 538 |
1 files changed, 363 insertions, 175 deletions
diff --git a/dwarf_prototypes.c b/dwarf_prototypes.c index ec39758..48d2673 100644 --- a/dwarf_prototypes.c +++ b/dwarf_prototypes.c @@ -43,8 +43,9 @@ if (res < 0) return false; /* error */ \ break /* no sibling exists */ -static bool get_type(struct arg_type_info** info, Dwarf_Die* type_die, struct protolib* plib, - struct dict* type_dieoffset_hash); +static struct arg_type_info* get_type(int* newly_allocated_info, + Dwarf_Die* type_die, struct protolib* plib, + struct dict* type_dieoffset_hash); #if 0 @@ -214,6 +215,8 @@ static bool get_integer_base_type(enum arg_type* type, int byte_size, bool is_si } } +// returns an ltrace ARGTYPE_XXX base type from the given die. If we dont +// support a particular type (or an error occurred), I regturn ARGTYPE_VOID static enum arg_type get_base_type(Dwarf_Die* die) { int64_t encoding; @@ -289,6 +292,9 @@ static bool get_type_die(Dwarf_Die* type_die, Dwarf_Die* die) dwarf_formref_die(&attr, type_die) != NULL; } + + +// type_dieoffset_hash dictionary callbacks static size_t dwarf_die_hash(const void* x) { return *(const Dwarf_Off*)x; @@ -298,124 +304,212 @@ static int dwarf_die_eq(const void* a, const void* b) return *(const Dwarf_Off*)a == *(const Dwarf_Off*)b; } -static bool get_enum(struct arg_type_info* enum_info, Dwarf_Die* parent) + +// returns a newly-allocated art_type_info*, or NULL on error +static struct arg_type_info* get_enum(Dwarf_Die* parent, struct dict* type_dieoffset_hash) { + +#define CLEANUP_AND_RETURN_ERROR(ret) do { \ + if(dupkey != NULL) \ + free((void*)dupkey); \ + if(value != NULL) { \ + value_destroy(value); \ + free(value); \ + } \ + if(lens != NULL ) { \ + lens_destroy(&lens->super); \ + free(lens); \ + } \ + if(result != NULL) { \ + type_destroy(result); \ + free(result); \ + } \ + dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \ + dict_insert(type_dieoffset_hash, &die_offset, \ + &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \ + return ret; \ + } while(0) + + struct arg_type_info* result = NULL; + struct enum_lens* lens = NULL; + const char* dupkey = NULL; + struct value* value = NULL; + + Dwarf_Off die_offset = dwarf_dieoffset(parent); + + result = calloc(1, sizeof(struct arg_type_info)); + if (result == NULL) { + complain(type_die, "alloc error"); + CLEANUP_AND_RETURN_ERROR(NULL); + } + + dict_insert(type_dieoffset_hash, &die_offset, &result); + uint64_t byte_size; if (!get_die_numeric(&byte_size, parent, DW_AT_byte_size)) { // No byte size given, assume 'int' - enum_info->type = ARGTYPE_INT; + result->type = ARGTYPE_INT; } else { - if(!get_integer_base_type(&enum_info->type, (int)byte_size, true)) { + if(!get_integer_base_type(&result->type, (int)byte_size, true)) { complain(parent, "Unknown integer base type. Using 'int'"); - enum_info->type = ARGTYPE_INT; + result->type = ARGTYPE_INT; } } - struct enum_lens *lens = calloc(1, sizeof(struct enum_lens)); + lens = calloc(1, sizeof(struct enum_lens)); if (lens == NULL) { complain(parent, "alloc error"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } lens_init_enum(lens); - enum_info->lens = &lens->super; + result->lens = &lens->super; + result->own_lens = 1; Dwarf_Die die; if (dwarf_child(parent, &die) != 0) { // empty enum. we're done - return true; + CLEANUP_AND_RETURN_ERROR(NULL); } + while(1) { complain(&die, "enum element: 0x%02x/'%s'", dwarf_tag(&die), dwarf_diename(&die)); + dupkey = NULL; + value = NULL; + if (dwarf_tag(&die) != DW_TAG_enumerator) { complain(&die, "Enums can have ONLY DW_TAG_enumerator elements"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } if (!dwarf_hasattr(&die, DW_AT_const_value)) { complain(&die, "Enums MUST have DW_AT_const_value values"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } const char* key = dwarf_diename(&die); if (key == NULL) { complain(&die, "Enums must have a DW_AT_name key"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } - const char* dupkey = strdup(key); + dupkey = strdup(key); if (dupkey == NULL) { complain(&die, "Couldn't duplicate enum key"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } - struct value* value = calloc(1, sizeof(struct value)); + value = calloc(1, sizeof(struct value)); if (value == NULL) { complain(&die, "Couldn't alloc enum value"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } - value_init_detached(value, NULL, type_get_simple(enum_info->type), 0); + value_init_detached(value, NULL, type_get_simple(result->type), 0); uint64_t enum_value; if (!get_die_numeric(&enum_value, &die, DW_AT_const_value)) { complain(&die, "Couldn't get enum value"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } value_set_word(value, (long)enum_value); - if (lens_enum_add(lens, dupkey, 0, value, 0)) { + if (lens_enum_add(lens, dupkey, 1, value, 1)) { complain(&die, "Couldn't add enum element"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } NEXT_SIBLING(&die); } - return true; + return result; + +#undef CLEANUP_AND_RETURN_ERROR } -static bool get_array(struct arg_type_info* array_info, Dwarf_Die* parent, struct protolib* plib, - struct dict* type_dieoffset_hash) +// returns a newly-allocated art_type_info*, or NULL on error +static struct arg_type_info* get_array( Dwarf_Die* parent, struct protolib* plib, + struct dict* type_dieoffset_hash) { + +#define CLEANUP_AND_RETURN_ERROR(ret) do { \ + if(value != NULL) { \ + value_destroy(value); \ + free(value); \ + } \ + if(length != NULL) { \ + expr_destroy(length); \ + free(length); \ + } \ + if(array_type != NULL && newly_allocated_array_type) { \ + type_destroy(array_type); \ + free(array_type); \ + } \ + if(result != NULL) { \ + type_destroy(result); \ + free(result); \ + } \ + dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \ + dict_insert(type_dieoffset_hash, &die_offset, \ + &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \ + return ret; \ + } while(0) + + + struct arg_type_info* result = NULL; + struct value* value = NULL; + struct expr_node* length = NULL; + struct arg_type_info* array_type = NULL; + int newly_allocated_array_type = 0; + + Dwarf_Off die_offset = dwarf_dieoffset(parent); + + result = calloc(1, sizeof(struct arg_type_info)); + if (result == NULL) { + complain(type_die, "alloc error"); + CLEANUP_AND_RETURN_ERROR(NULL); + } + Dwarf_Die type_die; if (!get_type_die(&type_die, parent)) { complain(parent, "Array has unknown type"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } - struct arg_type_info* info; - if (!get_type(&info, &type_die, plib, type_dieoffset_hash)) { + dict_insert(type_dieoffset_hash, &die_offset, &result); + array_type = get_type(&newly_allocated_array_type, + &type_die, plib, type_dieoffset_hash); + if( array_type == NULL ) { complain(parent, "Couldn't figure out array's type"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } Dwarf_Die subrange; if (dwarf_child(parent, &subrange) != 0) { complain(parent, "Array must have a DW_TAG_subrange_type child, but has none"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } Dwarf_Die next_subrange; if (dwarf_siblingof(&subrange, &next_subrange) <= 0) { complain(parent, "Array must have exactly one DW_TAG_subrange_type child"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } if (dwarf_hasattr(&subrange, DW_AT_lower_bound)) { uint64_t lower_bound; if (!get_die_numeric(&lower_bound, &subrange, DW_AT_lower_bound)) { complain(parent, "Couldn't read lower bound"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } if (lower_bound != 0) { complain(parent, "Array subrange has a nonzero lower bound. Don't know what to do"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } } @@ -429,7 +523,7 @@ static bool get_array(struct arg_type_info* array_info, Dwarf_Die* parent, struc { if (!get_die_numeric(&N, &subrange, DW_AT_upper_bound)) { complain(parent, "Couldn't read upper bound"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } N++; } @@ -437,75 +531,139 @@ static bool get_array(struct arg_type_info* array_info, Dwarf_Die* parent, struc // I'm not checking the subrange type. It should be some sort of integer, // and I don't know what it would mean for it to be something else - struct value* value = calloc(1, sizeof(struct value)); + value = calloc(1, sizeof(struct value)); if (value == NULL) { complain(&subrange, "Couldn't alloc length value"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } value_init_detached(value, NULL, type_get_simple(ARGTYPE_INT), 0); value_set_word(value, N); - struct expr_node* length = calloc(1, sizeof(struct expr_node)); + length = calloc(1, sizeof(struct expr_node)); if (length == NULL) { complain(&subrange, "Couldn't alloc length expr"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } expr_init_const(length, value); - type_init_array(array_info, info, 0, length, 0); + type_init_array(result, array_type, newly_allocated_array_type, + length, 1); + return result; - return true; +#undef CLEANUP_AND_RETURN_ERROR } -static bool get_structure(struct arg_type_info* struct_info, Dwarf_Die* parent, struct protolib* plib, - struct dict* type_dieoffset_hash) +// returns a newly-allocated art_type_info*, or NULL on error +static struct arg_type_info* get_structure(Dwarf_Die* parent, struct protolib* plib, + struct dict* type_dieoffset_hash) { - type_init_struct(struct_info); + +#define CLEANUP_AND_RETURN_ERROR(ret) do { \ + if(member_type != NULL && newly_allocated_member_type) { \ + type_destroy(member_type); \ + free(member_type); \ + } \ + if(result != NULL) { \ + type_destroy(result); \ + free(result); \ + } \ + dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \ + dict_insert(type_dieoffset_hash, &die_offset, \ + &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \ + return ret; \ + } while(0) + + + struct arg_type_info* result = NULL; + struct arg_type_info* member_type = NULL; + int newly_allocated_member_type = 0; + + Dwarf_Off die_offset = dwarf_dieoffset(parent); + + result = calloc(1, sizeof(struct arg_type_info)); + if (result == NULL) { + complain(type_die, "alloc error"); + CLEANUP_AND_RETURN_ERROR(NULL); + } + type_init_struct(result); + dict_insert(type_dieoffset_hash, &die_offset, &result); Dwarf_Die die; if (dwarf_child(parent, &die) != 0) { // no elements; we're done - return true; + return result; } while(1) { + member_type = NULL; + newly_allocated_member_type = 0; + complain(&die, "member: 0x%02x", dwarf_tag(&die)); if (dwarf_tag(&die) != DW_TAG_member) { complain(&die, "Structure can have ONLY DW_TAG_member"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } Dwarf_Die type_die; if (!get_type_die(&type_die, &die)) { complain(&die, "Couldn't get type of element"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } - struct arg_type_info* member_info = NULL; - if (!get_type(&member_info, &type_die, plib, type_dieoffset_hash)) { + member_type = get_type(&newly_allocated_member_type, + &type_die, plib, type_dieoffset_hash); + if(member_type == NULL) { complain(&die, "Couldn't parse type from DWARF data"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } - type_struct_add(struct_info, member_info, 0); + type_struct_add(result, member_type, newly_allocated_member_type); NEXT_SIBLING(&die); } - return true; + return result; +#undef CLEANUP_AND_RETURN_ERROR } -// Reads the type in the die into the given structure -// Returns true on sucess -static bool get_type(struct arg_type_info** info, Dwarf_Die* type_die, struct protolib* plib, - struct dict* type_dieoffset_hash) +// Reads the type in the die and returns the corresponding arg_type_info*. If +// this was newly allocated on the heap, *newly_allocated_info = true. If an +// error occurred, returns NULL +static struct arg_type_info* get_type(int* newly_allocated_result, + Dwarf_Die* type_die, struct protolib* plib, + struct dict* type_dieoffset_hash) { + +#define CLEANUP_AND_RETURN_ERROR(ret) do { \ + if(pointee != NULL && newly_allocated_pointee) { \ + type_destroy(pointee); \ + free(pointee); \ + } \ + if(result != NULL && *newly_allocated_result) { \ + type_destroy(result); \ + free(result); \ + } \ + dict_erase (type_dieoffset_hash, &die_offset, NULL, NULL, NULL); \ + dict_insert(type_dieoffset_hash, &die_offset, \ + &(struct arg_type_info*){type_get_simple(ARGTYPE_VOID)}); \ + return ret; \ + } while(0) + + struct arg_type_info* result = NULL; + struct arg_type_info* pointee = NULL; + int newly_allocated_pointee = 0; + Dwarf_Off die_offset = dwarf_dieoffset(type_die); + + + // by default, we say we allocated nothing. I set this to true later, when I + // allocate memory + *newly_allocated_result = 0; + struct arg_type_info** found_type = dict_find(type_dieoffset_hash, &die_offset); if (found_type != NULL) { - *info = *found_type; - complain(type_die, "Read pre-computed type: %p", *info); - return true; + complain(type_die, "Read pre-computed type"); + return *found_type; } const char* type_name = dwarf_diename(type_die); @@ -518,8 +676,7 @@ static bool get_type(struct arg_type_info** info, Dwarf_Die* type_die, struct pr complain(type_die, "Type '%s' defined in a .conf file. Using that instead of DWARF", type_name); - *info = already_defined_type->info; - return true; + return already_defined_type->info; } } @@ -527,130 +684,163 @@ static bool get_type(struct arg_type_info** info, Dwarf_Die* type_die, struct pr switch (dwarf_tag(type_die)) { case DW_TAG_base_type: - *info = type_get_simple(get_base_type(type_die)); - complain(type_die, "Storing base type: %p", *info); - dict_insert(type_dieoffset_hash, &die_offset, info); - return true; + complain(type_die, "Storing base type"); + result = type_get_simple(get_base_type(type_die)); + dict_insert(type_dieoffset_hash, &die_offset, &result); + return result; case DW_TAG_subroutine_type: case DW_TAG_inlined_subroutine: // function pointers are stored as void*. If ltrace tries to dereference // these, it'll get a segfault - *info = type_get_simple(ARGTYPE_VOID); - complain(type_die, "Storing subroutine type: %p", *info); - dict_insert(type_dieoffset_hash, &die_offset, info); - return true; + complain(type_die, "Storing subroutine type"); + result = type_get_simple(ARGTYPE_VOID); + dict_insert(type_dieoffset_hash, &die_offset, &result); + return result; case DW_TAG_pointer_type: - if (!get_type_die(&next_die, type_die)) { // the pointed-to type isn't defined, so I report a void* - *info = type_get_voidptr(); - complain(type_die, "Storing void-pointer type: %p", *info); - dict_insert(type_dieoffset_hash, &die_offset, info); - return true; + complain(type_die, "Storing void-pointer type"); + result = type_get_voidptr(); + dict_insert(type_dieoffset_hash, &die_offset, &result); + return result; } - *info = calloc(1, sizeof(struct arg_type_info)); - if (*info == NULL) { + complain(type_die, "Storing pointer type"); + + *newly_allocated_result = 1; + result = calloc(1, sizeof(struct arg_type_info)); + if (result == NULL) { complain(type_die, "alloc error"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } - type_init_pointer(*info, NULL, 0); + dict_insert(type_dieoffset_hash, &die_offset, &result); + pointee = get_type(&newly_allocated_pointee, + &next_die, plib, type_dieoffset_hash); + if(pointee == NULL) + CLEANUP_AND_RETURN_ERROR(NULL); - complain(type_die, "Storing pointer type: %p", *info); - dict_insert(type_dieoffset_hash, &die_offset, info); - return get_type(&(*info)->u.ptr_info.info, &next_die, plib, type_dieoffset_hash); + type_init_pointer(result, pointee, newly_allocated_pointee); + return result; case DW_TAG_structure_type: - *info = calloc(1, sizeof(struct arg_type_info)); - if (*info == NULL) { - complain(type_die, "alloc error"); - return false; - } + complain(type_die, "Storing struct type"); + *newly_allocated_result = 1; - complain(type_die, "Storing struct type: %p", *info); - dict_insert(type_dieoffset_hash, &die_offset, info); - return get_structure(*info, type_die, plib, type_dieoffset_hash); + result = get_structure(type_die, plib, type_dieoffset_hash); + if(result == NULL) + CLEANUP_AND_RETURN_ERROR(NULL); + return result; case DW_TAG_typedef: case DW_TAG_const_type: - case DW_TAG_volatile_type: { + case DW_TAG_volatile_type: // Various tags are simply pass-through, so I just keep going - bool res = true; if (get_type_die(&next_die, type_die)) { - complain(type_die, "Storing const/typedef type: %p", *info); - res = get_type(info, &next_die, plib, type_dieoffset_hash); + complain(type_die, "Storing const/typedef type"); + + result = get_type(newly_allocated_result, &next_die, + plib, type_dieoffset_hash); + if(result == NULL) + CLEANUP_AND_RETURN_ERROR(NULL); } else { // no type. Use 'void'. Normally I'd think this is bogus, but stdio // typedefs something to void - *info = type_get_simple(ARGTYPE_VOID); - complain(type_die, "Storing void type: %p", *info); + result = type_get_simple(ARGTYPE_VOID); + complain(type_die, "Storing void type"); } - if (res) - dict_insert(type_dieoffset_hash, &die_offset, info); - return res; - } + dict_insert(type_dieoffset_hash, &die_offset, &result); + return result; case DW_TAG_enumeration_type: - // We have an enumeration. This has type "int", but has a particular + // We have an enumeration. This has a base type, but has a particular // lens to handle the enum - *info = calloc(1, sizeof(struct arg_type_info)); - if (*info == NULL) { - complain(type_die, "alloc error"); - return false; - } + *newly_allocated_result = 1; - complain(type_die, "Storing enum int: %p", *info); - dict_insert(type_dieoffset_hash, &die_offset, info); - return get_enum(*info, type_die); + complain(type_die, "Storing enum int"); + result = get_enum(type_die, type_dieoffset_hash); + if(result == NULL) + CLEANUP_AND_RETURN_ERROR(NULL); + return result; case DW_TAG_array_type: - *info = calloc(1, sizeof(struct arg_type_info)); - if (*info == NULL) { - complain(type_die, "alloc error"); - return false; - } + *newly_allocated_result = 1; - complain(type_die, "Storing array: %p", *info); - dict_insert(type_dieoffset_hash, &die_offset, info); - return get_array(*info, type_die, plib, type_dieoffset_hash); + complain(type_die, "Storing array"); + result = get_array(type_die, plib, type_dieoffset_hash); + if(result == NULL) + CLEANUP_AND_RETURN_ERROR(NULL); + return result; case DW_TAG_union_type: - *info = type_get_simple(ARGTYPE_VOID); - complain(type_die, "Storing union-as-void type: %p", *info); - return true; + result = type_get_simple(ARGTYPE_VOID); + complain(type_die, "Storing union-as-void type"); + dict_insert(type_dieoffset_hash, &die_offset, &result); + return result; default: - complain(type_die, "Unknown type tag 0x%x", dwarf_tag(type_die)); - break; + complain(type_die, "Unknown type tag 0x%x. Returning void", dwarf_tag(type_die)); + result = type_get_simple(ARGTYPE_VOID); + dict_insert(type_dieoffset_hash, &die_offset, &result); + return result; } - return false; +#undef CLEANUP_AND_RETURN_ERROR } -static bool get_prototype(struct prototype* proto, Dwarf_Die* subroutine, struct protolib* plib, - struct dict* type_dieoffset_hash) +// returns a newly-allocated prototype*, or NULL on error +static struct prototype* get_prototype( Dwarf_Die* subroutine, struct protolib* plib, + struct dict* type_dieoffset_hash) { + +#define CLEANUP_AND_RETURN_ERROR(ret) do { \ + if(argument_type != NULL && newly_allocated_argument_type) { \ + type_destroy(argument_type); \ + free(argument_type); \ + } \ + if(result != NULL) { \ + prototype_destroy(result); \ + free(result); \ + } \ + return ret; \ + } while(0) + + + struct prototype* result = NULL; + struct arg_type_info* argument_type = NULL; + int newly_allocated_argument_type = 0; + + result = calloc(1, sizeof(struct prototype)); + if (result == NULL) { + complain(die, "couldn't alloc prototype"); + CLEANUP_AND_RETURN_ERROR(NULL); + } + prototype_init(result); + // First, look at the return type. This is stored in a DW_AT_type tag in the // subroutine DIE. If there is no such tag, this function returns void Dwarf_Die return_type_die; if (!get_type_die(&return_type_die, subroutine)) { - proto->return_info = type_get_simple(ARGTYPE_VOID); - proto->own_return_info = 0; + result->return_info = type_get_simple(ARGTYPE_VOID); + result->own_return_info = 0; } else { - proto->return_info = calloc(1, sizeof(struct arg_type_info)); - if (proto->return_info == NULL) { + result->return_info = calloc(1, sizeof(struct arg_type_info)); + if (result->return_info == NULL) { complain(subroutine, "Couldn't alloc return type"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } - proto->own_return_info = 0; + result->own_return_info = 1; - if (!get_type(&proto->return_info, &return_type_die, plib, type_dieoffset_hash)) { + int newly_allocated_return_type; + result->return_info = get_type(&newly_allocated_return_type, + &return_type_die, plib, type_dieoffset_hash); + if(result->return_info == NULL) { complain(subroutine, "Couldn't get return type"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } + result->own_return_info = newly_allocated_return_type; } @@ -658,7 +848,7 @@ static bool get_prototype(struct prototype* proto, Dwarf_Die* subroutine, struct Dwarf_Die arg_die; if (dwarf_child(subroutine, &arg_die) != 0) { // no args. We're done - return true; + return result; } while(1) { @@ -666,35 +856,41 @@ static bool get_prototype(struct prototype* proto, Dwarf_Die* subroutine, struct complain(&arg_die, "arg: 0x%02x", dwarf_tag(&arg_die)); + argument_type = NULL; + newly_allocated_argument_type = false; + Dwarf_Die type_die; if (!get_type_die(&type_die, &arg_die)) { complain(&arg_die, "Couldn't get the argument type die"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } - struct arg_type_info* arg_type_info = NULL; - if (!get_type(&arg_type_info, &type_die, plib, type_dieoffset_hash)) { + + argument_type = get_type(&newly_allocated_argument_type, + &type_die, plib, type_dieoffset_hash); + if(argument_type==NULL) { complain(&arg_die, "Couldn't parse arg type from DWARF data"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } struct param param; - param_init_type(¶m, arg_type_info, 0); - if (prototype_push_param(proto, ¶m) <0) { + param_init_type(¶m, argument_type, newly_allocated_argument_type); + if (prototype_push_param(result, ¶m) <0) { complain(&arg_die, "couldn't add argument to the prototype"); - return false; + CLEANUP_AND_RETURN_ERROR(NULL); } #ifdef DUMP_PROTOTYPES fprintf(stderr, "Adding argument:\n"); - dump_ltrace_tree(arg_type_info); + dump_ltrace_tree(argument_type); #endif } NEXT_SIBLING(&arg_die); } - return true; + return result; +#undef CLEANUP_AND_RETURN_ERROR } static bool import_subprogram(struct protolib* plib, struct library* lib, @@ -732,19 +928,20 @@ static bool import_subprogram(struct protolib* plib, struct library* lib, return true; } - proto = malloc(sizeof(struct prototype)); - if (proto == NULL) { - complain(die, "couldn't alloc prototype"); + proto = get_prototype(die, plib, type_dieoffset_hash); + if(proto == NULL) { + complain(die, "couldn't get prototype"); return false; } - prototype_init(proto); - if (!get_prototype(proto, die, plib, type_dieoffset_hash)) { - complain(die, "couldn't get prototype"); + const char* function_name_dup = strdup(function_name); + if( function_name_dup == NULL ) { + complain(die, "couldn't strdup"); + prototype_destroy(proto); + free(proto); return false; } - - protolib_add_prototype(plib, function_name, 0, proto); + protolib_add_prototype(plib, function_name_dup, 1, proto); return true; } @@ -761,7 +958,7 @@ static bool process_die_compileunit(struct protolib* plib, struct library* lib, while (1) { if (dwarf_tag(&die) == DW_TAG_subprogram) if(!import_subprogram(plib, lib, type_dieoffset_hash, &die)) - return false; + complain(&die, "Error importing subprogram. Skipping"); NEXT_SIBLING(&die); } @@ -769,7 +966,7 @@ static bool process_die_compileunit(struct protolib* plib, struct library* lib, return true; } -static bool import(struct protolib* plib, struct library* lib, Dwfl* dwfl) +static void import(struct protolib* plib, struct library* lib, Dwfl* dwfl) { // A map from DIE addresses (Dwarf_Off) to type structures (struct // arg_type_info*). This is created and filled in at the start of each @@ -779,30 +976,16 @@ static bool import(struct protolib* plib, struct library* lib, Dwfl* dwfl) dict_init(&type_dieoffset_hash, sizeof(Dwarf_Off), sizeof(struct arg_type_info*), dwarf_die_hash, dwarf_die_eq, NULL); - bool result = true; - Dwarf_Addr bias; Dwarf_Die* die = NULL; while ((die = dwfl_nextcu(dwfl, die, &bias)) != NULL) { - if (dwarf_tag(die) == DW_TAG_compile_unit) { - if (!process_die_compileunit(plib, lib, &type_dieoffset_hash, die)) { - complain(die, "Error reading compile unit"); - exit(1); - - result = false; - break; - } - } else { - complain(die, "DW_TAG_compile_unit expected"); - exit(1); - - result = false; - break; - } + if (dwarf_tag(die) == DW_TAG_compile_unit) + process_die_compileunit(plib, lib, &type_dieoffset_hash, die); + else + complain(die, "A DW_TAG_compile_unit die expected. Skipping this one"); } dict_destroy(&type_dieoffset_hash, NULL, NULL, NULL); - return result; } bool import_DWARF_prototypes(struct library* lib) @@ -811,18 +994,24 @@ bool import_DWARF_prototypes(struct library* lib) Dwfl* dwfl = lib->dwfl; if (plib == NULL) { - plib = protolib_cache_default(&g_protocache, lib->soname, 0); + + const char* soname_dup = strdup(lib->soname); + if( soname_dup == NULL ) { + fprintf(stderr, "couldn't strdup"); + return false; + } + + plib = protolib_cache_default(&g_protocache, soname_dup, 1); if (plib == NULL) { fprintf(stderr, "Error loading protolib %s: %s.\n", lib->soname, strerror(errno)); } } - if (import(plib, lib, dwfl)) { - lib->protolib = plib; - return true; - } - return false; + import(plib, lib, dwfl); + lib->protolib = plib; + + return true; } /* @@ -836,5 +1025,4 @@ bool import_DWARF_prototypes(struct library* lib) - all my *allocs leak - */ |