The 06/01/2021 13:01, lijiang wrote: > Hi, Firo > Thank you for the update. > On Wed, May 26, 2021 at 12:00 AM <crash-utility-request@xxxxxxxxxx> wrote: > > > Date: Tue, 25 May 2021 18:17:37 +0800 > > From: Firo Yang <firo.yang@xxxxxxxx> > > To: k-hagio-ab@xxxxxxx > > Cc: firogm@xxxxxxxxx, crash-utility@xxxxxxxxxx > > Subject: [PATCH v3 1/1] tools: list: create O option > > for specifying head node offset > > Message-ID: <20210525101737.51232-1-firo.yang@xxxxxxxx> > > Content-Type: text/plain > > > > This -O option is very useful to specify the embedded head node's > > offset which is different to the offset of other nodes embedded, > > 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 | 32 +++++++++++++++++++++++++++++++- > > tools.c | 36 +++++++++++++++++++++++++++++++++--- > > 3 files changed, 65 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..1593f12 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,15 @@ 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 Only used in conjunction with -h; it specifies the offset > > of head", > > +" node list_head embedded within a data structure which is > > different", > > +" than the offset of list_head of other nodes embedded > > within a data", > > +" structure.", > > +" The offset may be entered in either of the following > > 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 +6125,27 @@ char *help__list[] = { > > " comm = \"sudo\"", > > " ffff88005ac10180", > > " comm = \"crash\"", > > +"", > > +" To display a liked list whose head node and other nodes are embedded > > within ", > > +" either same or different data structures resulting in different > > offsets ", > > +" for head node and other nodes, e.g. dentry.d_subdirs and > > dentry.d_child, this", > > +" -O option can be used:", > > +"", > > +" %s> list -o dentry.d_child -s dentry.d_name.name -O > > dentry.d_subdirs -h ffff9c585b81a180", > > +" ffff9c585b9cb140", > > +" d_name.name = 0xffff9c585b9cb178 ccc.txt", > > +" ffff9c585b9cb980", > > +" d_name.name = 0xffff9c585b9cb9b8 bbb.txt", > > +" ffff9c585b9cb740", > > +" d_name.name = 0xffff9c585b9cb778 aaa.txt", > > +"", > > +" The dentry.d_subdirs example above is equal to the following > > sequence:", > > +"", > > +" %s> struct -o dentry.d_subdirs ffff9c585b81a180", > > +" struct dentry {", > > +" [ffff9c585b81a220] struct list_head d_subdirs;", > > +" }", > > +" %s> list -o dentry.d_child -s dentry.d_name.name -H > > ffff9c585b81a220", > > NULL > > }; > > > > diff --git a/tools.c b/tools.c > > index a26b101..636adc6 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,19 @@ 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); > > + if (ld->start == ld->end) { > > + fprintf(fp, "(empty)\n"); > > + return; > > + } > > > > The code block " if (ld->flags & LIST_HEAD_OFFSET_ENTERED) " should be at > the same level with the code block "if (ld->flags & LIST_OFFSET_ENTERED)", > just like the option "-o" and "-O" in the "switch-case" code blocks. For > example: > > if (ld->flags & LIST_HEAD_POINTER) { > if (!ld->end) > ld->end = ld->start; > readmem(ld->start + ld->member_offset, KVADDR, > &ld->start, > sizeof(void *), "LIST_HEAD contents", > FAULT_ON_ERROR); > if (ld->start == ld->end) { > fprintf(fp, "(empty)\n"); > return; > } > + } 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); > + if (ld->start == ld->end) { > + fprintf(fp, "(empty)\n"); > + return; > + } > } else > ld->start += ld->list_head_offset; > > The code looks more readable, but the above two "if" code blocks look very > similar, not sure if the code refactoring will be needed. > > What do you think about this? Firo and Kazu. Hi Lianbo, after thinking about this code for a while, I think the code refactoring is not necessary because 1) the original code makes more sense to express the mutual exclusive semantics between -H (ld->flags & LIST_HEAD_POINTER) and -h. 2) LIST_HEAD_OFFSET_ENTERED and LIST_OFFSET_ENTERED don't have to be at same level because LIST_HEAD_OFFSET_ENTERED is just a sub-option for -h. So please consider accepting the original patch. Thanks, Firo -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://listman.redhat.com/mailman/listinfo/crash-utility