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@xxxxxxxx> --- 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 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://listman.redhat.com/mailman/listinfo/crash-utility