[ltrace-commits] 26/40: reworked error and memory handling

Petr Machata pmachata-guest at moszumanska.debian.org
Sun May 11 22:38:54 UTC 2014


This is an automated email from the git hooks/post-receive script.

pmachata-guest pushed a commit to branch master
in repository ltrace.

commit 154657d0c1ad529c7856c0fea34cb5da26b5867a
Author: Dima Kogan <dima at secretsauce.net>
Date:   Wed Apr 30 03:35:13 2014 -0700

    reworked error and memory handling
    
    I now longer exit() on the slightest sign of trouble, nor do I leak all my heap
    memory allocations
---
 dwarf_prototypes.c | 538 ++++++++++++++++++++++++++++++++++++-----------------
 1 file 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
 
-
 */

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/ltrace.git



More information about the ltrace-commits mailing list