summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDima Kogan <dima@secretsauce.net>2014-04-30 03:35:13 -0700
committerChanho Park <chanho61.park@samsung.com>2014-08-22 20:38:25 +0900
commit1cf72c97626b03d56e9a6f0dd6090228e23a56ec (patch)
tree556748c1750b3f6bbd954e457f8f68db554f47de
parent8a5eaa17e9ce6ba947c710deb88cff3c533a53ec (diff)
downloadltrace-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.c538
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(&param, arg_type_info, 0);
- if (prototype_push_param(proto, &param) <0) {
+ param_init_type(&param, argument_type, newly_allocated_argument_type);
+ if (prototype_push_param(result, &param) <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
-
*/