[PATCH v2 3/8] makedumpfile: Load the module symbol data from vmcore.

Mahesh Jagannath Salgaonkar mahesh at linux.vnet.ibm.com
Wed Aug 3 06:35:38 EDT 2011


Hi Ken'ichi,

Sorry for late reply.

On 07/29/2011 03:12 PM, Ken'ichi Ohmichi wrote:
> 
> Hi Mahesh,
> 
> This patch is almost good, and there are some cleanup points and
> error-handling points.
> 
> On Wed, 18 May 2011 01:31:53 +0530
> Mahesh J Salgaonkar <mahesh at linux.vnet.ibm.com> wrote:
>>
>> This patch enables makedumpfile to load module symbol data from vmcore. This
>> info is required during kernel module data filtering process. Traverse the
>> modules list and load all module's symbol info data in the memory for fast
>> lookup.
> 
> [..]
> 
>> +static int
>> +load_module_symbols(void)
>> +{
>> +	unsigned long head, cur, cur_module;
>> +	unsigned long symtab, strtab;
>> +	unsigned long mod_base, mod_init;
>> +	unsigned int mod_size, mod_init_size;
>> +	unsigned char *module_struct_mem, *module_core_mem;
>> +	unsigned char *module_init_mem = NULL;
>> +	unsigned char *symtab_mem;
>> +	char *module_name, *strtab_mem, *nameptr;
>> +	struct module_info *modules = NULL;
>> +	struct symbol_info *sym_info;
>> +	unsigned int num_symtab;
>> +	unsigned int i = 0, nsym;
>> +
>> +	head = SYMBOL(modules);
>> +	if (!get_num_modules(head, &mod_st.num_modules)) {
>> +		ERRMSG("Can't get module count\n");
>> +		return FALSE;
>> +	}
>> +	if (!mod_st.num_modules) {
>> +		return FALSE;
> 
> If the above num_modules is 0, makedumpfile fails without any hint
> message. How about the below change ?

Agree.

> 
> @@ -7651,13 +7651,11 @@ load_module_symbols(void)
>         unsigned int i = 0, nsym;
> 
>         head = SYMBOL(modules);
> -       if (!get_num_modules(head, &mod_st.num_modules)) {
> +       if (!get_num_modules(head, &mod_st.num_modules) ||
> +           !mod_st.num_modules) {
>                 ERRMSG("Can't get module count\n");
>                 return FALSE;
>         }
> -       if (!mod_st.num_modules) {
> -               return FALSE;
> -       }
>         mod_st.modules = calloc(mod_st.num_modules,
>                                         sizeof(struct module_info));
>         if (!mod_st.modules) {
> ---
> 
> [..]
> 
>> +	/* Travese the list and read module symbols */
>> +	while (cur != head) {
> 
> [..]
> 
>> +		if (mod_init_size > 0) {
>> +			module_init_mem = calloc(1, mod_init_size);
>> +			if (module_init_mem == NULL) {
>> +				ERRMSG("Can't allocate memory for module "
>> +								"init\n");
>> +				return FALSE;
>> +			}
>> +			if (!readmem(VADDR, mod_init, module_init_mem,
>> +							mod_init_size)) {
>> +				ERRMSG("Can't access module init in memory.\n");
>> +				return FALSE;
> 
> In the above error case, module_init_mem should be freed.
> There are the same lacks of free, and I feel it is due to
> a large load_module_symbols() function.
> Hence I created the attached patch for making the function
> small and fixing the lacks of free.
> Can you review it ?

The attached patch looks good to me. Thanks for splitting the function.

Thanks,
-Mahesh.
> 
> 
>> +		if (mod_init_size > 0)
>> +			free(module_init_mem);
>> +	} while (cur != head);
> 
> This is the same as the begining of this loop, and it is not necessary.
> 
> 
> Thanks
> Ken'ichi Ohmichi
> 
> ---
> diff --git a/makedumpfile.c b/makedumpfile.c
> index 3ad2bd5..92ca23b 100644
> --- a/makedumpfile.c
> +++ b/makedumpfile.c
> @@ -7635,20 +7635,160 @@ clean_module_symbols(void)
>  }
> 
>  static int
> -load_module_symbols(void)
> +__load_module_symbol(struct module_info *modules, unsigned long addr_module)
>  {
> -	unsigned long head, cur, cur_module;
> +	int ret = FALSE;
> +	unsigned int nsym;
>  	unsigned long symtab, strtab;
>  	unsigned long mod_base, mod_init;
>  	unsigned int mod_size, mod_init_size;
> -	unsigned char *module_struct_mem, *module_core_mem;
> +	unsigned char *module_struct_mem = NULL;
> +	unsigned char *module_core_mem = NULL;
>  	unsigned char *module_init_mem = NULL;
>  	unsigned char *symtab_mem;
>  	char *module_name, *strtab_mem, *nameptr;
> -	struct module_info *modules = NULL;
> -	struct symbol_info *sym_info;
>  	unsigned int num_symtab;
> -	unsigned int i = 0, nsym;
> +
> +	/* Allocate buffer to read struct module data from vmcore. */
> +	if ((module_struct_mem = calloc(1, SIZE(module))) == NULL) {
> +		ERRMSG("Failed to allocate buffer for module\n");
> +		return FALSE;
> +	}
> +	if (!readmem(VADDR, addr_module, module_struct_mem,
> +						SIZE(module))) {
> +		ERRMSG("Can't get module info.\n");
> +		goto out;
> +	}
> +
> +	module_name = (char *)(module_struct_mem + OFFSET(module.name));
> +	if (strlen(module_name) < MOD_NAME_LEN)
> +		strcpy(modules->name, module_name);
> +	else
> +		strncpy(modules->name, module_name, MOD_NAME_LEN-1);
> +
> +	mod_init = ULONG(module_struct_mem +
> +					OFFSET(module.module_init));
> +	mod_init_size = UINT(module_struct_mem +
> +					OFFSET(module.init_size));
> +	mod_base = ULONG(module_struct_mem +
> +					OFFSET(module.module_core));
> +	mod_size = UINT(module_struct_mem +
> +					OFFSET(module.core_size));
> +
> +	DEBUG_MSG("Module: %s, Base: 0x%lx, Size: %u\n",
> +			module_name, mod_base, mod_size);
> +	if (mod_init_size > 0) {
> +		module_init_mem = calloc(1, mod_init_size);
> +		if (module_init_mem == NULL) {
> +			ERRMSG("Can't allocate memory for module "
> +							"init\n");
> +			goto out;
> +		}
> +		if (!readmem(VADDR, mod_init, module_init_mem,
> +						mod_init_size)) {
> +			ERRMSG("Can't access module init in memory.\n");
> +			goto out;
> +		}
> +	}
> +
> +	if ((module_core_mem = calloc(1, mod_size)) == NULL) {
> +		ERRMSG("Can't allocate memory for module\n");
> +		goto out;
> +	}
> +	if (!readmem(VADDR, mod_base, module_core_mem, mod_size)) {
> +		ERRMSG("Can't access module in memory.\n");
> +		goto out;
> +	}
> +
> +	num_symtab = UINT(module_struct_mem +
> +					OFFSET(module.num_symtab));
> +	if (!num_symtab) {
> +		ERRMSG("%s: Symbol info not available\n", module_name);
> +		goto out;
> +	}
> +	modules->num_syms = num_symtab;
> +	DEBUG_MSG("num_sym: %d\n", num_symtab);
> +
> +	symtab = ULONG(module_struct_mem + OFFSET(module.symtab));
> +	strtab = ULONG(module_struct_mem + OFFSET(module.strtab));
> +
> +	/* check if symtab and strtab are inside the module space. */
> +	if (!IN_RANGE(symtab, mod_base, mod_size) &&
> +		!IN_RANGE(symtab, mod_init, mod_init_size)) {
> +		ERRMSG("%s: module symtab is outseide of module "
> +			"address space\n", module_name);
> +		goto out;
> +	}
> +	if (IN_RANGE(symtab, mod_base, mod_size))
> +		symtab_mem = module_core_mem + (symtab - mod_base);
> +	else
> +		symtab_mem = module_init_mem + (symtab - mod_init);
> +
> +	if (!IN_RANGE(strtab, mod_base, mod_size) &&
> +		!IN_RANGE(strtab, mod_init, mod_init_size)) {
> +		ERRMSG("%s: module strtab is outseide of module "
> +			"address space\n", module_name);
> +		goto out;
> +	}
> +	if (IN_RANGE(strtab, mod_base, mod_size))
> +		strtab_mem = (char *)(module_core_mem
> +					+ (strtab - mod_base));
> +	else
> +		strtab_mem = (char *)(module_init_mem
> +					+ (strtab - mod_init));
> +
> +	modules->sym_info = calloc(num_symtab, sizeof(struct symbol_info));
> +	if (modules->sym_info == NULL) {
> +		ERRMSG("Can't allocate memory to store sym info\n");
> +		goto out;
> +	}
> +
> +	/* symbols starts from 1 */
> +	for (nsym = 1; nsym < num_symtab; nsym++) {
> +		Elf32_Sym *sym32;
> +		Elf64_Sym *sym64;
> +		/* 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 ((pointer_size * 8) == 64) {
> +			sym64 = (Elf64_Sym *) (symtab_mem
> +					+ (nsym * sizeof(Elf64_Sym)));
> +			modules->sym_info[nsym].value =
> +				(unsigned long long) sym64->st_value;
> +			nameptr = strtab_mem + sym64->st_name;
> +		} else {
> +			sym32 = (Elf32_Sym *) (symtab_mem
> +					+ (nsym * sizeof(Elf32_Sym)));
> +			modules->sym_info[nsym].value =
> +				(unsigned long long) sym32->st_value;
> +			nameptr = strtab_mem + sym32->st_name;
> +		}
> +		if (strlen(nameptr))
> +			modules->sym_info[nsym].name = strdup(nameptr);
> +		DEBUG_MSG("\t[%d] %llx %s\n", nsym,
> +					modules->sym_info[nsym].value, nameptr);
> +	}
> +	ret = TRUE;
> +out:
> +	free(module_struct_mem);
> +	free(module_core_mem);
> +	free(module_init_mem);
> +
> +	return ret;
> +}
> +
> +static int
> +load_module_symbols(void)
> +{
> +	unsigned long head, cur, cur_module;
> +	struct module_info *modules = NULL;
> +	unsigned int i = 0;
> 
>  	head = SYMBOL(modules);
>  	if (!get_num_modules(head, &mod_st.num_modules) ||
> @@ -7664,12 +7804,6 @@ load_module_symbols(void)
>  	}
>  	modules = mod_st.modules;
> 
> -	/* Allocate buffer to read struct module data from vmcore. */
> -	if ((module_struct_mem = calloc(1, SIZE(module))) == NULL) {
> -		ERRMSG("Failed to allocate buffer for module\n");
> -		return FALSE;
> -	}
> -
>  	if (!readmem(VADDR, head + OFFSET(list_head.next), &cur, sizeof cur)) {
>  		ERRMSG("Can't get next list_head.\n");
>  		return FALSE;
> @@ -7678,129 +7812,9 @@ load_module_symbols(void)
>  	/* Travese the list and read module symbols */
>  	while (cur != head) {
>  		cur_module = cur - OFFSET(module.list);
> -		if (!readmem(VADDR, cur_module, module_struct_mem,
> -							SIZE(module))) {
> -			ERRMSG("Can't get module info.\n");
> -			return FALSE;
> -		}
> -
> -		module_name = (char *)(module_struct_mem + OFFSET(module.name));
> -		if (strlen(module_name) < MOD_NAME_LEN)
> -			strcpy(modules[i].name, module_name);
> -		else
> -			strncpy(modules[i].name, module_name, MOD_NAME_LEN-1);
> -
> -		mod_init = ULONG(module_struct_mem +
> -						OFFSET(module.module_init));
> -		mod_init_size = UINT(module_struct_mem +
> -						OFFSET(module.init_size));
> -		mod_base = ULONG(module_struct_mem +
> -						OFFSET(module.module_core));
> -		mod_size = UINT(module_struct_mem +
> -						OFFSET(module.core_size));
> -
> -		DEBUG_MSG("Module: %s, Base: 0x%lx, Size: %u\n",
> -				module_name, mod_base, mod_size);
> -		if (mod_init_size > 0) {
> -			module_init_mem = calloc(1, mod_init_size);
> -			if (module_init_mem == NULL) {
> -				ERRMSG("Can't allocate memory for module "
> -								"init\n");
> -				return FALSE;
> -			}
> -			if (!readmem(VADDR, mod_init, module_init_mem,
> -							mod_init_size)) {
> -				ERRMSG("Can't access module init in memory.\n");
> -				return FALSE;
> -			}
> -		}
> 
> -		if ((module_core_mem = calloc(1, mod_size)) == NULL) {
> -			ERRMSG("Can't allocate memory for module\n");
> +		if (!__load_module_symbol(&modules[i], cur_module))
>  			return FALSE;
> -		}
> -		if (!readmem(VADDR, mod_base, module_core_mem, mod_size)) {
> -			ERRMSG("Can't access module in memory.\n");
> -			return FALSE;
> -		}
> -
> -		num_symtab = UINT(module_struct_mem +
> -						OFFSET(module.num_symtab));
> -		if (!num_symtab) {
> -			ERRMSG("%s: Symbol info not available\n", module_name);
> -			return FALSE;
> -		}
> -		modules[i].num_syms = num_symtab;
> -		DEBUG_MSG("num_sym: %d\n", num_symtab);
> -
> -		symtab = ULONG(module_struct_mem + OFFSET(module.symtab));
> -		strtab = ULONG(module_struct_mem + OFFSET(module.strtab));
> -
> -		/* check if symtab and strtab are inside the module space. */
> -		if (!IN_RANGE(symtab, mod_base, mod_size) &&
> -			!IN_RANGE(symtab, mod_init, mod_init_size)) {
> -			ERRMSG("%s: module symtab is outseide of module "
> -				"address space\n", module_name);
> -			return FALSE;
> -		}
> -		if (IN_RANGE(symtab, mod_base, mod_size))
> -			symtab_mem = module_core_mem + (symtab - mod_base);
> -		else
> -			symtab_mem = module_init_mem + (symtab - mod_init);
> -
> -		if (!IN_RANGE(strtab, mod_base, mod_size) &&
> -			!IN_RANGE(strtab, mod_init, mod_init_size)) {
> -			ERRMSG("%s: module strtab is outseide of module "
> -				"address space\n", module_name);
> -			return FALSE;
> -		}
> -		if (IN_RANGE(strtab, mod_base, mod_size))
> -			strtab_mem = (char *)(module_core_mem
> -						+ (strtab - mod_base));
> -		else
> -			strtab_mem = (char *)(module_init_mem
> -						+ (strtab - mod_init));
> -
> -		modules[i].sym_info = calloc(num_symtab,
> -						sizeof(struct symbol_info));
> -		if (modules[i].sym_info == NULL) {
> -			ERRMSG("Can't allocate memory to store sym info\n");
> -			return FALSE;
> -		}
> -		sym_info = modules[i].sym_info;
> -
> -		/* symbols starts from 1 */
> -		for (nsym = 1; nsym < num_symtab; nsym++) {
> -			Elf32_Sym *sym32;
> -			Elf64_Sym *sym64;
> -			/* 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 ((pointer_size * 8) == 64) {
> -				sym64 = (Elf64_Sym *) (symtab_mem
> -						+ (nsym * sizeof(Elf64_Sym)));
> -				sym_info[nsym].value =
> -					(unsigned long long) sym64->st_value;
> -				nameptr = strtab_mem + sym64->st_name;
> -			}
> -			else {
> -				sym32 = (Elf32_Sym *) (symtab_mem
> -						+ (nsym * sizeof(Elf32_Sym)));
> -				sym_info[nsym].value =
> -					(unsigned long long) sym32->st_value;
> -				nameptr = strtab_mem + sym32->st_name;
> -			}
> -			if (strlen(nameptr))
> -				sym_info[nsym].name = strdup(nameptr);
> -			DEBUG_MSG("\t[%d] %llx %s\n", nsym,
> -						sym_info[nsym].value, nameptr);
> -		}
> 
>  		if (!readmem(VADDR, cur + OFFSET(list_head.next),
>  					&cur, sizeof cur)) {
> @@ -7808,11 +7822,7 @@ load_module_symbols(void)
>  			return FALSE;
>  		}
>  		i++;
> -		free(module_core_mem);
> -		if (mod_init_size > 0)
> -			free(module_init_mem);
>  	} while (cur != head);
> -	free(module_struct_mem);
>  	return TRUE;
>  }
> 
> 
> 
> _______________________________________________
> kexec mailing list
> kexec at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec




More information about the kexec mailing list