[PATCH v2 2/8] makedumpfile: Apply relocation while loading module debuginfo.
Ken'ichi Ohmichi
oomichi at mxs.nes.nec.co.jp
Fri Jul 15 05:35:41 EDT 2011
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 */
>
More information about the kexec
mailing list