On Thu, Oct 27, 2022 at 12:14 PM lijiang <lijiang@xxxxxxxxxx> wrote: > > On Tue, Oct 25, 2022 at 8:39 PM <crash-utility-request@xxxxxxxxxx> wrote: > > Date: Tue, 25 Oct 2022 20:38:22 +0800 > > From: Tao Liu <ltao@xxxxxxxxxx> > > To: crash-utility@xxxxxxxxxx > > Subject: [PATCH v2 3/6] Add tree cmd support for maple > > tree > > Message-ID: <20221025123825.36421-4-ltao@xxxxxxxxxx> > > Content-Type: text/plain; charset="US-ASCII"; x-default=true > > > > Maple tree is a new data structure for crash, so cmd_tree support is > > needed for users to dump and view the content of maple tree. This patch > > achieves this by porting mt_dump() and its related functions from kernel, > > and adapting them with tree cmd. > > > > We introduced a new -v arg specifically for dumping the complete > > content of maple tree: > > > > crash> tree -t maple 0xffff9034c006aec0 -v > > > > maple_tree(ffff9034c006aec0) flags 309, height 0 root 0xffff9034de70041e > > > > 0-18446744073709551615: node 0xffff9034de700400 depth 0 type 3 parent 0xffff9034c006aec1 contents:... > > 0-140112331583487: node 0xffff9034c01e8800 depth 1 type 1 parent 0xffff9034de700406 contents:... > > 0-94643156942847: (nil) > > 94643156942848-94643158024191: 0xffff9035131754c0 > > 94643158024192-94643160117247: (nil) > > ... > > > > The old tree args can work as well: > > > > crash> tree -t maple -r mm_struct.mm_mt 0xffff9034c006aec0 -p > > ffff9034de70041e > > index: 0 position: root > > ffff9034c01e880c > > index: 1 position: root/0 > > 0 > > index: 2 position: root/0/0 > > ffff9035131754c0 > > index: 3 position: root/0/1 > > 0 > > index: 4 position: root/0/2 > > .... > > > > crash> tree -t maple 0xffff9034c006aec0 -p -x -s vm_area_struct.vm_start,vm_end > > ffff9034de70041e > > index: 0 position: root > > ffff9034c01e880c > > index: 1 position: root/0 > > 0 > > index: 2 position: root/0/0 > > ffff9035131754c0 > > index: 3 position: root/0/1 > > vm_start = 0x5613d3c00000, > > vm_end = 0x5613d3d08000, > > 0 > > index: 4 position: root/0/2 > > ... > > > > Signed-off-by: Tao Liu <ltao@xxxxxxxxxx> > > --- > > defs.h | 5 + > > maple_tree.c | 385 +++++++++++++++++++++++++++++++++++++++++++++++++++ > > tools.c | 20 ++- > > 3 files changed, 404 insertions(+), 6 deletions(-) > > > > diff --git a/defs.h b/defs.h > > index 2978cec..3f2453e 100644 > > --- a/defs.h > > +++ b/defs.h > > @@ -2191,12 +2191,15 @@ struct offset_table { /* stash of commonly-used offsets */ > > long maple_arange_64_parent; > > long maple_arange_64_pivot; > > long maple_arange_64_slot; > > + long maple_arange_64_gap; > > long maple_arange_64_meta; > > long maple_range_64_parent; > > long maple_range_64_pivot; > > long maple_range_64_slot; > > + long maple_range_64_pad; > > long maple_range_64_meta; > > long maple_metadata_end; > > + long maple_metadata_gap; > > }; > > They have to be appended to the end of this table. > > > > > struct size_table { /* stash of commonly-used sizes */ > > @@ -2705,6 +2708,7 @@ struct tree_data { > > #define TREE_PARSE_MEMBER (VERBOSE << 7) > > #define TREE_READ_MEMBER (VERBOSE << 8) > > #define TREE_LINEAR_ORDER (VERBOSE << 9) > > +#define TREE_STRUCT_VERBOSE (VERBOSE << 9) > > > > #define ALIAS_RUNTIME (1) > > #define ALIAS_RCLOCAL (2) > > @@ -5576,6 +5580,7 @@ int same_file(char *, char *); > > int cleanup_memory_driver(void); > > > > void maple_init(void); > > +int do_mptree(struct tree_data *); > > > > /* > > * help.c > > diff --git a/maple_tree.c b/maple_tree.c > > index 058b769..33903cb 100644 > > --- a/maple_tree.c > > +++ b/maple_tree.c > > @@ -34,6 +34,7 @@ > > > > unsigned char *mt_slots = NULL; > > unsigned char *mt_pivots = NULL; > > +unsigned long mt_max[4] = {0}; > > > > #define MAPLE_BUFSIZE 512 > > > > @@ -791,6 +792,382 @@ void *mas_find(struct ma_state *mas, unsigned long max) > > return mas_next_entry(mas, max); > > } > > > > +/***************For cmd_tree********************/ > > + > > +struct do_maple_tree_info { > > + ulong maxcount; > > + ulong count; > > + void *data; > > +}; > > + > > +struct cmd_tree_info { > > + ulong index; > > + struct tree_data *td; > > +} cmd_tree_info; > > + > > +static const char spaces[] = " "; > > + > > +static void do_mt_range64(const struct maple_tree *, void *, > > + unsigned long, unsigned long, unsigned int, char *); > > +static void do_mt_arange64(const struct maple_tree *, void *, > > + unsigned long, unsigned long, unsigned int, char *); > > +static void do_mt_entry(void *, unsigned long, unsigned long, unsigned int, > > + unsigned int, char *); > > +static void do_mt_node(const struct maple_tree *, void *, unsigned long, > > + unsigned long, unsigned int, char *); > > +struct req_entry *fill_member_offsets(char *); > > +void dump_struct_members_fast(struct req_entry *, int, ulong); > > +void dump_struct_members_for_tree(struct tree_data *, int, ulong); > > + > > +static void mt_dump_range(unsigned long min, unsigned long max, > > + unsigned int depth) > > +{ > > + if (min == max) > > + fprintf(fp, "%.*s%lu: ", depth * 2, spaces, min); > > + else > > + fprintf(fp, "%.*s%lu-%lu: ", depth * 2, spaces, min, max); > > +} > > + > > +static inline bool mt_is_reserved(const void *entry) > > +{ > > + return ((unsigned long)entry < MAPLE_RESERVED_RANGE) && > > + xa_is_internal(entry); > > +} > > + > > +static inline bool mte_is_leaf(const struct maple_enode *entry) > > +{ > > + return ma_is_leaf(mte_node_type(entry)); > > +} > > + > > +static unsigned int mt_height(const struct maple_tree *mt) > > +{ > > + return (*(unsigned int *)(mt + OFFSET(maple_tree_ma_flags)) & > > + MT_FLAGS_HEIGHT_MASK) > > + >> MT_FLAGS_HEIGHT_OFFSET; > > +} > > + > > +static void dump_mt_range64(struct maple_range_64 *node) > > +{ > > + int i; > > + > > + fprintf(fp, " contents: "); > > + for (i = 0; i < mt_slots[maple_range_64] - 1; i++) > > + fprintf(fp, "%p %lu ", > > + *((void **)((char *)node + OFFSET(maple_range_64_slot)) + i), > > + *((unsigned long *)((char *)node + OFFSET(maple_range_64_pivot)) + i)); > > + fprintf(fp, "%p\n", *((void **)((char *)node + OFFSET(maple_range_64_slot)) + i)); > > +} > > + > > +static void dump_mt_arange64(struct maple_arange_64 *node) > > +{ > > + int i; > > + > > + fprintf(fp, " contents: "); > > + for (i = 0; i < mt_slots[maple_arange_64]; i++) > > + fprintf(fp, "%lu ", > > + *((unsigned long *)((char *)node + OFFSET(maple_arange_64_gap)) + i)); > > + > > + fprintf(fp, "| %02X %02X| ", > > + *((unsigned char *)node + OFFSET(maple_arange_64_meta) + OFFSET(maple_metadata_end)), > > + *((unsigned char *)node + OFFSET(maple_arange_64_meta) + OFFSET(maple_metadata_gap))); > > + > > + for (i = 0; i < mt_slots[maple_arange_64] - 1; i++) > > + fprintf(fp, "%p %lu ", > > + *((void **)((char *)node + OFFSET(maple_arange_64_slot)) + i), > > + *((unsigned long *)((char *)node + OFFSET(maple_arange_64_pivot)) + i)); > > + fprintf(fp, "%p\n", > > + *((void **)((char *)node + OFFSET(maple_arange_64_slot)) + i)); > > +} > > + > > +static void dump_mt_entry(void *entry, unsigned long min, unsigned long max, > > + unsigned int depth) > > +{ > > + mt_dump_range(min, max, depth); > > + > > + if (xa_is_value(entry)) > > + fprintf(fp, "value %ld (0x%lx) [%p]\n", xa_to_value(entry), > > + xa_to_value(entry), entry); > > + else if (xa_is_zero(entry)) > > + fprintf(fp, "zero (%ld)\n", xa_to_internal(entry)); > > + else if (mt_is_reserved(entry)) > > + fprintf(fp, "UNKNOWN ENTRY (%p)\n", entry); > > + else > > + fprintf(fp, "%p\n", entry); > > +} > > + > > +static void dump_mt_node(struct maple_node *node, char *node_data, > > + unsigned int type, unsigned long min, unsigned long max, > > + unsigned int depth) > > +{ > > + mt_dump_range(min, max, depth); > > + > > + fprintf(fp, "node %p depth %d type %d parent %p", node, depth, type, > > + node ? *(struct maple_pnode **)(node_data + OFFSET(maple_node_parent)) > > + : NULL); > > +} > > + > > +static void do_mt_range64(const struct maple_tree *mt, void *entry, > > + unsigned long min, unsigned long max, > > + unsigned int depth, char *path) > > +{ > > + struct maple_node *m_node = mte_to_node(entry); > > + unsigned char tmp_node[MAPLE_BUFSIZE]; > > + bool leaf = mte_is_leaf(entry); > > + unsigned long first = min, last; > > + int i; > > + int len = strlen(path); > > + > > + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE); > > + > > + readmem((ulonglong)m_node, KVADDR, tmp_node, SIZE(maple_node_struct), > > + "mt_dump_range64 read maple_node", FAULT_ON_ERROR); > > + > > + struct maple_range_64 *node = (struct maple_range_64 *) > > + (tmp_node + OFFSET(maple_node_mr64)); > > + > > + if (cmd_tree_info.td) { > > + if (cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) { > > + dump_mt_range64(node); > > + } > > + if (cmd_tree_info.td->flags & TREE_POSITION_DISPLAY) > > + fprintf(fp, "%.*s index: %ld position: %s\n", > > + depth * 2, spaces, cmd_tree_info.index++, path); > > + } > > + > > + for (i = 0; i < mt_slots[maple_range_64]; i++) { > > + last = max; > > + > > + if (i < (mt_slots[maple_range_64] - 1)) > > + last = *((unsigned long *)((char *)node + OFFSET(maple_range_64_pivot)) + i); > > + else if (!*((void **)((char *)node + OFFSET(maple_range_64_slot)) + i) && > > + max != mt_max[mte_node_type(entry)]) > > + break; > > + if (last == 0 && i > 0) > > + break; > > + if (leaf) > > + do_mt_entry(mt_slot(mt, (void **)((char *)node + OFFSET(maple_range_64_slot)), i), > > + first, last, depth + 1, i, path); > > + else if (*((void **)((char *)node + OFFSET(maple_range_64_slot)) + i)) { > > + sprintf(path + len, "/%d", i); > > + do_mt_node(mt, mt_slot(mt, (void **)((char *)node + OFFSET(maple_range_64_slot)), i), > > + first, last, depth + 1, path); > > + } > > + > > + if (last == max) > > + break; > > + if (last > max) { > > + fprintf(fp, "node %p last (%lu) > max (%lu) at pivot %d!\n", > > + node, last, max, i); > > + break; > > + } > > + first = last + 1; > > + } > > +} > > + > > +static void do_mt_arange64(const struct maple_tree *mt, void *entry, > > + unsigned long min, unsigned long max, unsigned int depth, > > + char *path) > > +{ > > + struct maple_node *m_node = mte_to_node(entry); > > + unsigned char tmp_node[MAPLE_BUFSIZE]; > > + bool leaf = mte_is_leaf(entry); > > + unsigned long first = min, last; > > + int i; > > + int len = strlen(path); > > + > > + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE); > > + > > + readmem((ulonglong)m_node, KVADDR, tmp_node, SIZE(maple_node_struct), > > + "mt_dump_arange64 read maple_node", FAULT_ON_ERROR); > > + > > + struct maple_arange_64 *node = (struct maple_arange_64 *) > > + (tmp_node + OFFSET(maple_node_ma64)); > > + > > + if (cmd_tree_info.td) { > > + if (cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) { > > + dump_mt_arange64(node); > > + } > > + if (cmd_tree_info.td->flags & TREE_POSITION_DISPLAY) > > + fprintf(fp, "%.*s index: %ld position: %s\n", > > + depth * 2, spaces, cmd_tree_info.index++, path); > > + } > > + > > + for (i = 0; i < mt_slots[maple_arange_64]; i++) { > > + last = max; > > + > > + if (i < (mt_slots[maple_arange_64] - 1)) > > + last = *((unsigned long *)((char *)node + OFFSET(maple_arange_64_pivot)) + i); > > + else if (! *((void **)((char *)node + OFFSET(maple_arange_64_slot)) + i)) > > + break; > > + if (last == 0 && i > 0) > > + break; > > + > > + if (leaf) > > + do_mt_entry(mt_slot(mt, (void **)((char *)node + OFFSET(maple_arange_64_slot)), i), > > + first, last, depth + 1, i, path); > > + else if (*((void **)((char *)node + OFFSET(maple_arange_64_slot)) + i)) { > > + sprintf(path + len, "/%d", i); > > + do_mt_node(mt, mt_slot(mt, (void **)((char *)node + OFFSET(maple_arange_64_slot)), i), > > + first, last, depth + 1, path); > > + } > > + > > + if (last == max) > > + break; > > + if (last > max) { > > + fprintf(fp, "node %p last (%lu) > max (%lu) at pivot %d!\n", > > + node, last, max, i); > > + break; > > + } > > + first = last + 1; > > + } > > +} > > + > > +static void do_mt_entry(void *entry, unsigned long min, unsigned long max, > > + unsigned int depth, unsigned int index, char *path) > > +{ > > + int print_radix = 0, i; > > + static struct req_entry **e = NULL; > > + > > + if (!cmd_tree_info.td) > > + return; > > + > > + if (!cmd_tree_info.td->count && cmd_tree_info.td->structname_args) { > > + /* > > + * Retrieve all members' info only once (count == 0) > > + * After last iteration all memory will be freed up > > + */ > > + e = (struct req_entry **)GETBUF(sizeof(*e) * cmd_tree_info.td->structname_args); > > + for (i = 0; i < cmd_tree_info.td->structname_args; i++) > > + e[i] = fill_member_offsets(cmd_tree_info.td->structname[i]); > > + } > > + > > + cmd_tree_info.td->count++; > > + > > + if (cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) { > > + dump_mt_entry(entry, min, max, depth); > > + } else if (cmd_tree_info.td->flags & VERBOSE) > > + fprintf(fp, "%.*s%lx\n", depth * 2, spaces, (ulong)entry); > > + if (cmd_tree_info.td->flags & TREE_POSITION_DISPLAY) > > + fprintf(fp, "%.*s index: %ld position: %s/%u\n", > > + depth * 2, spaces, cmd_tree_info.index++, path, index); > > + > > + if (cmd_tree_info.td->structname) { > > + if (cmd_tree_info.td->flags & TREE_STRUCT_RADIX_10) > > + print_radix = 10; > > + else if (cmd_tree_info.td->flags & TREE_STRUCT_RADIX_16) > > + print_radix = 16; > > + else > > + print_radix = 0; > > + > > + for (i = 0; i < cmd_tree_info.td->structname_args; i++) { > > + switch (count_chars(cmd_tree_info.td->structname[i], '.')) { > > + case 0: > > + dump_struct(cmd_tree_info.td->structname[i], > > + (ulong)entry, print_radix); > > + break; > > + default: > > + if (cmd_tree_info.td->flags & TREE_PARSE_MEMBER) > > + dump_struct_members_for_tree(cmd_tree_info.td, i, (ulong)entry); > > + else if (cmd_tree_info.td->flags & TREE_READ_MEMBER) > > + dump_struct_members_fast(e[i], print_radix, (ulong)entry); > > + break; > > + } > > + } > > + } > > +} > > + > > +static void do_mt_node(const struct maple_tree *mt, void *entry, > > + unsigned long min, unsigned long max, unsigned int depth, > > + char *path) > > +{ > > + struct maple_node *node = mte_to_node(entry); > > + unsigned int type = mte_node_type(entry); > > + unsigned int i; > > + char tmp_node[MAPLE_BUFSIZE]; > > + > > + assert(SIZE(maple_node_struct) <= MAPLE_BUFSIZE); > > + > > + readmem((ulonglong)node, KVADDR, tmp_node, SIZE(maple_node_struct), > > + "mt_dump_node read maple_node", FAULT_ON_ERROR); > > + > > + if (cmd_tree_info.td) { > > + if (cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) { > > + dump_mt_node(node, tmp_node, type, min, max, depth); > > + } else if (cmd_tree_info.td->flags & VERBOSE) > > + fprintf(fp, "%.*s%lx\n", depth * 2, spaces, (ulong)entry); > > + } > > + > > + switch (type) { > > + case maple_dense: > > + if (cmd_tree_info.td && > > + cmd_tree_info.td->flags & TREE_POSITION_DISPLAY) > > + fprintf(fp, "%.*s index: %ld position: %s\n", > > + depth * 2, spaces, cmd_tree_info.index++, path); > > + for (i = 0; i < mt_slots[maple_dense]; i++) { > > + if (min + i > max) > > + fprintf(fp, "OUT OF RANGE: "); > > + do_mt_entry(mt_slot(mt, (void **)(tmp_node + OFFSET(maple_node_slot)), i), > > + min + i, min + i, depth, i, path); > > + } > > + break; > > + case maple_leaf_64: > > + case maple_range_64: > > + do_mt_range64(mt, entry, min, max, depth, path); > > + break; > > + case maple_arange_64: > > + do_mt_arange64(mt, entry, min, max, depth, path); > > + break; > > + default: > > + fprintf(fp, " UNKNOWN TYPE\n"); > > + } > > +} > > + > > +static int do_maple_tree_traverse(ulong ptr, int is_root) > > +{ > > + char path[BUFSIZE] = {0}; > > + unsigned char tmp_tree[MAPLE_BUFSIZE]; > > + void *entry; > > + > > Here, I would recommend checking if the related structures or members > are valid, just like this: > > if (!VALID_STRUCT(maple_tree_struct) || > !VALID_STRUCT(maple_node_struct) || > !VALID_MEMBER(maple_tree_ma_root) ...) > error(FATAL, > "maple tree does not exist or has changed its > format\n"); > ... > hmm... Not sure if the check is necessary. There are plenty of structures/members involved, see maple_* in def.h:offset_table. If we really care about the change of maple tree structure, all the variables should be checked IMHO, and that will make the checking code long and tedious... Thanks, Tao Liu > Thanks. > Lianbo > > > + assert(SIZE(maple_tree_struct) <= MAPLE_BUFSIZE); > > + > > + if (!is_root) { > > + strcpy(path, "direct"); > > + do_mt_node(NULL, (void *)ptr, 0, > > + mt_max[mte_node_type((struct maple_enode *)ptr)], 0, path); > > + } else { > > + readmem((ulonglong)ptr, KVADDR, tmp_tree, SIZE(maple_tree_struct), > > + "mt_dump read maple_tree", FAULT_ON_ERROR); > > + entry = *(void **)(tmp_tree + OFFSET(maple_tree_ma_root)); > > + > > + if (cmd_tree_info.td && > > + cmd_tree_info.td->flags & TREE_STRUCT_VERBOSE) { > > + fprintf(fp, "maple_tree(%lx) flags %X, height %u root %p\n\n", > > + ptr, *(unsigned int *)(tmp_tree + OFFSET(maple_tree_ma_flags)), > > + mt_height((struct maple_tree *)tmp_tree), entry); > > + } > > + > > + if (!xa_is_node(entry)) > > + do_mt_entry(entry, 0, 0, 0, 0, path); > > + else if (entry) { > > + strcpy(path, "root"); > > + do_mt_node((struct maple_tree *)tmp_tree, entry, 0, > > + mt_max[mte_node_type(entry)], 0, path); > > + } > > + } > > + return 0; > > +} > > + > > +int do_mptree(struct tree_data *td) > > +{ > > + int is_root = !(td->flags & TREE_NODE_POINTER); > > + > > + memset(&cmd_tree_info, 0, sizeof(cmd_tree_info)); > > + cmd_tree_info.td = td; > > + do_maple_tree_traverse(td->start, is_root); > > + > > + return 0; > > +} > > + > > /***********************************************/ > > void maple_init(void) > > { > > @@ -810,14 +1187,17 @@ void maple_init(void) > > MEMBER_OFFSET_INIT(maple_arange_64_parent, "maple_arange_64", "parent"); > > MEMBER_OFFSET_INIT(maple_arange_64_pivot, "maple_arange_64", "pivot"); > > MEMBER_OFFSET_INIT(maple_arange_64_slot, "maple_arange_64", "slot"); > > + MEMBER_OFFSET_INIT(maple_arange_64_gap, "maple_arange_64", "gap"); > > MEMBER_OFFSET_INIT(maple_arange_64_meta, "maple_arange_64", "meta"); > > > > MEMBER_OFFSET_INIT(maple_range_64_parent, "maple_range_64", "parent"); > > MEMBER_OFFSET_INIT(maple_range_64_pivot, "maple_range_64", "pivot"); > > MEMBER_OFFSET_INIT(maple_range_64_slot, "maple_range_64", "slot"); > > + MEMBER_OFFSET_INIT(maple_range_64_pad, "maple_range_64", "pad"); > > MEMBER_OFFSET_INIT(maple_range_64_meta, "maple_range_64", "meta"); > > > > MEMBER_OFFSET_INIT(maple_metadata_end, "maple_metadata", "end"); > > + MEMBER_OFFSET_INIT(maple_metadata_gap, "maple_metadata", "gap"); > > > > array_len = get_array_length("mt_slots", NULL, sizeof(char)); > > mt_slots = calloc(array_len, sizeof(char)); > > @@ -830,4 +1210,9 @@ void maple_init(void) > > readmem(symbol_value("mt_pivots"), KVADDR, mt_pivots, > > array_len * sizeof(char), "maple_init read mt_pivots", > > FAULT_ON_ERROR); > > + > > + mt_max[maple_dense] = mt_slots[maple_dense]; > > + mt_max[maple_leaf_64] = ULONG_MAX; > > + mt_max[maple_range_64] = ULONG_MAX; > > + mt_max[maple_arange_64] = ULONG_MAX; > > } > > \ No newline at end of file > > diff --git a/tools.c b/tools.c > > index 39306c1..3cb93c1 100644 > > --- a/tools.c > > +++ b/tools.c > > @@ -30,7 +30,7 @@ static void dealloc_hq_entry(struct hq_entry *); > > static void show_options(void); > > static void dump_struct_members(struct list_data *, int, ulong); > > static void rbtree_iteration(ulong, struct tree_data *, char *); > > -static void dump_struct_members_for_tree(struct tree_data *, int, ulong); > > +void dump_struct_members_for_tree(struct tree_data *, int, ulong); > > > > struct req_entry { > > char *arg, *name, **member; > > @@ -40,8 +40,8 @@ struct req_entry { > > }; > > > > static void print_value(struct req_entry *, unsigned int, ulong, unsigned int); > > -static struct req_entry *fill_member_offsets(char *); > > -static void dump_struct_members_fast(struct req_entry *, int, ulong); > > +struct req_entry *fill_member_offsets(char *); > > +void dump_struct_members_fast(struct req_entry *, int, ulong); > > > > FILE * > > set_error(char *target) > > @@ -3666,7 +3666,7 @@ dump_struct_members_fast(struct req_entry *e, int radix, ulong p) > > } > > } > > > > -static struct req_entry * > > +struct req_entry * > > fill_member_offsets(char *arg) > > { > > int j; > > @@ -4307,6 +4307,7 @@ dump_struct_members(struct list_data *ld, int idx, ulong next) > > #define RADIXTREE_REQUEST (0x1) > > #define RBTREE_REQUEST (0x2) > > #define XARRAY_REQUEST (0x4) > > +#define MAPLE_REQUEST (0x8) > > > > void > > cmd_tree() > > @@ -4324,11 +4325,11 @@ cmd_tree() > > td = &tree_data; > > BZERO(td, sizeof(struct tree_data)); > > > > - while ((c = getopt(argcnt, args, "xdt:r:o:s:S:plN")) != EOF) { > > + while ((c = getopt(argcnt, args, "xdt:r:o:s:S:plNv")) != EOF) { > > switch (c) > > { > > case 't': > > - if (type_flag & (RADIXTREE_REQUEST|RBTREE_REQUEST|XARRAY_REQUEST)) { > > + if (type_flag & (RADIXTREE_REQUEST|RBTREE_REQUEST|XARRAY_REQUEST|MAPLE_REQUEST)) { > > error(INFO, "multiple tree types may not be entered\n"); > > cmd_usage(pc->curcmd, SYNOPSIS); > > } > > @@ -4342,6 +4343,8 @@ cmd_tree() > > type_flag = RBTREE_REQUEST; > > else if (STRNEQ(optarg, "x")) > > type_flag = XARRAY_REQUEST; > > + else if (STRNEQ(optarg, "m")) > > + type_flag = MAPLE_REQUEST; > > else { > > error(INFO, "invalid tree type: %s\n", optarg); > > cmd_usage(pc->curcmd, SYNOPSIS); > > @@ -4417,6 +4420,9 @@ cmd_tree() > > "-d and -x are mutually exclusive\n"); > > td->flags |= TREE_STRUCT_RADIX_10; > > break; > > + case 'v': > > + td->flags |= TREE_STRUCT_VERBOSE; > > + break; > > default: > > argerrs++; > > break; > > @@ -4532,6 +4538,8 @@ next_arg: > > do_rdtree(td); > > else if (type_flag & XARRAY_REQUEST) > > do_xatree(td); > > + else if (type_flag & MAPLE_REQUEST) > > + do_mptree(td); > > else > > do_rbtree(td); > > hq_close(); > > -- > > 2.33.1 > -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://listman.redhat.com/mailman/listinfo/crash-utility Contribution Guidelines: https://github.com/crash-utility/crash/wiki