[PATCH v2 2/8] makedumpfile: Apply relocation while loading module debuginfo.
Mahesh Jagannath Salgaonkar
mahesh at linux.vnet.ibm.com
Fri Jul 15 06:21:38 EDT 2011
Hi Ken'ichi,
On 07/15/2011 03:05 PM, Ken'ichi Ohmichi wrote:
>
> 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 ?
Yes, I had tested these patches on RHEL6.0 and RHEl6.1 x86_64. As far as
I know RHEL6.0 had elfutils-0.148.
I did not try my patches on RHEL5 x86-64. Let me see if I can get a
RHEL5 x86_64 box to verify.
But in case we can not fix the compilation with RHEL5 environment, do
you think we can go with one of following options:
1. When compiled with older elfutils library, build makedumpfile without
this feature enabled.
2. Make newer elfutils vesion as pre-requisite for future makedumpfile
releases.
What do you think?
Thanks,
-Mahesh.
>
>
> 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