Hi Dave, here is the patch which introduces new key of `list` and `tree` commands. If new key is used, crash reads fields by means of 'readmem' function instead of parsing the gdb output. Therefore works much faster: % echo "tree -t radix -r address_space.page_tree -s page.flags,index,private ffff880456375220 | wc -l" | time ./crash -s ../crash_images/504.23.4.el6_x86-64-vm* crash: invalid task address: ffffffff81a01ea8 scroll: off (/usr/bin/less) extend: r.so: No such device or address 16652 ./crash -s ../crash_images/504.23.4.el6_x86-64-vm* 226.63s user 2.90s system 99% cpu 3:51.42 total % echo "tree -t radix -r address_space.page_tree -S page.flags,index,private ffff880456375220 | wc -l" | time ./crash -s ../crash_images/504.23.4.el6_x86-64-vm* crash: invalid task address: ffffffff81a01ea8 scroll: off (/usr/bin/less) extend: r.so: No such device or address 16652 ./crash -s ../crash_images/504.23.4.el6_x86-64-vm* 5.30s user 0.14s system 99% cpu 5.460 total 11,000,000 records might be dealt with within several minutes. Looking forward to your comments. Best, Alexandr --- crash-7.1.5.orig/tools.c 2016-04-27 21:46:50.000000000 +0300 +++ crash-7.1.5/tools.c 2016-07-26 13:56:27.192042851 +0300 @@ -23,10 +23,11 @@ struct hq_entry; 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 dump_struct_members(struct struct_req_entry *, int, ulong); static void rbtree_iteration(ulong, struct tree_data *, char *); static void rdtree_iteration(ulong, struct tree_data *, char *, ulong, uint); -static void dump_struct_members_for_tree(struct tree_data *, int, ulong); +static struct struct_req_entry *fill_member_offsets(char *); +static void print_value(char *, ulong, short, unsigned int); /* * General purpose error reporting routine. Type INFO prints the message @@ -3229,7 +3230,7 @@ BZERO(ld, sizeof(struct list_data)); struct_list_offset = 0; - while ((c = getopt(argcnt, args, "Hhrs:e:o:xdl:")) != EOF) { + while ((c = getopt(argcnt, args, "Hhrs:S:e:o:xdl:")) != EOF) { switch(c) { case 'H': @@ -3246,10 +3247,15 @@ break; case 's': - if (ld->structname_args++ == 0) - hq_open(); - hq_enter((ulong)optarg); - break; + case 'S': + if (ld->entries == 8) + error(WARNING, "Too many `-S` arguments." + " Ignoring argument: '%s'\n", optarg); + else { + ld->e[ld->entries] = fill_member_offsets(optarg); + ld->e[ld->entries++]->ff = (c == 's' ? FANCY : FAST); + } + break; case 'l': if (IS_A_NUMBER(optarg)) @@ -3313,13 +3319,10 @@ cmd_usage(pc->curcmd, SYNOPSIS); } - if (ld->structname_args) { - ld->structname = (char **)GETBUF(sizeof(char *) * ld->structname_args); - retrieve_list((ulong *)ld->structname, ld->structname_args); - hq_close(); + if (ld->entries) { ld->struct_list_offset = struct_list_offset; } else if (struct_list_offset) { - error(INFO, "-l option can only be used with -s option\n"); + error(INFO, "-l option can only be used with -s or -S option\n"); cmd_usage(pc->curcmd, SYNOPSIS); } @@ -3478,9 +3481,6 @@ hq_open(); c = do_list(ld); hq_close(); - - if (ld->structname_args) - FREEBUF(ld->structname); } @@ -3493,8 +3493,9 @@ { ulong next, last, first; ulong searchfor, readflag; - int i, count, others, close_hq_on_return; + int i, j, count, others, close_hq_on_return; unsigned int radix; + char b[BUFSIZE]; if (CRASHDEBUG(1)) { others = 0; @@ -3531,11 +3532,16 @@ console(" list_head_offset: %ld\n", ld->list_head_offset); console(" end: %lx\n", ld->end); console(" searchfor: %lx\n", ld->searchfor); - console(" structname_args: %lx\n", ld->structname_args); - if (!ld->structname_args) - console(" structname: (unused)\n"); - for (i = 0; i < ld->structname_args; i++) - console(" structname[%d]: %s\n", i, ld->structname[i]); + console(" entries: %lx\n", ld->entries); + for (i = 0; i < ld->entries; i++) { + console(" entry[%d]: ", i); + for (j = 0; j < ld->e[i]->count; j++) { + snprintf(b, BUFSIZE, "{ member: %s, width: %d, offset: %d }", + ld->e[i]->member[j], ld->e[i]->width[j], ld->e[i]->offset[j]); + console("%s", b); + console(j == ld->e[i]->count - 1 ? "\n" : ", "); + } + } console(" header: %s\n", ld->header); console(" list_ptr: %lx\n", (ulong)ld->list_ptr); console(" callback_func: %lx\n", (ulong)ld->callback_func); @@ -3584,21 +3590,16 @@ if (ld->flags & VERBOSE) { fprintf(fp, "%lx\n", next - ld->list_head_offset); - if (ld->structname) { - for (i = 0; i < ld->structname_args; i++) { - switch (count_chars(ld->structname[i], '.')) - { - case 0: - dump_struct(ld->structname[i], - next - ld->list_head_offset - ld->struct_list_offset, - radix); - break; - default: - dump_struct_members(ld, i, next); - break; - } - } - } + for (i = 0; i < ld->entries; i++) { + struct struct_req_entry *e = ld->e[i]; + if (e->count == 0) + dump_struct(e->name, + next - ld->list_head_offset - ld->struct_list_offset, + radix); + else + dump_struct_members(e, radix, + next - ld->list_head_offset - ld->struct_list_offset); + } } if (next && !hq_enter(next - ld->list_head_offset)) { @@ -3689,41 +3690,22 @@ * struct.member1,member2,member3 */ void -dump_struct_members(struct list_data *ld, int idx, ulong next) +dump_struct_members(struct struct_req_entry *e, int radix, ulong p) { - int i, argc; - char *p1, *p2; - char *structname, *members; - char *arglist[MAXARGS]; - unsigned int radix; + unsigned int i; + char b[BUFSIZE]; - if (ld->flags & LIST_STRUCT_RADIX_10) - radix = 10; - else if (ld->flags & LIST_STRUCT_RADIX_16) - radix = 16; - else - radix = 0; - - structname = GETBUF(strlen(ld->structname[idx])+1); - members = GETBUF(strlen(ld->structname[idx])+1); - - strcpy(structname, ld->structname[idx]); - p1 = strstr(structname, ".") + 1; - - p2 = strstr(ld->structname[idx], ".") + 1; - strcpy(members, p2); - replace_string(members, ",", ' '); - argc = parse_line(members, arglist); + if (!IS_KVADDR(p)) + return; - for (i = 0; i < argc; i++) { - *p1 = NULLCHAR; - strcat(structname, arglist[i]); - dump_struct_member(structname, - next - ld->list_head_offset - ld->struct_list_offset, radix); + for (i = 0; i < e->count; i++) { + if (e->ff == FANCY || e->width[i] == 0 || e->width[i] > 8) { + snprintf(b, BUFSIZE, "%s.%s", e->name, e->member[i]); + dump_struct_member(b, p, radix); + } else { + print_value(e->member[i], p + e->offset[i], e->width[i], radix); + } } - - FREEBUF(structname); - FREEBUF(members); } #define RADIXTREE_REQUEST (0x1) @@ -3745,7 +3727,7 @@ td = &tree_data; BZERO(td, sizeof(struct tree_data)); - while ((c = getopt(argcnt, args, "xdt:r:o:s:pN")) != EOF) { + while ((c = getopt(argcnt, args, "xdt:r:o:s:S:pN")) != EOF) { switch (c) { case 't': @@ -3799,11 +3781,15 @@ break; case 's': - if (td->structname_args++ == 0) - hq_open(); - hq_enter((ulong)optarg); - break; - + case 'S': + if (td->entries == 8) + error(WARNING, "Too many `-S` arguments." + " Ignoring argument: '%s'\n", optarg); + else { + td->e[td->entries] = fill_member_offsets(optarg); + td->e[td->entries++]->ff = (c == 's' ? FANCY : FAST); + } + break; case 'p': td->flags |= TREE_POSITION_DISPLAY; break; @@ -3878,13 +3864,6 @@ cmd_usage(pc->curcmd, SYNOPSIS); } - if (td->structname_args) { - td->structname = (char **)GETBUF(sizeof(char *) * - td->structname_args); - retrieve_list((ulong *)td->structname, td->structname_args); - hq_close(); - } - if (!(td->flags & TREE_NODE_POINTER)) td->start = td->start + root_offset; @@ -3916,7 +3895,7 @@ td->flags & TREE_NODE_POINTER ? "yes" : "no"); fprintf(fp, " start: %lx\n", td->start); fprintf(fp, "node_member_offset: %ld\n", td->node_member_offset); - fprintf(fp, " structname_args: %d\n", td->structname_args); + fprintf(fp, " entries: %d\n", td->entries); fprintf(fp, " count: %d\n", td->count); } @@ -3924,20 +3903,68 @@ td->flags |= VERBOSE; hq_open(); + if (type_flag & RADIXTREE_REQUEST) do_rdtree(td); else do_rbtree(td); hq_close(); - - if (td->structname_args) - FREEBUF(td->structname); } static ulong RADIX_TREE_MAP_SHIFT = UNINITIALIZED; static ulong RADIX_TREE_MAP_SIZE = UNINITIALIZED; static ulong RADIX_TREE_MAP_MASK = UNINITIALIZED; +static struct struct_req_entry * +fill_member_offsets(char *arg) +{ + int j; + char *p, m; + struct struct_req_entry *e; + char b[BUFSIZE]; + + if (!(arg && *arg)) + return NULL; + + j = count_chars(arg, ',') + 1; + e = (struct struct_req_entry *)GETBUF(sizeof(*e)); + + e->arg = GETBUF(strlen(arg + 1)); + strcpy(e->arg, arg); + + m = ((p = strchr(e->arg, '.')) != NULL); + if (!p++) + p = e->arg + strlen(e->arg) + 1; + + e->name = GETBUF(p - e->arg); + strncpy(e->name, e->arg, p - e->arg - 1); + + if (!m) + return e; + + e->count = count_chars(p, ',') + 1; + e->width = GETBUF(e->count); + e->member = (char **)GETBUF(e->count * sizeof(char *)); + e->offset = (short *)GETBUF(e->count * sizeof(short)); + + replace_string(p, ",", ' '); + parse_line(p, e->member); + + for (j = 0; j < e->count; j++) { + e->offset[j] = MEMBER_OFFSET(e->name, e->member[j]); + if (e->offset[j] == -1) + e->offset[j] = ANON_MEMBER_OFFSET(e->name, e->member[j]); + if (e->offset[j] == -1) + break; + + // Dirty hack for obtaining size of particular field + snprintf(b, BUFSIZE, "%s + 1", e->member[j]); + e->width[j] = ANON_MEMBER_OFFSET(e->name, b) - e->offset[j]; + } + + return e; +} + int do_rdtree(struct tree_data *td) { @@ -4049,28 +4076,20 @@ if (td->flags & TREE_POSITION_DISPLAY) fprintf(fp, " position: %s/%d\n", pos, index); - if (td->structname) { - if (td->flags & TREE_STRUCT_RADIX_10) - print_radix = 10; - else if (td->flags & TREE_STRUCT_RADIX_16) - print_radix = 16; - else - print_radix = 0; + if (td->flags & TREE_STRUCT_RADIX_10) + print_radix = 10; + else if (td->flags & TREE_STRUCT_RADIX_16) + print_radix = 16; + else + print_radix = 0; - for (i = 0; i < td->structname_args; i++) { - switch(count_chars(td->structname[i], '.')) - { - case 0: - dump_struct(td->structname[i], - slot, print_radix); - break; - default: - dump_struct_members_for_tree(td, i, - slot); - break; - } - } - } + for (i = 0; i < td->entries; i++) { + struct struct_req_entry *e = td->e[i]; + if (e->count == 0) + dump_struct(e->name, slot, print_radix); + else + dump_struct_members(td->e[i], print_radix, slot); + } } else rdtree_iteration(slot, td, pos, index, height-1); } @@ -4124,26 +4143,20 @@ if (td->flags & TREE_POSITION_DISPLAY) fprintf(fp, " position: %s\n", pos); - if (td->structname) { - if (td->flags & TREE_STRUCT_RADIX_10) - print_radix = 10; - else if (td->flags & TREE_STRUCT_RADIX_16) - print_radix = 16; - else - print_radix = 0; + if (td->flags & TREE_STRUCT_RADIX_10) + print_radix = 10; + else if (td->flags & TREE_STRUCT_RADIX_16) + print_radix = 16; + else + print_radix = 0; - for (i = 0; i < td->structname_args; i++) { - switch(count_chars(td->structname[i], '.')) - { - case 0: - dump_struct(td->structname[i], struct_p, print_radix); - break; - default: - dump_struct_members_for_tree(td, i, struct_p); - break; - } - } - } + for (i = 0; i < td->entries; i++) { + struct struct_req_entry *e = td->e[i]; + if (e->count == 0) + dump_struct(e->name, struct_p, print_radix); + else + dump_struct_members(td->e[i], print_radix, struct_p); + } readmem(node_p+OFFSET(rb_node_rb_left), KVADDR, &left_p, sizeof(void *), "rb_node rb_left", FAULT_ON_ERROR); @@ -4157,40 +4170,32 @@ rbtree_iteration(right_p, td, right_pos); } -void -dump_struct_members_for_tree(struct tree_data *td, int idx, ulong struct_p) +static void +print_value(char *name, ulong addr, short width, unsigned int radix) { - int i, argc; - uint print_radix; - char *p1; - char *structname, *members; - char *arglist[MAXARGS]; - - if (td->flags & TREE_STRUCT_RADIX_10) - print_radix = 10; - else if (td->flags & TREE_STRUCT_RADIX_16) - print_radix = 16; - else - print_radix = 0; - - structname = GETBUF(strlen(td->structname[idx])+1); - members = GETBUF(strlen(td->structname[idx])+1); - - strcpy(structname, td->structname[idx]); - p1 = strstr(structname, ".") + 1; + union { uint64_t v64; uint32_t v32; + uint16_t v16; uint8_t v8; + } v; + char fmt[BUFSIZE]; + + if (!readmem(addr, KVADDR, &v, width, + "structure value", RETURN_ON_ERROR | QUIET)) { + error(INFO, "cannot access field: %s at %lx\n", name, addr); + return; + } + snprintf(fmt, BUFSIZE, " %%s = %s%%%s%s\n", + (radix == 16 ? "0x" : ""), + (width == 8 ? "l" : ""), + (radix == 16 ? "x" : "u" ) + ); - strcpy(members, p1); - replace_string(members, ",", ' '); - argc = parse_line(members, arglist); - for (i = 0; i <argc; i++) { - *p1 = NULLCHAR; - strcat(structname, arglist[i]); - dump_struct_member(structname, struct_p, print_radix); + switch (width) { + case 1: fprintf(fp, fmt, name, v.v8); break; + case 2: fprintf(fp, fmt, name, v.v16); break; + case 4: fprintf(fp, fmt, name, v.v32); break; + case 8: fprintf(fp, fmt, name, v.v64); break; } - - FREEBUF(structname); - FREEBUF(members); } /* --- crash-7.1.5.orig/defs.h 2016-04-27 21:46:50.000000000 +0300 +++ crash-7.1.5/defs.h 2016-07-25 14:43:32.224688448 +0300 @@ -2376,6 +2376,15 @@ #define union_name struct_name +enum fast_or_fancy { FAST, FANCY }; +struct struct_req_entry { + char *arg, *name; + char **member, *width; + short *offset; + unsigned char count; + enum fast_or_fancy ff; +}; + struct list_data { /* generic structure used by do_list() to walk */ ulong flags; /* through linked lists in the kernel */ ulong start; @@ -2383,13 +2392,14 @@ long list_head_offset; ulong end; ulong searchfor; - char **structname; - int structname_args; char *header; ulong *list_ptr; int (*callback_func)(void *, void *); void *callback_data; long struct_list_offset; + int count; + int entries; + struct struct_req_entry *e[8]; }; #define LIST_OFFSET_ENTERED (VERBOSE << 1) #define LIST_START_ENTERED (VERBOSE << 2) @@ -2408,9 +2418,9 @@ ulong flags; ulong start; long node_member_offset; - char **structname; - int structname_args; int count; + int entries; + struct struct_req_entry *e[8]; }; #define TREE_ROOT_OFFSET_ENTERED (VERBOSE << 1) --- crash-7.1.5.orig/help.c 2016-04-27 21:46:50.000000000 +0300 +++ crash-7.1.5/help.c 2016-07-26 14:02:42.192044349 +0300 @@ -5583,6 +5583,9 @@ " or \"struct.member[index]\"; embedded member specifications may", " extend beyond one level deep by expressing the struct argument as", " \"struct.member.member.member...\".", +" -S struct Do exactly the same thing as `-s`, but instead of parsing gdb output", +" it reads value from memory, therefore it works much faster for" +" 1-, 2-, 4-, and 8-bytes fields." " -x Override default output format with hexadecimal format.", " -d Override default output format with decimal format.", " -p Display the node's position information, showing the relationship", -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility