--- crash-7.1.4.orig/defs.h 2015-12-16 18:59:36.000000000 +0300 +++ crash-7.1.4/defs.h 2016-04-12 15:39:58.149121279 +0300 @@ -4116,25 +4116,27 @@ /* * GNU commands */ -#define GNU_DATATYPE_INIT (1) -#define GNU_DISASSEMBLE (2) -#define GNU_GET_LINE_NUMBER (3) -#define GNU_PASS_THROUGH (4) -#define GNU_GET_DATATYPE (5) -#define GNU_COMMAND_EXISTS (6) -#define GNU_STACK_TRACE (7) -#define GNU_ALPHA_FRAME_OFFSET (8) -#define GNU_FUNCTION_NUMARGS (9) -#define GNU_RESOLVE_TEXT_ADDR (10) -#define GNU_ADD_SYMBOL_FILE (11) -#define GNU_DELETE_SYMBOL_FILE (12) -#define GNU_VERSION (13) -#define GNU_PATCH_SYMBOL_VALUES (14) -#define GNU_GET_SYMBOL_TYPE (15) -#define GNU_USER_PRINT_OPTION (16) -#define GNU_SET_CRASH_BLOCK (17) -#define GNU_GET_FUNCTION_RANGE (18) -#define GNU_DEBUG_COMMAND (100) +#define GNU_DATATYPE_INIT (1) +#define GNU_DISASSEMBLE (2) +#define GNU_GET_LINE_NUMBER (3) +#define GNU_PASS_THROUGH (4) +#define GNU_GET_DATATYPE (5) +#define GNU_COMMAND_EXISTS (6) +#define GNU_STACK_TRACE (7) +#define GNU_ALPHA_FRAME_OFFSET (8) +#define GNU_FUNCTION_NUMARGS (9) +#define GNU_RESOLVE_TEXT_ADDR (10) +#define GNU_ADD_SYMBOL_FILE (11) +#define GNU_DELETE_SYMBOL_FILE (12) +#define GNU_VERSION (13) +#define GNU_PATCH_SYMBOL_VALUES (14) +#define GNU_GET_SYMBOL_TYPE (15) +#define GNU_USER_PRINT_OPTION (16) +#define GNU_SET_CRASH_BLOCK (17) +#define GNU_GET_FUNCTION_RANGE (18) +#define GNU_GET_NEXT_DATATYPE (19) +#define GNU_LOOKUP_STRUCT_CONTENTS (20) +#define GNU_DEBUG_COMMAND (100) /* * GNU flags */ --- crash-7.1.4.orig/symbols.c 2015-12-16 18:59:36.000000000 +0300 +++ crash-7.1.4/symbols.c 2016-04-12 15:38:52.497120294 +0300 @@ -33,6 +33,9 @@ static int compare_syms(const void *, const void *); static int compare_mods(const void *, const void *); static int compare_prios(const void *v1, const void *v2); +static int compare_size_name(const void *, const void *); +static void append_struct_symbol (void *, struct gnu_request *); +static void request_types(int, int, char *); static asection *get_kernel_section(char *); static char * get_section(ulong vaddr, char *buf); static void symbol_dump(ulong, char *); @@ -5976,6 +5979,16 @@ return TRUE; } +static int +compare_size_name(const void *va, const void *vb) { + const struct { char *n; ulong s; } *a = va, *b = vb; + + if (a->s == b->s) + return strcmp(a->n, b->n); + else + return a->s < b->s ? -1 : 1; +} + static void cmd_datatype_common(ulong flags) { @@ -6529,6 +6542,75 @@ fprintf(ofp, "\n"); } +static void +append_struct_symbol (void *pout, struct gnu_request *r) +{ + struct { + int sz, idx; + struct { char *n; int s; } *st; + } *output = pout; + int i, s; + + for (i = 0; i < output->idx; i++) + if (output->st[i].n == r->name) + break; + + if (i < output->idx) // We've already collected this type + return; + + if (output->idx == output->sz) { + s = sizeof(*(output->st)) * output->sz; + output->st = (void *)resizebuf((void *)output->st, s, s * 3); + output->sz *= 3; + } + output->st[output->idx].n = r->name; + output->st[output->idx].s = (int)(r->length); + output->idx++; +} + +static void +request_types(int lowest, int highest, char *type_name) +{ + struct gnu_request request = {0}; + struct { + int sz, idx; + struct { char *n; int s; } *st; + } output = {0, 0, NULL}; + struct { char fi, i; void * p[3]; } iter = { 0 }; + + int i; + + output.st = (void *)GETBUF(16 * sizeof(*(output.st))); + output.sz = 16; + request.addr2 = (ulong)&iter; +#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) || defined(GDB_7_0) + req->typename = type_name; +#else + request.type_name = type_name; +#endif + + while (!iter.fi) { + request.command = GNU_GET_NEXT_DATATYPE; + gdb_interface(&request); + if (!(lowest <= request.length && request.length <= highest)) + continue; + + request.command = GNU_LOOKUP_STRUCT_CONTENTS; + gdb_interface(&request); + if (!request.value) + continue; + + append_struct_symbol(&output, &request); + } + + qsort(output.st, output.idx, sizeof(*output.st), compare_size_name); + + for (i = 0; i < output.idx; i++) + fprintf(fp, "%d\t%s\n", output.st[i].s, output.st[i].n); + + FREEBUF(output.st); +} + /* * This command displays the definition of structures, unions, typedefs or * text/data symbols: @@ -6543,33 +6625,58 @@ * declaration is displayed. * 5. For a kernel symbol name, the output is the same as if the "sym" command * was used. + * 6. If the -r and optional -f are given, then the structures/unions of + * specified size will be searched. */ void cmd_whatis(void) { struct datatype_member datatype_member, *dm; struct syment *sp; - char buf[BUFSIZE]; + + char buf[BUFSIZE], *pl = buf, *ph, *field = NULL; long len; - int c; + int c, lowest, highest; ulong flags; dm = &datatype_member; flags = 0; + lowest = highest = UNUSED; - while ((c = getopt(argcnt, args, "o")) != EOF) { + while ((c = getopt(argcnt, args, "of:r:")) != EOF) { switch(c) { case 'o': flags |= SHOW_OFFSET; break; + case 'f': + field = optarg; + break; + + case 'r': + strncpy(buf, optarg, 15); + if ((ph = strstr(buf, "-")) != NULL) + *(ph++) = '\0'; + + highest = lowest = stol(pl, FAULT_ON_ERROR, NULL); + + if (ph) + highest = stol(ph, FAULT_ON_ERROR, NULL); + + break; + default: argerrs++; break; } } + if (!argerrs && lowest != UNUSED && highest != UNUSED) { + request_types(lowest, highest, field); + return; + } + if (argerrs || !args[optind]) cmd_usage(pc->curcmd, SYNOPSIS); --- crash-7.1.4.orig/help.c 2015-12-16 18:59:36.000000000 +0300 +++ crash-7.1.4/help.c 2016-04-06 11:09:24.896859034 +0300 @@ -3461,9 +3461,9 @@ char *help_whatis[] = { "whatis", "search symbol table for data or type information", -"[struct | union | typedef | symbol] ", +"[[-c] [struct | union | typedef | symbol]] | [[-f field] -r range] ", " This command displays the definition of structures, unions, typedefs or", -" text/data symbols.\n", +" text/data symbols, or fulfil a search of structure with particular size.\n", " struct a structure name. The output is the same as if the \"struct\"", " command was used.", " union a union name. The output is the same as if the \"union\" command", @@ -3473,6 +3473,10 @@ " was used. If the typedef is a primitive datatype, the one-line", " declaration is displayed.", " symbol a kernel symbol. ", +" -f field The field type (or substring of type name) which the structure", +" should contain", +" -r range The range or the exact size of the structure we're looking for.", + "\nEXAMPLES", " Display the definition of a linux_binfmt structure:\n", " %s> whatis linux_binfmt", @@ -3514,7 +3518,29 @@ " Display definition of a kdev_t typedef:\n", " %s> whatis kdev_t", " typedef short unsigned int kdev_t;", -" SIZE: 2 (0x2)", +" SIZE: 2 (0x2)\n", +" Find all structures which have size exactly 192 bytes:\n", +" %s> whatis -r 192", +" 192 apic", +" 192 ata_eh_context", +" 192 cper_sec_proc_generic", +" 192 cpuinfo_x86", +" 192 pebs_record_hsw\n", +" Find all structures which have size from 190 up to 200 bytes and which", +" contain member of type '*list*'\n", +" %s> whatis -r 190-200 -f list", +" 196 kioctx", +" 200 scsi_transport_template", +" The structure `kioctx` really has members of types hlist_node and list_head.", +" However, the last structure is more subtle. It contains field of type", +" list_head within itself.", +" That is:", +" scsi_transport_template` contains member of type `transport_container`,", +" which has member of type attribute_container. The last one, in its turn,", +" contains list_head which has poiners to list_head.", +" This is the exact place where algorithm triggers. It delves into the", +" structure _only_ if the particular member is a structure, not a pointer.", +" If it is a pointer, we only match name of type against the given pattern.", NULL }; -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility