[Crash-utility] [PATCH v2 1/1] tools: list: create O option for specifying head node offset

Firo Yang firo.yang at suse.com
Thu May 20 06:31:56 UTC 2021


This new O option is very useful to specify the head node
offset for listing linked list whose head node embedded has a
different offset to other node, e.g. dentry.d_subdirs(the head node)
and dentry.d_child.

Signed-off-by: Firo Yang <firo.yang at suse.com>
---
 defs.h  |  1 +
 help.c  | 15 ++++++++++++++-
 tools.c | 32 +++++++++++++++++++++++++++++---
 3 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/defs.h b/defs.h
index 396d61a..d5fcd37 100644
--- a/defs.h
+++ b/defs.h
@@ -2613,6 +2613,7 @@ struct list_data {             /* generic structure used by do_list() to walk */
 #define LIST_PARSE_MEMBER   (VERBOSE << 13)
 #define LIST_READ_MEMBER    (VERBOSE << 14)
 #define LIST_BRENT_ALGO     (VERBOSE << 15)
+#define LIST_HEAD_OFFSET_ENTERED  (VERBOSE << 16)
 
 struct tree_data {
 	ulong flags;
diff --git a/help.c b/help.c
index e0c8408..3aa99f0 100644
--- a/help.c
+++ b/help.c
@@ -5716,7 +5716,7 @@ char *help__list[] = {
 "list",
 "linked list",
 "[[-o] offset][-e end][-[s|S] struct[.member[,member] [-l offset]] -[x|d]]"
-"\n       [-r|-B] [-h|-H] start",
+"\n       [-r|-B] [-h [-O head_offset]|-H] start",
 " ",
 "  This command dumps the contents of a linked list.  The entries in a linked",
 "  list are typically data structures that are tied together in one of two",
@@ -5800,6 +5800,14 @@ char *help__list[] = {
 "    -S struct  Similar to -s, but instead of parsing gdb output, member values",
 "               are read directly from memory, so the command works much faster",
 "               for 1-, 2-, 4-, and 8-byte members.",
+"    -O offset  The -O option works only with -h option.",
+"               It is used for specifying the offset of head node embedded in a",
+"               structure, like dentry.d_subdirs or cgroup_subsys_state.children.",
+"               The offset may be entered in either of two manners:",
+"",
+"               1. \"structure.member\" format.",
+"               2. a number of bytes.",
+"",
 "    -l offset  Only used in conjunction with -s, if the start address argument",
 "               is a pointer to an embedded list head (or any other similar list",
 "               linkage structure whose first member points to the next linkage",
@@ -6116,6 +6124,11 @@ char *help__list[] = {
 "      comm = \"sudo\"",
 "    ffff88005ac10180",
 "      comm = \"crash\"",
+"",
+"  With the support of '-O' option, we can easily achieve the following convenient",
+"  usage: ",
+"    %s> alias ls list -O dentry.d_subdirs -o dentry.d_child -s dentry.d_name.name -h ",
+"    %s> ls <address of dentry>",
 NULL               
 };
 
diff --git a/tools.c b/tools.c
index a26b101..6a11670 100644
--- a/tools.c
+++ b/tools.c
@@ -3343,6 +3343,7 @@ void
 cmd_list(void)
 {
 	int c;
+	long head_member_offset = 0; /* offset for head like denty.d_subdirs */
 	struct list_data list_data, *ld;
 	struct datatype_member struct_member, *sm;
 	struct syment *sp;
@@ -3353,7 +3354,7 @@ cmd_list(void)
 	BZERO(ld, sizeof(struct list_data));
 	struct_list_offset = 0;
 
-	while ((c = getopt(argcnt, args, "BHhrs:S:e:o:xdl:")) != EOF) {
+	while ((c = getopt(argcnt, args, "BHhrs:S:e:o:O:xdl:")) != EOF) {
                 switch(c)
 		{
 		case 'B':
@@ -3394,6 +3395,24 @@ cmd_list(void)
 					optarg);
 			break;
 
+		case 'O':
+			if (ld->flags & LIST_HEAD_OFFSET_ENTERED)
+                               error(FATAL,
+                                "offset value %d (0x%lx) already entered\n",
+                                        head_member_offset, head_member_offset);
+			else if (IS_A_NUMBER(optarg))
+				head_member_offset = stol(optarg,
+					FAULT_ON_ERROR, NULL);
+			else if (arg_to_datatype(optarg,
+				sm, RETURN_ON_ERROR) > 1)
+				head_member_offset = sm->member_offset;
+			else
+				error(FATAL, "invalid -O argument: %s\n",
+					optarg);
+
+			ld->flags |= LIST_HEAD_OFFSET_ENTERED;
+			break;
+
 		case 'o':
 			if (ld->flags & LIST_OFFSET_ENTERED) 
                                error(FATAL,
@@ -3599,8 +3618,15 @@ next_arg:
 				fprintf(fp, "(empty)\n");
 				return;
 			}
-		} else
-			ld->start += ld->list_head_offset;
+		} else {
+			if (ld->flags & LIST_HEAD_OFFSET_ENTERED) {
+				if (!ld->end)
+					ld->end = ld->start + head_member_offset;
+				readmem(ld->start + head_member_offset, KVADDR,
+					&ld->start, sizeof(void *), "LIST_HEAD contents", FAULT_ON_ERROR);
+			} else
+				ld->start += ld->list_head_offset;
+		}
 	}
 
 	ld->flags &= ~(LIST_OFFSET_ENTERED|LIST_START_ENTERED);
-- 
2.31.1





More information about the Crash-utility mailing list