commit 94b2d0e2b0abb1a9dd1a0a39a1212162e37b2de4 Author: Mahesh Salgaonkar Date: Fri Aug 19 17:05:18 2011 +0900 [PATCH v2 4/8] Introduce routines to get type name from debuginfo. 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 Signed-off-by: Prerna Saxena --- diff -Nrup kexec-tools-2.0.0.orig/makedumpfile-1.3.5/makedumpfile.c kexec-tools-2.0.0/makedumpfile-1.3.5/makedumpfile.c --- kexec-tools-2.0.0.orig/makedumpfile-1.3.5/makedumpfile.c 2012-01-02 16:59:06.000000000 +0800 +++ kexec-tools-2.0.0/makedumpfile-1.3.5/makedumpfile.c 2012-01-02 16:59:20.000000000 +0800 @@ -30,6 +30,7 @@ struct module_sym_table mod_st = { 0 }; char filename_stdout[] = FILENAME_STDOUT; int message_level; int flag_ignore_r_char; /* 0: '\r' is effective. 1: not effective. */ +long pointer_size; /* * Forward declarations @@ -1795,6 +1796,41 @@ check_array_type(Dwarf *dwarfd, Dwarf_Di 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. */ @@ -1875,6 +1911,15 @@ search_member(Dwarf *dwarfd, Dwarf_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; @@ -1937,6 +1982,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)) @@ -1958,6 +2004,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 @@ -2014,6 +2061,7 @@ search_structure(Dwarf *dwarfd, Dwarf_Di 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: @@ -2146,6 +2194,9 @@ search_symbol(Dwarf *dwarfd, Dwarf_Die * 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; } } @@ -2222,6 +2273,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"); @@ -2260,6 +2315,47 @@ get_structure_size(char *structname, int } /* + * 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 @@ -2278,6 +2374,35 @@ get_member_offset(char *structname, char } /* + * 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 @@ -2375,6 +2500,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; } @@ -7463,13 +7590,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 -Nrup kexec-tools-2.0.0.orig/makedumpfile-1.3.5/makedumpfile.h kexec-tools-2.0.0/makedumpfile-1.3.5/makedumpfile.h --- kexec-tools-2.0.0.orig/makedumpfile-1.3.5/makedumpfile.h 2012-01-02 16:59:06.000000000 +0800 +++ kexec-tools-2.0.0/makedumpfile-1.3.5/makedumpfile.h 2012-01-02 16:59:12.000000000 +0800 @@ -1210,7 +1210,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 { @@ -1225,13 +1228,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);