----- Original Message ----- > Hi Dave, > > I found it useful to be able listing structure's fields which are resided > deeper than the first level: > > crash> list super_block.s_list -s > super_block.s_id,s_dquot.info[1].dqi_dirty_list,s_dquot.dqonoff_mutex.count.counter > -H 0xc0a9c800 > de805c00 > s_id = > "sysfs\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", > s_dquot.info[1].dqi_dirty_list = { > next = 0x0, > prev = 0x0 > }, > s_dquot.dqonoff_mutex.count.counter = 1 > de805800 > s_id = > "rootfs\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", > s_dquot.info[1].dqi_dirty_list = { > next = 0x0, > prev = 0x0 > }, > s_dquot.dqonoff_mutex.count.counter = 1 > > Here is a draft patch which contains corresponding logic. > I will appreciate your comments and suggestions. > > Best regards, > Alexandr Hi Alexandr, This looks quite useful. I haven't looked at the details, but this kind of change modifies an a critical area of usage that I cannot risk breaking. To prevent any kind of possible regression/breakage or other unexpected behavior, would it be possible to call parse_for_member_new() *only* if it is required? In other words, if the commented-out MEMBER_EXISTS() call fails, then you could set a flag to force it to attempt parse_for_member_new(). Otherwise, it could continue to use the older/simpler parse_for_member() function. I'll dig into the patch later, test it out, etc., and it's entirely possible that I'll change my mind, but paranoia forces me to err on the side of caution. Dave > --- crash-7.1.0.orig/tools.c 2015-02-06 21:44:11.000000000 +0300 > +++ crash-7.1.0/tools.c 2015-04-28 14:09:40.764966266 +0300 > @@ -3526,13 +3526,9 @@ > dump_struct(ld->structname[i], > next - ld->list_head_offset, radix); > break; > - case 1: > + default: > dump_struct_members(ld, i, next); > break; > - default: > - error(FATAL, > - "invalid structure reference: %s\n", > - ld->structname[i]); > } > } > } > --- crash-7.1.0.orig/symbols.c 2015-02-06 21:44:11.000000000 +0300 > +++ crash-7.1.0/symbols.c 2015-04-28 13:46:12.760992540 +0300 > @@ -93,6 +93,7 @@ > #define PARSE_FOR_DATA (1) > #define PARSE_FOR_DECLARATION (2) > static void parse_for_member(struct datatype_member *, ulong); > +static void parse_for_member_new(struct datatype_member *, ulong); > static int show_member_offset(FILE *, struct datatype_member *, char *); > > > @@ -5576,17 +5577,19 @@ > FREEBUF(buf); > error(FATAL, "invalid structure name: %s\n", dm->name); > } > +/* > if (!MEMBER_EXISTS(dm->name, dm->member)) { > FREEBUF(buf); > error(FATAL, "invalid structure member name: %s\n", > dm->member); > } > - > +*/ > set_temporary_radix(radix, &restore_radix); > > open_tmpfile(); > print_struct(dm->name, addr); > - parse_for_member(dm, PARSE_FOR_DATA); > +/* parse_for_member(dm, PARSE_FOR_DATA); */ > + parse_for_member_new(dm, PARSE_FOR_DATA); > close_tmpfile(); > > restore_current_radix(restore_radix); > @@ -7251,6 +7254,206 @@ > fprintf(ofp, ")\n"); > } > > +struct struct_elem { > + char field_name[BUFSIZE]; > + char value[BUFSIZE]; > + unsigned char is_array; > + > + > + struct struct_elem *parent; > + struct struct_elem *inner; > + struct struct_elem *next; > + struct struct_elem *prev; > +}; > + > +#define ALLOC_XXX_ELEMENT(xxx, clone_parent, is_array_root) \ > +{ \ > + if (NULL == current) { \ > + return; \ > + } \ > + current->xxx = calloc(1, sizeof(struct struct_elem)); \ > + if (NULL == current->xxx) \ > + error(FATAL, "cannot allocate any more memory!\n"); \ > + if (clone_parent) current->xxx->parent = current->parent; \ > + else current->xxx->parent = current; \ > + current = current->xxx; \ > + current->is_array = is_array_root; \ > +} > + > +#define ALLOC_INNER_ELEMENT ALLOC_XXX_ELEMENT(inner, 0, 0) > +#define ALLOC_NEXT_ELEMENT ALLOC_XXX_ELEMENT(next, 1, 0) > +#define ALLOC_ARRAY_ELEMENT ALLOC_XXX_ELEMENT(inner, 0, 1) > + > +unsigned char is_right_brace(const char *b) { > + unsigned char r = 0; > + for (; *b == ' '; b++); > + if (*b == '}') { > + b++; > + r = 1; > + if (*b == '}') > + b++; > + } > + > + if (*b == ',') > + b++; > + > + if (*b == '\0') > + return r; > + else > + return 0; > +} > + > +struct struct_elem *find_node(struct struct_elem *s, char *n) { > + char *p, *b, *e; > + struct struct_elem *f; > + unsigned i; > + do { > + f = NULL; > + /* [n .. p] - struct member with index*/ > + if (NULL == (p = strstr(n, "."))) > + p = n + strlen(n); > + > + /* [n .. b] - struct member without index*/ > + for (b = n; (b < p) && (*b != '['); b++); > + > + while (s) { > + > + if (0 == memcmp(s->field_name, n, b - n)) { > + f = s; // Keep found node > + s = s->inner; > + if (*b == '[') { > + i = strtol(b + 1, &e, 10); > + if (!(s->is_array && *e == ']'&& (e != b + 1))) > + return NULL; > + > + while (i && s) { > + s = s->next; > + if (s) > + i -= !!s->is_array; > + } > + > + } > + break; > + } > + if (NULL == s) > + return NULL; > + s = s->next; > + if (s && s->is_array) > + break; // That is we encounter the next array item > + } > + if (*p == '.') n = p + 1; else n = p; > + } while (*n); > + > + return f; > +} > + > + > + > +void dump_node(struct struct_elem *p, char *f, unsigned char level, unsigned > char is_array) { > + unsigned int i; > + if (p == NULL) > + return; > + do { > +#define PUT_INDENTED_STRING(m, ...) { \ > + for (i = 0; i++ < 2 * (m * is_array + level); printf(" ")); \ > + printf(__VA_ARGS__); } > + > + if (p->inner) { > + PUT_INDENTED_STRING(1, "%s = %s\n", f ? f : p->field_name, > p->inner->is_array ? "{{" : "{"); > + dump_node(p->inner, NULL, is_array + level + 1, > p->inner->is_array); > + PUT_INDENTED_STRING(1, "%s%s\n", p->inner->is_array ? "}}" : > "}", p->next ? "," : ""); > + } else { > + PUT_INDENTED_STRING(1, "%s = %s%s\n", f ? f : p->field_name, > p->value, p->next && !p->next->is_array ? "," : ""); > + } > + if (level) { > + p = p->next; > + if (p && p->is_array) > + PUT_INDENTED_STRING(0, "}, {\n"); > + } > + } while (p && level); > +} > + > +void free_structure(struct struct_elem *p) { > + if (p == NULL) > + return; > + free_structure(p->inner); > + free_structure(p->next); > + free(p); > +} > + > +static void > +parse_for_member_new(struct datatype_member *dm, ulong flag) > +{ > + struct struct_elem *current = NULL, *root = NULL; > + > + char buf[BUFSIZE]; > + char *p, *p1; > + unsigned int len; > + unsigned char trailing_comma; > + > + rewind(pc->tmpfile); > + > + while (fgets(buf, BUFSIZE, pc->tmpfile)) { > + len = strlen(buf) - 1; > + for (; buf[len] <= ' '; buf[len--] = '\0'); > + if ((trailing_comma = (buf[len] == ','))) > + buf[len--] = '\0'; > + > + if (is_right_brace(buf)) { > + current = current->parent; > + if (trailing_comma) > + ALLOC_NEXT_ELEMENT; > + continue; > + } > + > + for (p1 = buf; *p1 == ' '; p1++); > + > + if ( > + (p = strstr(buf, " = ")) && > + ((*(p + 3) != '{') || (*(p + 3) == '{' && buf[len] == '}')) > + ) /* next = 0x0 or files = {0x0, 0x0} */ > + { > + strncpy(current->field_name, p1, p - p1); > + strcpy(current->value, p + 3); > + if (trailing_comma) > + ALLOC_NEXT_ELEMENT; > + } > + else > + if (p = strstr(buf, " = {")) { > + strncpy(current->field_name, p1, p - p1); > + if (*(p + 4) == '\0') { > + ALLOC_INNER_ELEMENT; > + } else if (*(p + 4) == '{' && *(p + 5) == '\0') { > + ALLOC_ARRAY_ELEMENT; > + } > + } > + else > + if (strstr(buf, "}, {")) { /* Next array element */ > + ALLOC_NEXT_ELEMENT; > + current->is_array = 1; > + } > + else > + if (buf == (p = strstr(buf, "struct "))) { // The least likely > branch > + /* Our parent */ > + current = calloc(1, sizeof(struct struct_elem)); > + p += 7; /* strlen "struct " */ > + p1 = strstr(buf, " {"); > + strncpy(current->field_name, p, p1 - p); > + root = current; > + ALLOC_INNER_ELEMENT; > + } > + } > + > + current = find_node(root->inner, dm->member); > + if (NULL == current) > + error(FATAL, "invalid structure reference: %s\n", dm->member); > + > + dump_node(current, dm->member, 0, 0); > + free_structure(root); > + > + return; > +} > + > /* > * When a request is made to print just a member of a structure or union, > * the whole datatype is dumped to a temporary file, and this routine > > -- > Crash-utility mailing list > Crash-utility@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/crash-utility > -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility