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",