[PATCH v2 6/8] makedumpfile: Read and process 'for' command from config file.

Ken'ichi Ohmichi oomichi at mxs.nes.nec.co.jp
Thu Sep 1 04:06:58 EDT 2011


Hi Mahesh,

Thank you for the patch.
I have one question.

On Tue, 30 Aug 2011 23:46:42 +0530
Mahesh J Salgaonkar <mahesh at linux.vnet.ibm.com> wrote:
> 
> [PATCH] makedumpfile: Fix array traversal for array of structure and char type.
> 
> From: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>
> 
> Introduce new function get_next_list_entry() that returns config entry
> for each element in the LIST entry. This approach improves the handling
> of LIST entry. With this change the function get_config_symbol_addr()
> no longer required to handle LIST entry separately.
> 
> This patch fixes following BUGs:

[..]

> - The loop construct used for array of char* (pointer) silently fails and
> does not filter the strings.

Did the silent failure happen at the following code of list_entry_empty() ?

   7373         addr = get_config_symbol_addr(le, 0, NULL);
   7374         if (!addr)
   7375                 return TRUE;

If list_entry_empty() returns TRUE, a "while" loop of process_config() breaks
and update_filter_info() is not called.
Is that the problem you said ?

If yes, I feel the behavior related with this problem has not changed.
because the method for getting a pointer array has not changed like the
following:

o OLD
    111 -                               while (ce->index < ce->array_length) {
    112 -                                       addr = read_pointer_value(ce->addr +
    113 -                                               (ce->index * get_pointer_size()));
    114 -                                       ce->index++;
    115 -                                       if (addr)
    116 -                                               break;
    117 -                               }
    118 -                               return addr;

o NEW
    197 +                               while (ce->index < ce->array_length) {
    198 +                                       addr = read_pointer_value(ce->addr +
    199 +                                               (ce->index * get_pointer_size()));
    200 +                                       if (addr)
    201 +                                               break;
    202 +                                       ce->index++;
    203 +                               }
    204 +                               if (ce->index == ce->array_length)
    205 +                                       return FALSE;


I think the other bugfixes are right, thanks.


Thanks
Ken'ichi Ohmichi

