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