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(a)redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility