[PATCH v1 4/6] makedumpfile: Introduce routines to get type name from debuginfo.

Mahesh J Salgaonkar mahesh at linux.vnet.ibm.com
Fri Mar 11 03:05:12 EST 2011


From: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>

This patch implements following routines that returns type, type name and
size of kernel symbol/member using dwarf info:

	char *get_symbol_type_name();
	char *get_member_type_name();
	long get_pointer_size();

These routines will be used to resolve symbol/member information specified
through filter config commands.

Signed-off-by: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>
Signed-off-by: Prerna Saxena <prerna at linux.vnet.ibm.com>
---

 makedumpfile.c |  142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 makedumpfile.h |   13 +++++
 2 files changed, 148 insertions(+), 7 deletions(-)

diff --git a/makedumpfile.c b/makedumpfile.c
index 7601e3d..f7d37cc 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -30,6 +30,7 @@ struct module_sym_table	mod_st = { 0 };
 
 char filename_stdout[] = FILENAME_STDOUT;
 int message_level;
+long pointer_size;
 
 /*
  * Forward declarations
@@ -1822,6 +1823,41 @@ check_array_type(Dwarf *dwarfd, Dwarf_Die *die)
 	return TRUE;
 }
 
+static int
+get_dwarf_base_type(Dwarf *dwarfd, Dwarf_Die *die)
+{
+	int tag;
+	const char *name;
+
+	while (get_die_type(dwarfd, die, die)) {
+		tag = dwarf_tag(die);
+		switch (tag) {
+		case DW_TAG_array_type:
+			dwarf_info.type_flag |= TYPE_ARRAY;
+			break;
+		case DW_TAG_pointer_type:
+			dwarf_info.type_flag |= TYPE_PTR;
+			break;
+		case DW_TAG_structure_type:
+			dwarf_info.type_flag |= TYPE_STRUCT;
+			break;
+		case DW_TAG_base_type:
+			dwarf_info.type_flag |= TYPE_BASE;
+			break;
+		}
+	}
+
+	name = dwarf_diename(die);
+	if (name)
+		dwarf_info.type_name = strdup(name);
+	else if (dwarf_info.type_flag == TYPE_PTR)
+		dwarf_info.type_name = strdup("void");
+
+	dwarf_info.struct_size = dwarf_bytesize(die);
+
+	return TRUE;
+}
+
 /*
  * Function for searching struct page.union.struct.mapping.
  */
