[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