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 <[email protected]>
---
 defs.h  |  1 +
 help.c  | 12 +++++++++++-
 tools.c | 30 +++++++++++++++++++++++++++---
 3 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/defs.h b/defs.h
index 35b983a..764facf 100644
--- a/defs.h
+++ b/defs.h
@@ -2605,6 +2605,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 531f50a..b561f3b 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,16 @@ 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.",
+"",
+"               You can use it like the following:",
+"               list -O <head node offset> -o <node offset> -h start -s <...>",
 "    -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",
diff --git a/tools.c b/tools.c
index a26b101..792a567 100644
--- a/tools.c
+++ b/tools.c
@@ -3343,6 +3343,7 @@ void
 cmd_list(void)
 {
        int c;
+       long head_member_offset; /* 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,13 @@ next_arg:
                                fprintf(fp, "(empty)\n");
                                return;
                        }
-               } else
-                       ld->start += ld->list_head_offset;
+               } else {
+                       if (ld->flags & LIST_HEAD_OFFSET_ENTERED)
+                               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.30.2


--
Crash-utility mailing list
[email protected]
https://listman.redhat.com/mailman/listinfo/crash-utility

Reply via email to