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
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to