Hi Dave, thank you for the comments. Here is the fixed patch. Best, Alexandr --- crash-7.1.0.orig/symbols.c 2015-05-13 11:39:12.401474372 +0300 +++ crash-7.1.0/symbols.c 2015-05-13 13:57:08.193598469 +0300 @@ -94,6 +94,11 @@ static int dereference_pointer(ulong, st #define PARSE_FOR_DECLARATION (2) static void parse_for_member(struct datatype_member *, ulong); static int show_member_offset(FILE *, struct datatype_member *, char *); +struct struct_elem; +static void free_structure(struct struct_elem *); +static unsigned char is_right_brace(const char *); +static struct struct_elem *find_node(struct struct_elem *, char *); +static void dump_node(struct struct_elem *, char *, unsigned char, unsigned char); /* @@ -5576,17 +5581,18 @@ dump_struct_member(char *s, ulong addr, 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); + + if (MEMBER_EXISTS(dm->name, dm->member)) { + parse_for_member(dm, PARSE_FOR_DATA); + } else { + parse_for_member_new(dm, PARSE_FOR_DATA); + } + close_tmpfile(); restore_current_radix(restore_radix); @@ -6026,8 +6032,7 @@ cmd_datatype_common(ulong flags) if ((count_chars(args[optind], ',')+1) > MAXARGS) error(FATAL, "too many members in comma-separated list!\n"); - if ((count_chars(args[optind], '.') > 1) || - (LASTCHAR(args[optind]) == ',') || + if ((LASTCHAR(args[optind]) == ',') || (LASTCHAR(args[optind]) == '.')) error(FATAL, "invalid format: %s\n", args[optind]); @@ -6219,6 +6224,10 @@ do_datatype_addr(struct datatype_member i = 0; do { if (argc_members) { + /* This call works fine with fields + * of the second, third, ... levels. + * There is no need to fix it + */ if (!member_to_datatype(memberlist[i], dm, ANON_MEMBER_QUERY)) error(FATAL, "invalid data structure reference: %s.%s\n", @@ -6250,7 +6259,12 @@ do_datatype_addr(struct datatype_member if (dm->member) { if (!((flags & DEREF_POINTERS) && dereference_pointer(addr, dm, flags))) - parse_for_member(dm, PARSE_FOR_DATA); + { + if (count_chars(dm->member, '.')) + parse_for_member_new(dm, PARSE_FOR_DATA); + else + parse_for_member(dm, PARSE_FOR_DATA); + } close_tmpfile(); } @@ -6275,6 +6289,10 @@ do_datatype_declaration(struct datatype_ if (CRASHDEBUG(1)) dump_datatype_member(fp, dm); + if (dm->member && count_chars(dm->member, '.')) + error(FATAL, "invalid data structure reference: %s.%s\n", + dm->name, dm->member); + open_tmpfile(); whatis_datatype(dm->name, flags, pc->tmpfile); rewind(pc->tmpfile); @@ -7383,6 +7401,277 @@ next_item: } } +struct struct_elem { + char field_name[BUFSIZE]; + unsigned char field_len; + char value[BUFSIZE]; + unsigned char is_array_root:1; + + struct struct_elem *parent; + struct struct_elem *inner; + struct struct_elem *next; + struct struct_elem *prev; +}; + +#define ALLOC_XXX_ELEMENT(xxx, clone_parent) \ +{ \ + if (NULL == current) { \ + error(FATAL, "Internal error while parsing structure %s\n", dm->name); \ + } \ + current->xxx = (struct struct_elem *)GETBUF(sizeof(struct struct_elem)); \ + if (clone_parent) current->xxx->parent = current->parent; \ + else current->xxx->parent = current; \ + current = current->xxx; \ +} + +#define ALLOC_INNER_ELEMENT { ALLOC_XXX_ELEMENT(inner, 0) } +#define ALLOC_NEXT_ELEMENT { ALLOC_XXX_ELEMENT(next, 1) } + +static void +free_structure(struct struct_elem *p) +{ + if (p == NULL) + return; + free_structure(p->inner); + free_structure(p->next); + FREEBUF(p); +} + +static unsigned char +is_right_brace(const char *b) +{ + unsigned char r = 0; + for (; *b == ' '; b++); + if (*b == '}') { + b++; + r = 1; + if (*b == '}') { + r = 2; + b++; + } + } + + if (*b == ',') + b++; + + if (*b == '\0') + return r; + else + return 0; +} + +static struct struct_elem * +find_node(struct struct_elem *s, char *n) +{ + char *p, *b, *e; + struct struct_elem *t = s; + unsigned i; + + if (('\0' == *n) || (NULL == s)) + return s; + + /* [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++); + + /* s - is the current level of items [s, s->next, ..., s->...->next] */ + for (; s; s = s->next) { + if (*s->field_name == '\0') + continue; + + /* `field_name` doesn't match */ + if (((b - n) != s->field_len) || memcmp(s->field_name, n, b - n)) + continue; + + if (*b == '[') { /* Array */ + i = strtol(b + 1, &e, 10); + /* Check if the current node is array and + * we've parsed index more or less correctly + */ + if (!(s->is_array_root && *e == ']' && (e != b + 1))) + return NULL; + + /* Look for the i-th element */ + for (s = s->inner; s && i; s = s->next, i--); + if (i || (NULL == s)) + return NULL; + } + + /* Ok. We've found node, it's - the last member + * in our search string, let's return it. + */ + if ('\0' == *p) + return s; + else + return find_node(s->inner, p + 1); + } + + // We haven't found any field. + // Might happen, we've encountered anonymous structure + // of union. Lets try every record without `field_name` + s = t; + t = NULL; + for (; s; s = s->next) { + if (*s->field_name) + continue; + t = find_node(s->inner, n); + if (t) + break; + } + + return t; +} + +static 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 + 2 * (m * is_array + level); fprintf(pc->saved_fp, " ")); \ + fprintf(pc->saved_fp, __VA_ARGS__); } + + if (p->inner) { + if (*p->field_name) { + PUT_INDENTED_STRING(1, "%s = %s\n", f ? f : p->field_name, p->inner->is_array_root ? "{{" : "{"); + } else { + if (f) /* For union */ + PUT_INDENTED_STRING(1, "%s = ", f); + PUT_INDENTED_STRING(1, "%s\n", p->inner->is_array_root ? "{{" : "{"); + } + dump_node(p->inner, NULL, is_array + level + 1, p->inner->is_array_root); + PUT_INDENTED_STRING(1, "%s%s\n", p->inner->is_array_root ? "}}" : "}", (p->next && !p->next->is_array_root) ? "," : ""); + } else { + PUT_INDENTED_STRING(1, "%s = %s%s", f ? f : p->field_name, p->value, p->next ? ",\n" : "\n"); + } + if (level) { + p = p->next; + if (p && p->is_array_root) + PUT_INDENTED_STRING(0, "}, {\n"); + } + } while (p && level); +} + +void +parse_for_member_new(struct datatype_member *dm, + ulong __attribute__ ((unused)) flag) +{ + struct struct_elem *i, *current = NULL, *root = NULL; + + char buf[BUFSIZE]; + char *p, *p1; + char *s_e; // structure_element + unsigned int len; + unsigned char trailing_comma, braces, found = 0; + + rewind(pc->tmpfile); + + root = (struct struct_elem *)GETBUF(sizeof(struct struct_elem)); + current = root; + ALLOC_INNER_ELEMENT; + + 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 ((braces = is_right_brace(buf))) { + for (; braces && current; braces--) + current = current->parent; + + if ((current->parent == root) || trailing_comma) + ALLOC_NEXT_ELEMENT; + continue; + } + + for (p1 = buf; *p1 == ' '; p1++); + + if (NULL != (p = strstr(buf, " = "))) { + s_e = p + 3; + } else { + s_e = p1; + } + + /* + * After that we have pointers: + * foobar = bazzz + * -----^ ^ ^ + * | ------| | + * | | | + * p1 p s_e + * + * OR + * + * { + * ^ + * | + * --------- + * | | + * p1 s_e + * + * p == NULL + * + * + * p1 - the first non-whitespace symbol in line + * p - pointer to line ' = '. + * If not NULL, there is identifier + * s_e - element of structure (brace / double brace / array separator / scalar) + * + */ + + if (current && p) strncpy(current->field_name, p1, p - p1); + current->field_len = p - p1; + + if ( p && (*s_e != '{' || (*s_e == '{' && buf[len] == '}') )) { + /* Scalar or one-line array + * next = 0x0 + * or + * files = {0x0, 0x0} + */ + strcpy(current->value, s_e); + if (trailing_comma) ALLOC_NEXT_ELEMENT; + } + else if ( *s_e == '{' ) { + ALLOC_INNER_ELEMENT; + if (*(s_e + 1) == '{') { + current->parent->is_array_root = 1; + ALLOC_INNER_ELEMENT; + } + } + else if (strstr(s_e, "}, {")) { + /* Next array element */ + current = current->parent; + ALLOC_NEXT_ELEMENT; + ALLOC_INNER_ELEMENT; + } + else if (buf == (p = strstr(buf, "struct "))) { + p += 7; /* strlen "struct " */ + p1 = strstr(buf, " {"); + strncpy(current->field_name, p, p1 - p); + ALLOC_INNER_ELEMENT; + } + } + + for (i = root->inner; i; i = i->next) { + if ((current = find_node(i->inner, dm->member))) { + dump_node(current, dm->member, 0, 0); + found = 1; + break; + } + } + + free_structure(root); + + if (!found) + error(WARNING, "invalid structure reference: %s\n", dm->member); +} + /* * Dig out a member name from a formatted gdb structure declaration dump, * and print its offset from the named structure passed in. --- crash-7.1.0.orig/defs.h 2015-05-13 11:39:12.405474372 +0300 +++ crash-7.1.0/defs.h 2015-05-13 13:32:43.809576510 +0300 @@ -4641,6 +4641,7 @@ void dump_trace(void **); int enumerator_value(char *, long *); int dump_enumerator_list(char *); struct load_module *init_module_function(ulong); +void parse_for_member_new(struct datatype_member *, ulong); /* * memory.c --- crash-7.1.0.orig/task.c 2015-05-13 11:39:12.409474373 +0300 +++ crash-7.1.0/task.c 2015-05-13 13:32:43.809576510 +0300 @@ -107,6 +107,7 @@ static int sort_by_last_run(const void * static void sort_context_array_by_last_run(void); static void show_ps_summary(ulong); static void irqstacks_init(void); +static void parse_task_thread(int argcnt, char *arglist[], struct task_context *); /* * Figure out how much space will be required to hold the task context @@ -2746,13 +2747,9 @@ task_struct_member(struct task_context * int argcnt; char *arglist[MAXARGS]; char *refcopy; - char buf[BUFSIZE]; - char lookfor1[BUFSIZE]; - char lookfor2[BUFSIZE]; - char lookfor3[BUFSIZE]; - int header_printed; - - header_printed = FALSE; + unsigned char call_new_parser = 0; + struct datatype_member dm; + char *member = GETBUF(BUFSIZE); if ((count_chars(ref->str, ',')+1) > MAXARGS) { error(INFO, @@ -2767,14 +2764,39 @@ task_struct_member(struct task_context * argcnt = parse_line(refcopy, arglist); for (i = 0; i < argcnt; i++) if (!MEMBER_EXISTS("task_struct", arglist[i]) && - !MEMBER_EXISTS("thread_info", arglist[i])) - error(INFO, "%s: not a task_struct or thread_info member\n", - arglist[i]); - + !MEMBER_EXISTS("thread_info", arglist[i])) { + if (count_chars(arglist[i], '.') || count_chars(arglist[i], '[')) + call_new_parser = 1; + else + error(INFO, "%s: not a task_struct or " + "thread_info member\n", arglist[i]); + } open_tmpfile(); dump_struct("task_struct", tc->task, radix); if (tt->flags & THREAD_INFO) dump_struct("thread_info", tc->thread_info, radix); + if (call_new_parser) { + for (i = 0; i < argcnt; i++) { + dm.member = arglist[i]; + parse_for_member_new(&dm, 0); + } + } else { + parse_task_thread(argcnt, arglist, tc); + } + close_tmpfile(); + + FREEBUF(member); + +} + +static void parse_task_thread(int argcnt, char *arglist[], struct task_context *tc) { + char buf[BUFSIZE]; + char lookfor1[BUFSIZE]; + char lookfor2[BUFSIZE]; + char lookfor3[BUFSIZE]; + int header_printed = FALSE; + int i; + rewind(pc->tmpfile); BZERO(lookfor1, BUFSIZE); @@ -2825,7 +2847,6 @@ task_struct_member(struct task_context * } } } - close_tmpfile(); } static char *ps_exclusive = --- crash-7.1.0.orig/tools.c 2015-05-13 11:39:12.409474373 +0300 +++ crash-7.1.0/tools.c 2015-05-13 13:32:43.813576510 +0300 @@ -3526,13 +3526,9 @@ do_list(struct list_data *ld) 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-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility