[Crash-utility] [PATCH 1/1] CLI list command, print deep structure members

Alexandr Terekhov Alexandr_Terekhov at epam.com
Tue Apr 28 12:39:34 UTC 2015


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




More information about the Crash-utility mailing list