Hi Mahesh, On my machine (RHEL5 x86_64), I cannot compile makedumpfile with this patch. I guess that it is due to old elfutils of my machine, and I am trying this problem by newer elfutils. I'd like to get some hints, so can you tell me your environment ? RHEL6 x86_64 ? Thanks Ken'ichi Ohmichi On Wed, 18 May 2011 01:31:01 +0530 Mahesh J Salgaonkar <mahesh at linux.vnet.ibm.com> wrote: > > From: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com> > > So far makedumpfile implementation does not have to deal with module > debuginfo files. In order to support filtering of kernel module data, > it needs to read dwarf information from module debuginfo files. The linux > kernel module debuginfo are of ET_REL type and requires relocation to be > applied in order to get the dwarf information. > > This patch uses dwfl_* API's to make the code relocation-aware while > loading module debuginfo files. It also uses dwfl_* API to search module > debuginfo files installed under default debuginfo path. > > Signed-off-by: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com> > Signed-off-by: Prerna Saxena <prerna at linux.vnet.ibm.com> > --- > > makedumpfile.c | 261 +++++++++++++++++++++++++++++++++++++++++++++----------- > makedumpfile.h | 7 ++ > 2 files changed, 216 insertions(+), 52 deletions(-) > > diff --git a/makedumpfile.c b/makedumpfile.c > index f136eba..2274b18 100644 > --- a/makedumpfile.c > +++ b/makedumpfile.c > @@ -1372,6 +1372,146 @@ get_elf_info(void) > return TRUE; > } > > +static int > +process_module (Dwfl_Module *dwflmod, > + void **userdata __attribute__ ((unused)), > + const char *name __attribute__ ((unused)), > + Dwarf_Addr base __attribute__ ((unused)), > + void *arg) > +{ > + const char *fname, *mod_name, *debugfile; > + Dwarf_Addr dwbias; > + > + /* get a debug context descriptor.*/ > + dwarf_info.dwarfd = dwfl_module_getdwarf (dwflmod, &dwbias); > + dwarf_info.elfd = dwarf_getelf(dwarf_info.dwarfd); > + > + mod_name = dwfl_module_info(dwflmod, NULL, NULL, NULL, NULL, NULL, > + &fname, &debugfile); > + > + if (!strcmp(dwarf_info.module_name, mod_name) && > + !dwarf_info.name_debuginfo && debugfile) { > + /* > + * Store the debuginfo filename. Next time we will > + * open debuginfo file direclty instead of searching > + * for it again. > + */ > + dwarf_info.name_debuginfo = strdup(debugfile); > + } > + > + return DWARF_CB_OK; > +} > + > +static int > +dwfl_report_module_p(const char *modname, const char *filename) > +{ > + if (filename && !strcmp(modname, dwarf_info.module_name)) > + return 1; > + return 0; > +} > + > +static void > +clean_dwfl_info(void) > +{ > + if (dwarf_info.dwfl) > + dwfl_end(dwarf_info.dwfl); > + > + dwarf_info.dwfl = NULL; > + dwarf_info.dwarfd = NULL; > + dwarf_info.elfd = NULL; > +} > + > +/* > + * Intitialize the dwarf info. > + * Linux kernel module debuginfo are of ET_REL (relocatable) type. The old > + * implementation of get_debug_info() function that reads the debuginfo was > + * not relocation-aware and hence could not read the dwarf info properly > + * from module debuginfo. > + * > + * This function uses dwfl API's to apply relocation before reading the > + * dwarf information from module debuginfo. > + * On success, this function sets the dwarf_info.elfd and dwarf_info.dwarfd > + * after applying relocation to module debuginfo. > + */ > +static int > +init_dwarf_info(void) > +{ > + Dwfl *dwfl = NULL; > + int dwfl_fd = -1; > + static char *debuginfo_path = DEFAULT_DEBUGINFO_PATH; > + static const Dwfl_Callbacks callbacks = { > + .section_address = dwfl_offline_section_address, > + .find_debuginfo = dwfl_standard_find_debuginfo, > + .debuginfo_path = &debuginfo_path, > + }; > + > + dwarf_info.elfd = NULL; > + dwarf_info.dwarfd = NULL; > + > + if ((dwfl = dwfl_begin(&callbacks)) == NULL) { > + ERRMSG("Can't create a handle for a new dwfl session.\n"); > + return FALSE; > + } > + > + if (dwarf_info.name_debuginfo) { > + /* We have absolute path for debuginfo file, use it directly > + * instead of searching it through > + * dwfl_linux_kernel_report_offline() call. > + * > + * Open the debuginfo file if it is not already open. > + */ > + if (dwarf_info.fd_debuginfo < 0) > + dwarf_info.fd_debuginfo = > + open(dwarf_info.name_debuginfo, O_RDONLY); > + > + dwfl_fd = dup(dwarf_info.fd_debuginfo); > + if (dwfl_fd < 0) { > + ERRMSG("Failed to get a duplicate handle for" > + " debuginfo.\n"); > + goto err_out; > + } > + } > + if (dwarf_info.fd_debuginfo > 0) { > + if (dwfl_report_offline(dwfl, dwarf_info.module_name, > + dwarf_info.name_debuginfo, dwfl_fd) == NULL) { > + ERRMSG("Failed reading %s: %s\n", > + dwarf_info.name_debuginfo, dwfl_errmsg (-1)); > + /* dwfl_fd is consumed on success, not on failure */ > + close(dwfl_fd); > + goto err_out; > + } > + } > + else if (dwfl_linux_kernel_report_offline(dwfl, > + info->system_utsname.release, > + &dwfl_report_module_p)) { > + ERRMSG("Can't get Module debuginfo for module '%s'\n", > + dwarf_info.module_name); > + goto err_out; > + } > + dwfl_report_end(dwfl, NULL, NULL); > + > + dwfl_getmodules(dwfl, &process_module, NULL, 0); > + > + if (dwarf_info.elfd == NULL) { > + ERRMSG("Can't get first elf header of %s.\n", > + dwarf_info.name_debuginfo); > + goto err_out; > + } > + > + if (dwarf_info.dwarfd == NULL) { > + ERRMSG("Can't get debug context descriptor for %s.\n", > + dwarf_info.name_debuginfo); > + goto err_out; > + } > + dwarf_info.dwfl = dwfl; > + return TRUE; > +err_out: > + if (dwfl) > + dwfl_end(dwfl); > + > + return FALSE; > +} > + > unsigned long long > get_symbol_addr(char *symname) > { > @@ -1383,18 +1523,12 @@ get_symbol_addr(char *symname) > Elf_Data *data = NULL; > Elf_Scn *scn = NULL; > char *sym_name = NULL; > - const off_t failed = (off_t)-1; > > - if (lseek(dwarf_info.fd_debuginfo, 0, SEEK_SET) == failed) { > - ERRMSG("Can't seek the kernel file(%s). %s\n", > - dwarf_info.name_debuginfo, strerror(errno)); > - return NOT_FOUND_SYMBOL; > - } > - if (!(elfd = elf_begin(dwarf_info.fd_debuginfo, ELF_C_READ, NULL))) { > - ERRMSG("Can't get first elf header of %s.\n", > - dwarf_info.name_debuginfo); > - return NOT_FOUND_SYMBOL; > - } > + if (!init_dwarf_info()) > + return 0; > + > + elfd = dwarf_info.elfd; > + > while ((scn = elf_nextscn(elfd, scn)) != NULL) { > if (gelf_getshdr(scn, &shdr) == NULL) { > ERRMSG("Can't get section header.\n"); > @@ -1431,8 +1565,7 @@ get_symbol_addr(char *symname) > } > } > out: > - if (elfd != NULL) > - elf_end(elfd); > + clean_dwfl_info(); > > return symbol; > } > @@ -1449,18 +1582,12 @@ get_next_symbol_addr(char *symname) > Elf_Data *data = NULL; > Elf_Scn *scn = NULL; > char *sym_name = NULL; > - const off_t failed = (off_t)-1; > > - if (lseek(dwarf_info.fd_debuginfo, 0, SEEK_SET) == failed) { > - ERRMSG("Can't seek the kernel file(%s). %s\n", > - dwarf_info.name_debuginfo, strerror(errno)); > - return NOT_FOUND_SYMBOL; > - } > - if (!(elfd = elf_begin(dwarf_info.fd_debuginfo, ELF_C_READ, NULL))) { > - ERRMSG("Can't get first elf header of %s.\n", > - dwarf_info.name_debuginfo); > - return NOT_FOUND_SYMBOL; > - } > + if (!init_dwarf_info()) > + return 0; > + > + elfd = dwarf_info.elfd; > + > while ((scn = elf_nextscn(elfd, scn)) != NULL) { > if (gelf_getshdr(scn, &shdr) == NULL) { > ERRMSG("Can't get section header.\n"); > @@ -1522,8 +1649,7 @@ get_next_symbol_addr(char *symname) > } > } > out: > - if (elfd != NULL) > - elf_end(elfd); > + clean_dwfl_info(); > > return next_symbol; > } > @@ -2034,24 +2160,15 @@ get_debug_info(void) > Elf_Scn *scn = NULL; > GElf_Shdr scnhdr_mem, *scnhdr = NULL; > Dwarf_Die cu_die; > - const off_t failed = (off_t)-1; > > int ret = FALSE; > > - if (lseek(dwarf_info.fd_debuginfo, 0, SEEK_SET) == failed) { > - ERRMSG("Can't seek the kernel file(%s). %s\n", > - dwarf_info.name_debuginfo, strerror(errno)); > - return FALSE; > - } > - if (!(elfd = elf_begin(dwarf_info.fd_debuginfo, ELF_C_READ_MMAP, NULL))) { > - ERRMSG("Can't get first elf header of %s.\n", > - dwarf_info.name_debuginfo); > + if (!init_dwarf_info()) > return FALSE; > - } > - if (!(dwarfd = dwarf_begin_elf(elfd, DWARF_C_READ, NULL))) { > - ERRMSG("Can't create a handle for a new debug session.\n"); > - goto out; > - } > + > + elfd = dwarf_info.elfd; > + dwarfd = dwarf_info.dwarfd; > + > if (elf_getshstrndx(elfd, &shstrndx) < 0) { > ERRMSG("Can't get the section index of the string table.\n"); > goto out; > @@ -2088,10 +2205,7 @@ get_debug_info(void) > } > ret = TRUE; > out: > - if (dwarfd != NULL) > - dwarf_end(dwarfd); > - if (elfd != NULL) > - elf_end(elfd); > + clean_dwfl_info(); > > return ret; > } > @@ -2448,14 +2562,58 @@ get_mem_type(void) > return ret; > } > > +/* > + * Set the dwarf_info with kernel/module debuginfo file information. > + */ > +int > +set_dwarf_debuginfo(char *mod_name, char *name_debuginfo, int fd_debuginfo) > +{ > + if (!mod_name) > + return FALSE; > + if (dwarf_info.module_name && !strcmp(dwarf_info.module_name, mod_name)) > + return TRUE; > + > + /* Switching to different module. > + * > + * Close the file descriptor if previous module is != kernel and > + * xen-syms. The reason is, vmlinux file will always be supplied > + * by user and code to open/close kernel debuginfo file already > + * in place. The module debuginfo files are opened only if '--config' > + * option is used. This helps not to break the existing functionlity > + * if called without '--config' option. > + */ > + > + if (dwarf_info.module_name > + && strcmp(dwarf_info.module_name, "vmlinux") > + && strcmp(dwarf_info.module_name, "xen-syms")) { > + if (dwarf_info.fd_debuginfo > 0) > + close(dwarf_info.fd_debuginfo); > + if (dwarf_info.name_debuginfo) > + free(dwarf_info.name_debuginfo); > + } > + dwarf_info.fd_debuginfo = fd_debuginfo; > + dwarf_info.name_debuginfo = name_debuginfo; > + dwarf_info.module_name = mod_name; > + > + if (!strcmp(dwarf_info.module_name, "vmlinux") || > + !strcmp(dwarf_info.module_name, "xen-syms")) > + return TRUE; > + > + /* check to see whether module debuginfo is available */ > + if (!init_dwarf_info()) > + return FALSE; > + else > + clean_dwfl_info(); > + return TRUE; > +} > + > int > generate_vmcoreinfo(void) > { > if (!set_page_size(sysconf(_SC_PAGE_SIZE))) > return FALSE; > > - dwarf_info.fd_debuginfo = info->fd_vmlinux; > - dwarf_info.name_debuginfo = info->name_vmlinux; > + set_dwarf_debuginfo("vmlinux", info->name_vmlinux, info->fd_vmlinux); > > if (!get_symbol_info()) > return FALSE; > @@ -3888,8 +4046,8 @@ initial(void) > * Get the debug information for analysis from the kernel file > */ > } else if (info->name_vmlinux) { > - dwarf_info.fd_debuginfo = info->fd_vmlinux; > - dwarf_info.name_debuginfo = info->name_vmlinux; > + set_dwarf_debuginfo("vmlinux", info->name_vmlinux, > + info->fd_vmlinux); > > if (!get_symbol_info()) > return FALSE; > @@ -6552,8 +6710,7 @@ generate_vmcoreinfo_xen(void) > ERRMSG("Can't get the size of page.\n"); > return FALSE; > } > - dwarf_info.fd_debuginfo = info->fd_xen_syms; > - dwarf_info.name_debuginfo = info->name_xen_syms; > + set_dwarf_debuginfo("xen-syms", info->name_xen_syms, info->fd_xen_syms); > > if (!get_symbol_info_xen()) > return FALSE; > @@ -6820,8 +6977,8 @@ initial_xen(void) > * Get the debug information for analysis from the xen-syms file > */ > } else if (info->name_xen_syms) { > - dwarf_info.fd_debuginfo = info->fd_xen_syms; > - dwarf_info.name_debuginfo = info->name_xen_syms; > + set_dwarf_debuginfo("xen-syms", info->name_xen_syms, > + info->fd_xen_syms); > > if (!get_symbol_info_xen()) > return FALSE; > diff --git a/makedumpfile.h b/makedumpfile.h > index e037f12..3fda754 100644 > --- a/makedumpfile.h > +++ b/makedumpfile.h > @@ -27,6 +27,7 @@ > #include <sys/wait.h> > #include <zlib.h> > #include <elfutils/libdw.h> > +#include <elfutils/libdwfl.h> > #include <libelf.h> > #include <dwarf.h> > #include <byteswap.h> > @@ -1177,6 +1178,8 @@ extern struct srcfile_table srcfile_table; > /* > * Debugging information > */ > +#define DEFAULT_DEBUGINFO_PATH "/usr/lib/debug" > + > enum { > DWARF_INFO_GET_STRUCT_SIZE, > DWARF_INFO_GET_MEMBER_OFFSET, > @@ -1194,10 +1197,14 @@ struct dwarf_info { > unsigned int cmd; /* IN */ > int fd_debuginfo; /* IN */ > char *name_debuginfo; /* IN */ > + char *module_name; /* IN */ > char *struct_name; /* IN */ > char *symbol_name; /* IN */ > char *member_name; /* IN */ > char *enum_name; /* IN */ > + Elf *elfd; /* OUT */ > + Dwarf *dwarfd; /* OUT */ > + Dwfl *dwfl; /* OUT */ > long struct_size; /* OUT */ > long member_offset; /* OUT */ > long array_length; /* OUT */ >