Hello Dave,
I've rewritten the mentioned logic, now crash communicates with gdb by means of
gdb_interface.
--- gdb-7.6.orig/gdb/symtab.c 2016-03-23 11:43:09.000000000 +0300
+++ gdb-7.6/gdb/symtab.c 2016-04-13 09:50:53.597120297 +0300
@@ -5140,6 +5140,9 @@
static void gdb_set_crash_block(struct gnu_request *);
void gdb_command_funnel(struct gnu_request *);
+static long lookup_struct_contents(struct gnu_request *);
+static void iterate_datatypes (struct gnu_request *);
+
struct objfile *gdb_kernel_objfile = { 0 };
static ulong gdb_merge_flags = 0;
@@ -5242,6 +5245,14 @@
req->flags |= GNU_COMMAND_FAILED;
break;
+ case GNU_LOOKUP_STRUCT_CONTENTS:
+ req->value = lookup_struct_contents(req);
+ break;
+
+ case GNU_GET_NEXT_DATATYPE:
+ iterate_datatypes(req);
+ break;
+
default:
req->flags |= GNU_COMMAND_FAILED;
break;
@@ -5779,4 +5790,144 @@
else
return NULL;
}
+
+static long
+lookup_struct_contents(struct gnu_request *req)
+{
+ int i;
+ long r;
+ struct field *f;
+ struct main_type *m;
+ const char *n;
+ struct main_type *top_m = (struct main_type *)req->addr;
+#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) || defined(GDB_7_0)
+ char *type_name = req->typename;
+#else
+ char *type_name = req->type_name;
+#endif
+
+ if (!top_m || !type_name)
+ return 1;
+
+ for (i = 0; i < top_m->nfields; i++)
+ {
+ f = top_m->flds_bnds.fields + i;
+ if (!f->type)
+ continue;
+ m = f->type->main_type;
+
+ // If the field is an array, check the target type -
+ // it might be structure, or might not be.
+ // - struct request_sock *syn_table[0];
+ // here m->target_type->main_type->code is expected
+ // to be TYPE_CODE_PTR
+ // - struct list_head vec[TVN_SIZE];
+ // here m->target_type->main_type->code should be
+ // TYPE_CODE_STRUCT
+ if (m->code == TYPE_CODE_ARRAY && m->target_type)
+ m = m->target_type->main_type;
+
+ /* Here is a recursion.
+ * If we have struct variable (not pointer),
+ * scan this inner structure
+ */
+ if (m->code == TYPE_CODE_STRUCT) {
+ req->addr = (ulong)m;
+ r = lookup_struct_contents(req);
+ req->addr = (ulong)top_m;
+ if (r)
+ return 1;
+ }
+
+ if (m->code == TYPE_CODE_PTR && m->target_type)
+ m = m->target_type->main_type;
+ if (m->name)
+ n = m->name;
+ else if (m->tag_name)
+ n = m->tag_name;
+ else
+ continue;
+
+ if (strstr(n, type_name))
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+iterate_datatypes (struct gnu_request *req)
+{
+ static struct block_iterator bi; // Keeping this static will simplify code
+ struct block *b;
+ int do_return = 0;
+ struct {
+ char fi, i;
+ struct symtab *st;
+ struct symbol *sym;
+ struct objfile *o;
+ } *gi = (void *)req->addr2; /*Global iterator */
+
+ if (gi->fi)
+ return;
+
+ if (gi->o == NULL)
+ {
+ gi->o = current_program_space->objfiles;
+ gi->st = NULL;
+ do_return = 1; // The initial case - we don't need to make next step.
+ }
+
+ for (; gi->o; gi->o = gi->o->next, gi->st = NULL)
+ {
+ if (gi->st == NULL)
+ {
+ // Symtab `st` is nullified for every objfile
+ if (gi->o->sf)
+ gi->o->sf->qf->expand_all_symtabs(gi->o);
+ gi->st = gi->o->symtabs;
+ gi->sym = NULL;
+ }
+
+ for (; gi->st; gi->st = gi->st->next, gi->i = -1)
+ {
+ if (!gi->st->primary)
+ continue;
+
+ if (gi->i == -1)
+ {
+ gi->i = GLOBAL_BLOCK;
+ gi->sym = NULL;
+ }
+ for (; gi->i <= STATIC_BLOCK; gi->i++, gi->sym = NULL)
+ {
+ if (!gi->sym)
+ {
+ b = BLOCKVECTOR_BLOCK(BLOCKVECTOR(gi->st), gi->i);
+ gi->sym = block_iterator_first(b, &bi);
+ }
+ for (; gi->sym; gi->sym = block_iterator_next(&bi))
+ {
+ QUIT;
+
+ if (SYMBOL_CLASS (gi->sym) != LOC_TYPEDEF)
+ continue;
+
+ // Iteration 1 (do_return == 0): initialization
+ // Iteration 2 (do_return == 1): iterate symbol
+ if (do_return++ == 0)
+ continue;
+
+ // Yield the current symbol and its size
+ req->addr = (ulong)(gi->sym->type->main_type);
+ req->name = (char *)(gi->sym->ginfo.name);
+ req->length = gi->sym->type->length;
+
+ return;
+ }
+ }
+ }
+ }
+ gi->fi = 1;
+}
#endif