[Crash-utility] [PATCH 1/1] CLI list command, print deep structure members
Dave Anderson
anderson at redhat.com
Tue Apr 28 13:16:21 UTC 2015
----- 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 at redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility
>
More information about the Crash-utility
mailing list