@@ -1902,6 +1938,15 @@ search_member(Dwarf *dwarfd, Dwarf_Die *die)
 			continue;
 
 		switch (dwarf_info.cmd) {
+		case DWARF_INFO_GET_MEMBER_TYPE:
+			if ((!name) || strcmp(name, dwarf_info.member_name))
+				continue;
+			/*
+			 * Get the member offset.
+			 */
+			if (!get_dwarf_base_type(dwarfd, walker))
+				continue;
+			return;
 		case DWARF_INFO_GET_MEMBER_OFFSET:
 			if ((!name) || strcmp(name, dwarf_info.member_name))
 				continue;
@@ -1964,6 +2009,7 @@ is_search_structure(int cmd)
 {
 	if ((cmd == DWARF_INFO_GET_STRUCT_SIZE)
 	    || (cmd == DWARF_INFO_GET_MEMBER_OFFSET)
+	    || (cmd == DWARF_INFO_GET_MEMBER_TYPE)
 	    || (cmd == DWARF_INFO_GET_MEMBER_OFFSET_IN_UNION)
 	    || (cmd == DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION)
 	    || (cmd == DWARF_INFO_GET_MEMBER_ARRAY_LENGTH))
@@ -1985,6 +2031,7 @@ int
 is_search_symbol(int cmd)
 {
 	if ((cmd == DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH)
+	    || (cmd == DWARF_INFO_GET_SYMBOL_TYPE)
 	    || (cmd == DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE))
 		return TRUE;
 	else
@@ -2041,6 +2088,7 @@ search_structure(Dwarf *dwarfd, Dwarf_Die *die, int *found)
 	switch (dwarf_info.cmd) {
 	case DWARF_INFO_GET_STRUCT_SIZE:
 		break;
+	case DWARF_INFO_GET_MEMBER_TYPE:
 	case DWARF_INFO_GET_MEMBER_OFFSET:
 	case DWARF_INFO_GET_MEMBER_OFFSET_IN_UNION:
 	case DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION:
@@ -2173,6 +2221,9 @@ search_symbol(Dwarf *dwarfd, Dwarf_Die *die, int *found)
 	case DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE:
 		check_array_type(dwarfd, die);
 		break;
+	case DWARF_INFO_GET_SYMBOL_TYPE:
+		get_dwarf_base_type(dwarfd, die);
+		break;
 	}
 }
 
@@ -2249,6 +2300,10 @@ get_debug_info(void)
 	 */
 	while (dwarf_nextcu(dwarfd, off, &next_off, &header_size,
 	    &abbrev_offset, &address_size, &offset_size) == 0) {
+		if (dwarf_info.cmd == DWARF_INFO_GET_PTR_SIZE) {
+			dwarf_info.struct_size = address_size;
+			break;
+		}
 		off += header_size;
 		if (dwarf_offdie(dwarfd, off, &cu_die) == NULL) {
 			ERRMSG("Can't get CU die.\n");
@@ -2287,6 +2342,47 @@ get_structure_size(char *structname, int flag_typedef)
 }
 
 /*
+ * Get the size of pointer.
+ */
+long
+get_pointer_size()
+{
+	dwarf_info.cmd = DWARF_INFO_GET_PTR_SIZE;
+	/* reuse struct_size member to report pointer size */
+	dwarf_info.struct_size = NOT_FOUND_STRUCTURE;
+
+	if (!get_debug_info())
+		return FAILED_DWARFINFO;
+
+	return dwarf_info.struct_size;
+}
+
+/*
+ * Get the type of given symbol.
+ */
+char *
+get_symbol_type_name(char *symname, int cmd, long *size,
+					unsigned long *flag)
+{
+	dwarf_info.cmd = cmd;
+	dwarf_info.symbol_name = symname;
+	dwarf_info.type_name = NULL;
+	dwarf_info.struct_size = NOT_FOUND_STRUCTURE;
+	dwarf_info.type_flag = 0;
+
+	if (!get_debug_info())
+		return NULL;
+
+	if (size)
+		*size = dwarf_info.struct_size;
+
+	if (flag)
+		*flag = dwarf_info.type_flag;
+
+	return dwarf_info.type_name;
+}
+
+/*
  * Get the offset of member.
  */
 long
@@ -2305,6 +2401,35 @@ get_member_offset(char *structname, char *membername, int cmd)
 }
 
 /*
+ * Get the type name and size of member.
+ */
+char *
+get_member_type_name(char *structname, char *membername, int cmd, long *size,
+						unsigned long *flag)
+{
+	dwarf_info.cmd = cmd;
+	dwarf_info.struct_name = structname;
+	dwarf_info.struct_size = NOT_FOUND_STRUCTURE;
+	dwarf_info.member_name = membername;
+	dwarf_info.type_name = NULL;
+	dwarf_info.type_flag = 0;
+
+	if (!get_debug_info())
+		return NULL;
+
+	if (dwarf_info.struct_size == NOT_FOUND_STRUCTURE)
+		return NULL;
+
+	if (size)
+		*size = dwarf_info.struct_size;
+
+	if (flag)
+		*flag = dwarf_info.type_flag;
+
+	return dwarf_info.type_name;
+}
+
+/*
  * Get the length of array.
  */
 long
@@ -2402,6 +2527,8 @@ get_symbol_info(void)
 	if (SYMBOL(node_memblk) != NOT_FOUND_SYMBOL)
 		SYMBOL_ARRAY_LENGTH_INIT(node_memblk, "node_memblk");
 
+	pointer_size = get_pointer_size();
+
 	return TRUE;
 }
 
@@ -7519,13 +7646,16 @@ load_module_symbols(void)
 		for (nsym = 1; nsym < num_symtab; nsym++) {
 			Elf32_Sym *sym32;
 			Elf64_Sym *sym64;
-			/*
-			 * We can not depend on info->flag_elf64_memory if
-			 * the input vmcore file is kdump-compressed format.
-			 * We will fix this in the next patch and remove the
-			 * dependancy on info->flag_elf64_memory.
+			/* If case of ELF vmcore then the word size can be
+			 * determined using info->flag_elf64_memory flag.
+			 * But in case of kdump-compressed dump, kdump header
+			 * does not carry word size info. May be in future
+			 * this info will be available in kdump header.
+			 * Until then, in order to make this logic work on both
+			 * situation we depend on pointer_size that is
+			 * extracted from vmlinux dwarf information.
 			 */
-			if (info->flag_elf64_memory) {
+			if ((pointer_size * 8) == 64) {
 				sym64 = (Elf64_Sym *) (symtab_mem
 						+ (nsym * sizeof(Elf64_Sym)));
 				sym_info[nsym].value =
diff --git a/makedumpfile.h b/makedumpfile.h
index a21eaef..79ff56e 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -1242,7 +1242,10 @@ enum {
 	DWARF_INFO_GET_TYPEDEF_SIZE,
 	DWARF_INFO_GET_TYPEDEF_SRCNAME,
 	DWARF_INFO_GET_ENUM_NUMBER,
-	DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE
+	DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE,
+	DWARF_INFO_GET_SYMBOL_TYPE,
+	DWARF_INFO_GET_MEMBER_TYPE,
+	DWARF_INFO_GET_PTR_SIZE,
 };
 
 struct dwarf_info {
@@ -1257,13 +1260,21 @@ struct dwarf_info {
 	Elf	*elfd;			/* OUT */
 	Dwarf	*dwarfd;		/* OUT */
 	Dwfl	*dwfl;			/* OUT */
+	char	*type_name;		/* OUT */
 	long	struct_size;		/* OUT */
 	long	member_offset;		/* OUT */
 	long	array_length;		/* OUT */
 	long	enum_number;		/* OUT */
+	unsigned char	type_flag;	/* OUT */
 	char	src_name[LEN_SRCFILE];	/* OUT */
 };
 
+/* flags for dwarf_info.type_flag */
+#define TYPE_BASE	0x01
+#define TYPE_ARRAY	0x02
+#define TYPE_PTR	0x04
+#define TYPE_STRUCT	0x08
+
 extern struct dwarf_info	dwarf_info;
 
 int readmem(int type_addr, unsigned long long addr, void *bufptr, size_t size);




More information about the kexec mailing list