summaryrefslogtreecommitdiff
path: root/sys/ddb/parse_structinfo.awk
diff options
context:
space:
mode:
Diffstat (limited to 'sys/ddb/parse_structinfo.awk')
-rw-r--r--sys/ddb/parse_structinfo.awk318
1 files changed, 318 insertions, 0 deletions
diff --git a/sys/ddb/parse_structinfo.awk b/sys/ddb/parse_structinfo.awk
new file mode 100644
index 00000000000..b4e03b20252
--- /dev/null
+++ b/sys/ddb/parse_structinfo.awk
@@ -0,0 +1,318 @@
+# $OpenBSD: parse_structinfo.awk,v 1.1 2009/08/09 23:04:49 miod Exp $
+#
+# Copyright (c) 2009 Miodrag Vallat.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+# This ugly script parses the output of objdump -g in order to extract
+# structure layout information, to be used by ddb.
+#
+# The output of this script is the following static data:
+# - for each struct:
+# - its name
+# - its size (individual element size if an array)
+# - the number of elements in the array (1 if not)
+# - its first and last field indexes
+# - for each field:
+# - its name
+# - its offset and size
+# - the index of the struct it is member of
+# This allows fast struct -> field information retrieval.
+#
+# To retrieve information from a field size or offset, we also output
+# the following reverse arrays:
+# - for each offset, in ascending order, a variable length list of field
+# indexes.
+# - for each size, in ascending order, a variable length list of field
+# indexes.
+#
+# The compromise here is that I want to minimize linear searches. Memory
+# use is considered secondary, hence the back `pointer' to the struct in the
+# fields array.
+#
+# No attempt is made to share name pointers when multiple fields share
+# the same name. Rewriting this script in perl, or any other language
+# with hash data structures, would be a good time to add this.
+
+BEGIN {
+ depth = 0;
+ ignore = 0;
+ scnt = 0; # current struct count
+ sidx = -1; # current struct index
+ # field index #0 is used as a sentinel.
+ fcnt = 1; # current field count
+ fidx = 0; # current field index
+ ocnt = 0; # current offset count
+ zcnt = 0; # current size count
+
+}
+/^struct / {
+ depth = 1;
+ sidx = scnt;
+ sname[sidx] = $2;
+ ssize[sidx] = $6;
+ sfieldmin[sidx] = fcnt;
+ scnt++;
+ #printf("struct %d %s (size %d)\n", sidx, $2, $6);
+ next;
+}
+/^};/ {
+ if (depth != 0) {
+ depth = 0;
+ if (fcnt == sfieldmin[sidx]) # empty struct, ignore it
+ scnt--;
+ else
+ sfieldmax[sidx] = fidx;
+ } else
+ ignore--;
+ next;
+}
+/{.*}/ {
+ # single line enum
+ next;
+}
+/{/ {
+ # subcomponent
+ if (depth != 0) {
+ depth++;
+ } else {
+ ignore++;
+ }
+ next;
+}
+/}/ {
+ if (ignore != 0) {
+ ignore--;
+ next;
+ } else {
+ depth--;
+ }
+ if (depth != 1)
+ next;
+ # FALLTHROUGH
+}
+/bitsize/ {
+ if (ignore != 0)
+ next;
+ if (depth != 1)
+ next;
+
+ # Bitfields are a PITA... From a ddb point of view, we can't really
+ # access storage units smaller than a byte.
+ # So we'll report all bitfields as having size 0, and the
+ # rounded down byte position where they start.
+ cursize = int($(NF - 3));
+ curoffs = int($(NF - 1) / 8);
+ if ((cursize % 8) != 0)
+ cursize = 0;
+ else
+ cursize /= 8;
+
+ # try and gather the field name.
+ field = $(NF - 6);
+ if (field == "};") {
+ # anonymous union. discard it.
+ next;
+ }
+ if (field == "*/);") {
+ field = $(NF - 9); # function pointer
+ # remove enclosing braces
+ field = substr(field, 2, length(field) - 2);
+ }
+ colon = index(field, ":");
+ if (colon != 0)
+ field = substr(field, 1, colon - 1);
+ else if (substr(field, length(field), 1) == ";")
+ field = substr(field, 1, length(field) - 1);
+
+ while (index(field, "*") == 1)
+ field = substr(field, 2);
+
+ # This could be an array. If it is, we need to trim the field
+ # name and update its size to a single member size.
+ obracket = index(field, "[");
+ cbracket = index(field, "]");
+ if (obracket != 0) {
+ obracket++;
+ nitems = substr(field, obracket, cbracket - obracket);
+ field = substr(field, 1, obracket - 2);
+ cursize /= nitems;
+ } else
+ nitems = 1;
+
+ fidx = fcnt;
+ fname[fidx] = field;
+ foffs[fidx] = curoffs;
+ fsize[fidx] = cursize;
+ fitems[fidx] = nitems;
+ fstruct[fidx] = sidx;
+ fcnt++;
+ #printf(" %s at %d len %d\n", field, curoffs, cursize);
+
+ # Remember size and offset if not found yet
+
+ for (i = 0; i < ocnt; i++)
+ if (offs[i] == curoffs)
+ break;
+ if (i == ocnt) {
+ # keep array sorted
+ for (i = 0; i < ocnt; i++)
+ if (offs[i] > curoffs)
+ break;
+ if (i < ocnt) {
+ for (j = ocnt + 1; j > i; j--)
+ offs[j] = offs[j - 1];
+ }
+ offs[i] = curoffs;
+ ocnt++;
+ }
+
+ for (i = 0; i < zcnt; i++)
+ if (sizes[i] == cursize)
+ break;
+ if (i == zcnt) {
+ # keep array sorted
+ for (i = 0; i < zcnt; i++)
+ if (sizes[i] > cursize)
+ break;
+ if (i < zcnt) {
+ for (j = zcnt + 1; j > i; j--)
+ sizes[j] = sizes[j - 1];
+ }
+ sizes[i] = cursize;
+ zcnt++;
+ }
+}
+END {
+ printf("/*\n");
+ printf(" * THIS IS A GENERATED FILE. DO NOT EDIT!\n");
+ printf(" */\n\n");
+
+ printf("#include <sys/param.h>\n");
+ printf("#include <sys/types.h>\n");
+ printf("\n");
+
+ # structure definitions
+
+ printf("struct ddb_struct_info {\n");
+ printf("\tconst char *name;\n");
+ printf("\tsize_t size;\n");
+ printf("\tuint fmin, fmax;\n");
+ printf("};\n");
+
+ printf("struct ddb_field_info {\n");
+ printf("\tconst char *name;\n");
+ printf("\tuint sidx;\n");
+ printf("\tsize_t offs;\n");
+ printf("\tsize_t size;\n");
+ printf("\tuint nitems;\n");
+ printf("};\n");
+
+ printf("struct ddb_field_offsets {\n");
+ printf("\tsize_t offs;\n");
+ printf("\tconst uint *list;\n");
+ printf("};\n");
+
+ printf("struct ddb_field_sizes {\n");
+ printf("\tsize_t size;\n");
+ printf("\tconst uint *list;\n");
+ printf("};\n");
+
+ # forward arrays
+
+ printf("#define NSTRUCT %d\n", scnt);
+ printf("static const struct ddb_struct_info ddb_struct_info[NSTRUCT] = {\n");
+ for (i = 0; i < scnt; i++) {
+ printf("\t{ \"%s\", %d, %d, %d },\n",
+ sname[i], ssize[i], sfieldmin[i], sfieldmax[i]);
+ }
+ printf("};\n\n");
+
+ printf("#define NFIELD %d\n", fcnt);
+ printf("static const struct ddb_field_info ddb_field_info[NFIELD] = {\n");
+ printf("\t{ NULL, 0, 0, 0 },\n");
+ for (i = 1; i < fcnt; i++) {
+ printf("\t{ \"%s\", %d, %d, %d, %d },\n",
+ fname[i], fstruct[i], foffs[i], fsize[i], fitems[i]);
+ }
+ printf("};\n\n");
+
+ # reverse arrays
+
+ printf("static const uint ddb_fields_by_offset[] = {\n");
+ w = 0;
+ for (i = 0; i < ocnt; i++) {
+ cmp = offs[i];
+ ohead[i] = w;
+ for (f = 1; f < fcnt; f++)
+ if (foffs[f] == cmp) {
+ if ((w % 10) == 0)
+ printf("\t");
+ printf("%d, ", f);
+ w++;
+ if ((w % 10) == 0)
+ printf("\n");
+ }
+ if ((w % 10) == 0)
+ printf("\t");
+ printf("0, ");
+ w++;
+ if ((w % 10) == 0)
+ printf("\n");
+ }
+ if ((w % 10) != 0)
+ printf("\n");
+ printf("};\n\n");
+
+ printf("#define NOFFS %d\n", ocnt);
+ printf("static const struct ddb_field_offsets ddb_field_offsets[NOFFS] = {\n");
+ for (i = 0; i < ocnt; i++) {
+ printf("\t{ %d, ddb_fields_by_offset + %d },\n",
+ offs[i], ohead[i]);
+ }
+ printf("};\n\n");
+
+ printf("static const uint ddb_fields_by_size[] = {\n");
+ w = 0;
+ for (i = 0; i < zcnt; i++) {
+ cmp = sizes[i];
+ zhead[i] = w;
+ for (f = 1; f < fcnt; f++)
+ if (fsize[f] == cmp) {
+ if ((w % 10) == 0)
+ printf("\t");
+ printf("%d, ", f);
+ w++;
+ if ((w % 10) == 0)
+ printf("\n");
+ }
+ if ((w % 10) == 0)
+ printf("\t");
+ printf("0, ");
+ w++;
+ if ((w % 10) == 0)
+ printf("\n");
+ }
+ if ((w % 10) != 0)
+ printf("\n");
+ printf("};\n\n");
+
+ printf("#define NSIZES %d\n", zcnt);
+ printf("static const struct ddb_field_sizes ddb_field_sizes[NSIZES] = {\n");
+ for (i = 0; i < zcnt; i++) {
+ printf("\t{ %d, ddb_fields_by_size + %d },\n",
+ sizes[i], zhead[i]);
+ }
+ printf("};\n");
+}