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

Mahesh J Salgaonkar mahesh at linux.vnet.ibm.com
Tue Aug 30 14:16:42 EDT 2011


On 2011-08-11 17:06:21 Thu, Ken'ichi Ohmichi wrote:
> 
> Hi Mahesh,
> 
> On Wed, 18 May 2011 01:35:19 +0530
> Mahesh J Salgaonkar <mahesh at linux.vnet.ibm.com> wrote:
> >
> > From: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>
> > 
> > This patch adds support to read and process 'for' command from config file
> > to filter multiple memory locations that are accessible through an array,
> > link list or list_head.
> > 
> > The syntax for 'for' (loop construct) filter command is:
> > 
> > for <id> in {<ArrayVar> |
> > 	     <StructVar> via <NextMember> |
> > 	     <ListHeadVar> within <StructName>:<ListHeadMember>}
> > 	erase <id>[.MemberExpression] [size <SizeExpression>|nullify]
> > 	[erase <id> ...]
> > 	[...]
> > endfor
> > 
> > Updated filter.conf(8) man page that describes the syntax for loop construct.
> > 
> > Signed-off-by: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>
> > Signed-off-by: Prerna Saxena <prerna at linux.vnet.ibm.com>
> > ---
> 
> Thank you for the patch.
> I think this patch is good.
> 
> Acked-by: Ken'ichi Ohmichi <oomichi at mxs.nes.nec.co.jp>
> 
> 
> Thanks
> Ken'ichi Ohmichi

Hi Ken'ichi,

As I told you earlier I found few BUGs w.r.t patch 6/8 that processes loop
construct. Please find the patch below that fixes those BUGs. Please review.

Thanks,
-Mahesh.

-------

[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:

- If the loop construct is used for array of structures (non-pointer), then
the array index value is not incremented resulting in an infinite loop. This
patch fixes this BUG.
- The loop construct used for array of char* (pointer) silently fails and
does not filter the strings.
- Corrected 2nd argument while calling get_structure_size().
- Fixed dwarf_info.c:get_data_array_length() to handle array of const data
type.
  e.g.
	<1><1a49df3>: Abbrev Number: 90 (DW_TAG_variable)
	   <1a49df4>   DW_AT_name        : policycap_names
	   <1a49df8>   DW_AT_decl_file   : 1
	   <1a49df9>   DW_AT_decl_line   : 43
	   <1a49dfa>   DW_AT_type        : <0x1a49e08>
	<1><1a49e08>: Abbrev Number: 7 (DW_TAG_const_type)
	   <1a49e09>   DW_AT_type        : <0x1a49de3>
	<1><1a49de3>: Abbrev Number: 4 (DW_TAG_array_type)
	   <1a49de4>   DW_AT_type        : <0x1a3b276>
	   <1a49de8>   DW_AT_sibling     : <0x1a49df3>


Signed-off-by: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>
---
 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