> ---
>  dwarf_info.c   |    8 ++
>  makedumpfile.c |  292 +++++++++++++++++++++++++++++++++++---------------------
>  2 files changed, 188 insertions(+), 112 deletions(-)
> 
> diff --git a/dwarf_info.c b/dwarf_info.c
> index 744ecf7..46dcd8e 100644
> --- a/dwarf_info.c
> +++ b/dwarf_info.c
> @@ -328,6 +328,14 @@ get_data_array_length(Dwarf_Die *die)
>  		return FALSE;
>  	}
>  	tag = dwarf_tag(&die_type);
> +	if (tag == DW_TAG_const_type) {
> +		/* This array is of const type. Get the die type again */
> +		if (!get_die_type(&die_type, &die_type)) {
> +			ERRMSG("Can't get CU die of DW_AT_type.\n");
> +			return FALSE;
> +		}
> +		tag = dwarf_tag(&die_type);
> +	}
>  	if (tag != DW_TAG_array_type) {
>  		/*
>  		 * This kernel doesn't have the member of array.
> diff --git a/makedumpfile.c b/makedumpfile.c
> index 599950d..1a88171 100644
> --- a/makedumpfile.c
> +++ b/makedumpfile.c
> @@ -6763,11 +6763,27 @@ read_pointer_value(unsigned long long addr)
>  	return val;
>  }
>  
> +static long
> +get_strlen(unsigned long long addr)
> +{
> +	char buf[BUFSIZE + 1];
> +	long len = 0;
> +
> +	/*
> +	 * Determine the string length for 'char' pointer.
> +	 * BUFSIZE(1024) is the upper limit for string length.
> +	 */
> +	if (readmem(VADDR, addr, buf, BUFSIZE)) {
> +		buf[BUFSIZE] = '\0';
> +		len = strlen(buf);
> +	}
> +	return len;
> +}
> +
>  int
>  resolve_config_entry(struct config_entry *ce, unsigned long long base_addr,
>  						char *base_struct_name)
>  {
> -	char buf[BUFSIZE + 1];
>  	unsigned long long symbol;
>  
>  	if (ce->flag & SYMBOL_ENTRY) {
> @@ -6866,7 +6882,7 @@ resolve_config_entry(struct config_entry *ce, unsigned long long base_addr,
>  		 * If this is a struct or list_head data type then
>  		 * create a leaf node entry with 'next' member.
>  		 */
> -		if ((ce->type_flag & TYPE_BASE)
> +		if (((ce->type_flag & (TYPE_BASE | TYPE_ARRAY)) == TYPE_BASE)
>  					&& (strcmp(ce->type_name, "void")))
>  			return FALSE;
>  
> @@ -6905,17 +6921,14 @@ resolve_config_entry(struct config_entry *ce, unsigned long long base_addr,
>  			ce->size = 0;
>  
>  	}
> -	if ((ce->type_flag & TYPE_BASE) && (ce->type_flag & TYPE_PTR)) {
> +	if ((ce->type_flag & TYPE_BASE) && (ce->type_flag & TYPE_PTR)
> +					&& !(ce->type_flag & TYPE_ARRAY)) {
>  		/*
>  		 * Determine the string length for 'char' pointer.
>  		 * BUFSIZE(1024) is the upper limit for string length.
>  		 */
> -		if (!strcmp(ce->type_name, "char")) {
> -			if (readmem(VADDR, ce->addr, buf, BUFSIZE)) {
> -				buf[BUFSIZE] = '\0';
> -				ce->size = strlen(buf);
> -			}
> -		}
> +		if (!strcmp(ce->type_name, "char"))
> +			ce->size = get_strlen(ce->addr);
>  	}
>  	if (!ce->next && (ce->flag & SIZE_ENTRY)) {
>  		void *val;
> @@ -6968,80 +6981,11 @@ get_config_symbol_addr(struct config_entry *ce,
>  			unsigned long long base_addr,
>  			char *base_struct_name)
>  {
> -	unsigned long addr = 0;
> -
>  	if (!(ce->flag & ENTRY_RESOLVED)) {
>  		if (!resolve_config_entry(ce, base_addr, base_struct_name))
>  			return 0;
>  	}
>  
> -	if ((ce->flag & LIST_ENTRY)) {
> -		/* handle List entry differently */
> -		if (!ce->next) {
> -			/* leaf node. */
> -			if (ce->type_flag & TYPE_ARRAY) {
> -				if (ce->index == ce->array_length)
> -					return 0;
> -				if (!(ce->type_flag & TYPE_PTR))
> -					return (ce->addr +
> -							(ce->index * ce->size));
> -				/* Array of pointers.
> -				 *
> -				 * Array may contain NULL pointers at some
> -				 * indexes. Hence return the next non-null
> -				 * address value.
> -				 */
> -				while (ce->index < ce->array_length) {
> -					addr = read_pointer_value(ce->addr +
> -						(ce->index * get_pointer_size()));
> -					ce->index++;
> -					if (addr)
> -						break;
> -				}
> -				return addr;
> -			}
> -			else {
> -				if (ce->addr == ce->cmp_addr)
> -					return 0;
> -
> -				/* Set the leaf node as unresolved, so that
> -				 * it will be resolved every time when
> -				 * get_config_symbol_addr is called untill
> -				 * it hits the exit condiftion.
> -				 */
> -				ce->flag &= ~ENTRY_RESOLVED;
> -			}
> -		}
> -		else if ((ce->next->next == NULL) &&
> -					!(ce->next->type_flag & TYPE_ARRAY)) {
> -			/* the next node is leaf node. for non-array element
> -			 * Set the sym_addr and addr of this node with that of
> -			 * leaf node.
> -			 */
> -			addr = ce->addr;
> -			ce->addr = ce->next->addr;
> -
> -			if (!(ce->type_flag & TYPE_LIST_HEAD)) {
> -				if (addr == ce->next->cmp_addr)
> -					return 0;
> -
> -				if (!ce->next->cmp_addr) {
> -					/* safeguard against circular
> -					 * link-list
> -					 */
> -					ce->next->cmp_addr = addr;
> -				}
> -
> -				/* Force resolution of traversal node */
> -				if (ce->addr && !resolve_config_entry(ce->next,
> -						ce->addr, ce->type_name))
> -					return 0;
> -
> -				return addr;
> -			}
> -		}
> -	}
> -
>  	if (ce->next && ce->addr) {
>  		/* Populate nullify flag down the list */
>  		ce->next->nullify = ce->nullify;
> @@ -7083,6 +7027,116 @@ get_config_symbol_size(struct config_entry *ce,
>  	}
>  }
>  
> +int
> +get_next_list_entry(struct config_entry *ce, unsigned long long base_addr,
> +			char *base_struct_name, struct config_entry *out_ce)
> +{
> +	unsigned long addr = 0;
> +
> +	/* This function only deals with LIST_ENTRY config entry. */
> +	if (!(ce->flag & LIST_ENTRY))
> +		return FALSE;
> +
> +	if (!(ce->flag & ENTRY_RESOLVED)) {
> +		if (!resolve_config_entry(ce, base_addr, base_struct_name))
> +			return FALSE;
> +	}
> +
> +	if (!ce->next) {
> +		/* leaf node. */
> +		if (ce->type_flag & TYPE_ARRAY) {
> +			if (ce->index == ce->array_length)
> +				return FALSE;
> +
> +			if (ce->type_flag & TYPE_PTR) {
> +				/* Array of pointers.
> +				 *
> +				 * Array may contain NULL pointers at some
> +				 * indexes. Hence jump to the next non-null
> +				 * address value.
> +				 */
> +				while (ce->index < ce->array_length) {
> +					addr = read_pointer_value(ce->addr +
> +						(ce->index * get_pointer_size()));
> +					if (addr)
> +						break;
> +					ce->index++;
> +				}
> +				if (ce->index == ce->array_length)
> +					return FALSE;
> +				out_ce->sym_addr = ce->addr + (ce->index *
> +							get_pointer_size());
> +				out_ce->addr = addr;
> +				if (!strcmp(ce->type_name, "char"))
> +					out_ce->size = get_strlen(addr);
> +				else
> +					out_ce->size = ce->size;
> +			}
> +			else {
> +				out_ce->sym_addr = ce->addr +
> +							(ce->index * ce->size);
> +				out_ce->addr = out_ce->sym_addr;
> +				out_ce->size = ce->size;
> +			}
> +			ce->index++;
> +		}
> +		else {
> +			if (ce->addr == ce->cmp_addr)
> +				return FALSE;
> +
> +			out_ce->addr = ce->addr;
> +			/* Set the leaf node as unresolved, so that
> +			 * it will be resolved every time when
> +			 * get_next_list_entry is called untill
> +			 * it hits the exit condiftion.
> +			 */
> +			ce->flag &= ~ENTRY_RESOLVED;
> +		}
> +		return TRUE;
> +	}
> +	else if ((ce->next->next == NULL) &&
> +				!(ce->next->type_flag & TYPE_ARRAY)) {
> +		/* the next node is leaf node. for non-array element
> +		 * Set the sym_addr and addr of this node with that of
> +		 * leaf node.
> +		 */
> +		if (!(ce->type_flag & TYPE_LIST_HEAD)) {
> +			if (!ce->addr || ce->addr == ce->next->cmp_addr)
> +				return FALSE;
> +
> +			if (!ce->next->cmp_addr) {
> +				/* safeguard against circular
> +				 * link-list
> +				 */
> +				ce->next->cmp_addr = ce->addr;
> +			}
> +
> +			out_ce->addr = ce->addr;
> +			out_ce->sym_addr = ce->sym_addr;
> +			out_ce->size = ce->size;
> +
> +			ce->sym_addr = ce->next->sym_addr;
> +			ce->addr = ce->next->addr;
> +
> +			/* Force resolution of traversal node */
> +			if (ce->addr && !resolve_config_entry(ce->next,
> +					ce->addr, ce->type_name))
> +				return FALSE;
> +
> +			return TRUE;
> +		}
> +		else {
> +			ce->sym_addr = ce->next->sym_addr;
> +			ce->addr = ce->next->addr;
> +		}
> +	}
> +
> +	if (ce->next && ce->addr)
> +		return get_next_list_entry(ce->next, ce->addr,
> +						ce->type_name, out_ce);
> +	return FALSE;
> +}
> +
>  static int
>  resolve_list_entry(struct config_entry *ce, unsigned long long base_addr,
>  			char *base_struct_name, char **out_type_name,
> @@ -7308,31 +7362,14 @@ initialize_iteration_entry(struct config_entry *ie,
>  								ie->line);
>  			ie->next->flag &= ~SYMBOL_ENTRY;
>  		}
> -	}
> -	else {
> -		if (ie->type_name) {
> -			/* looks like user has used 'within' keyword for
> -			 * non-list_head VAR. Print the warning and continue.
> -			 */
> -			ERRMSG("Warning: line %d: 'within' keyword not "
> -				"required for ArrayVar/StructVar.\n", ie->line);
> -			free(ie->type_name);
> -
> -			/* remove the next list_head member from iteration
> -			 * entry that would have added as part of 'within'
> -			 * keyword processing.
> -			 */
> -			if (ie->next) {
> -				free_config_entry(ie->next);
> -				ie->next = NULL;
> -			}
> -		}
> -		ie->type_name = strdup(type_name);
> -	}
>  
> -	if (!ie->size) {
> -		ie->size = get_structure_size(ie->type_name,
> -						DWARF_INFO_GET_STRUCT_SIZE);
> +		/*
> +		 * For list_head find out the size of the StructName and
> +		 * populate ie->size now. For array and link list we get the
> +		 * size info from config entry returned by
> +		 * get_next_list_entry().
> +		 */
> +		ie->size = get_structure_size(ie->type_name, 0);
>  		if (ie->size == FAILED_DWARFINFO) {
>  			ERRMSG("Config error at %d: "
>  				"Can't get size for type: %s.\n",
> @@ -7345,8 +7382,7 @@ initialize_iteration_entry(struct config_entry *ie,
>  				ie->line, ie->type_name);
>  			return FALSE;
>  		}
> -	}
> -	if (type_flag & TYPE_LIST_HEAD) {
> +
>  		if (!resolve_config_entry(ie->next, 0, ie->type_name))
>  			return FALSE;
>  
> @@ -7356,6 +7392,34 @@ initialize_iteration_entry(struct config_entry *ie,
>  				ie->next->line, ie->next->name);
>  			return FALSE;
>  		}
> +		ie->type_flag = TYPE_STRUCT;
> +	}
> +	else {
> +		if (ie->type_name) {
> +			/* looks like user has used 'within' keyword for
> +			 * non-list_head VAR. Print the warning and continue.
> +			 */
> +			ERRMSG("Warning: line %d: 'within' keyword not "
> +				"required for ArrayVar/StructVar.\n", ie->line);
> +			free(ie->type_name);
> +
> +			/* remove the next list_head member from iteration
> +			 * entry that would have added as part of 'within'
> +			 * keyword processing.
> +			 */
> +			if (ie->next) {
> +				free_config_entry(ie->next);
> +				ie->next = NULL;
> +			}
> +		}
> +		/*
> +		 * Set type flag for iteration entry. The iteration entry holds
> +		 * individual element from array/list, hence strip off the
> +		 * array type flag bit.
> +		 */
> +		ie->type_name = strdup(type_name);
> +		ie->type_flag = type_flag;
> +		ie->type_flag &= ~TYPE_ARRAY;
>  	}
>  	return TRUE;
>  }
> @@ -7363,25 +7427,29 @@ initialize_iteration_entry(struct config_entry *ie,
>  int
>  list_entry_empty(struct config_entry *le, struct config_entry *ie)
>  {
> -	unsigned long long addr;
> +	struct config_entry ce;
>  
>  	/* Error out if arguments are not correct */
>  	if (!(le->flag & LIST_ENTRY) || !(ie->flag & ITERATION_ENTRY)) {
>  		ERRMSG("Invalid arguments\n");
>  		return TRUE;
>  	}
> -	addr = get_config_symbol_addr(le, 0, NULL);
> -	if (!addr)
> +
> +	memset(&ce, 0, sizeof(struct config_entry));
> +	/* get next available entry from LIST entry. */
> +	if (!get_next_list_entry(le, 0, NULL, &ce))
>  		return TRUE;
>  
>  	if (ie->next) {
>  		/* we are dealing with list_head */
> -		ie->next->addr = addr;
> -		ie->addr = addr - ie->next->offset;
> -		//resolve_iteration_entry(ie, addr);
> +		ie->next->addr = ce.addr;
> +		ie->addr = ce.addr - ie->next->offset;
> +	}
> +	else {
> +		ie->addr = ce.addr;
> +		ie->sym_addr = ce.sym_addr;
> +		ie->size = ce.size;
>  	}
> -	else
> -		ie->addr = addr;
>  	return FALSE;
>  }
>  
> 
> 
> -- 
> Mahesh J Salgaonkar




More information about the kexec mailing list