sync
[bitrig.git] / sys / ddb / parse_structinfo.awk
blobb4e03b20252b06ce732e5419573a0614da22f09b
1 # $OpenBSD: parse_structinfo.awk,v 1.1 2009/08/09 23:04:49 miod Exp $
3 # Copyright (c) 2009 Miodrag Vallat.
5 # Permission to use, copy, modify, and distribute this software for any
6 # purpose with or without fee is hereby granted, provided that the above
7 # copyright notice and this permission notice appear in all copies.
9 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 # This ugly script parses the output of objdump -g in order to extract
19 # structure layout information, to be used by ddb.
21 # The output of this script is the following static data:
22 # - for each struct:
23 # - its name
24 # - its size (individual element size if an array)
25 # - the number of elements in the array (1 if not)
26 # - its first and last field indexes
27 # - for each field:
28 # - its name
29 # - its offset and size
30 # - the index of the struct it is member of
31 # This allows fast struct -> field information retrieval.
33 # To retrieve information from a field size or offset, we also output
34 # the following reverse arrays:
35 # - for each offset, in ascending order, a variable length list of field
36 # indexes.
37 # - for each size, in ascending order, a variable length list of field
38 # indexes.
40 # The compromise here is that I want to minimize linear searches. Memory
41 # use is considered secondary, hence the back `pointer' to the struct in the
42 # fields array.
44 # No attempt is made to share name pointers when multiple fields share
45 # the same name. Rewriting this script in perl, or any other language
46 # with hash data structures, would be a good time to add this.
48 BEGIN {
49 depth = 0;
50 ignore = 0;
51 scnt = 0; # current struct count
52 sidx = -1; # current struct index
53 # field index #0 is used as a sentinel.
54 fcnt = 1; # current field count
55 fidx = 0; # current field index
56 ocnt = 0; # current offset count
57 zcnt = 0; # current size count
60 /^struct / {
61 depth = 1;
62 sidx = scnt;
63 sname[sidx] = $2;
64 ssize[sidx] = $6;
65 sfieldmin[sidx] = fcnt;
66 scnt++;
67 #printf("struct %d %s (size %d)\n", sidx, $2, $6);
68 next;
70 /^};/ {
71 if (depth != 0) {
72 depth = 0;
73 if (fcnt == sfieldmin[sidx]) # empty struct, ignore it
74 scnt--;
75 else
76 sfieldmax[sidx] = fidx;
77 } else
78 ignore--;
79 next;
81 /{.*}/ {
82 # single line enum
83 next;
85 /{/ {
86 # subcomponent
87 if (depth != 0) {
88 depth++;
89 } else {
90 ignore++;
92 next;
94 /}/ {
95 if (ignore != 0) {
96 ignore--;
97 next;
98 } else {
99 depth--;
101 if (depth != 1)
102 next;
103 # FALLTHROUGH
105 /bitsize/ {
106 if (ignore != 0)
107 next;
108 if (depth != 1)
109 next;
111 # Bitfields are a PITA... From a ddb point of view, we can't really
112 # access storage units smaller than a byte.
113 # So we'll report all bitfields as having size 0, and the
114 # rounded down byte position where they start.
115 cursize = int($(NF - 3));
116 curoffs = int($(NF - 1) / 8);
117 if ((cursize % 8) != 0)
118 cursize = 0;
119 else
120 cursize /= 8;
122 # try and gather the field name.
123 field = $(NF - 6);
124 if (field == "};") {
125 # anonymous union. discard it.
126 next;
128 if (field == "*/);") {
129 field = $(NF - 9); # function pointer
130 # remove enclosing braces
131 field = substr(field, 2, length(field) - 2);
133 colon = index(field, ":");
134 if (colon != 0)
135 field = substr(field, 1, colon - 1);
136 else if (substr(field, length(field), 1) == ";")
137 field = substr(field, 1, length(field) - 1);
139 while (index(field, "*") == 1)
140 field = substr(field, 2);
142 # This could be an array. If it is, we need to trim the field
143 # name and update its size to a single member size.
144 obracket = index(field, "[");
145 cbracket = index(field, "]");
146 if (obracket != 0) {
147 obracket++;
148 nitems = substr(field, obracket, cbracket - obracket);
149 field = substr(field, 1, obracket - 2);
150 cursize /= nitems;
151 } else
152 nitems = 1;
154 fidx = fcnt;
155 fname[fidx] = field;
156 foffs[fidx] = curoffs;
157 fsize[fidx] = cursize;
158 fitems[fidx] = nitems;
159 fstruct[fidx] = sidx;
160 fcnt++;
161 #printf(" %s at %d len %d\n", field, curoffs, cursize);
163 # Remember size and offset if not found yet
165 for (i = 0; i < ocnt; i++)
166 if (offs[i] == curoffs)
167 break;
168 if (i == ocnt) {
169 # keep array sorted
170 for (i = 0; i < ocnt; i++)
171 if (offs[i] > curoffs)
172 break;
173 if (i < ocnt) {
174 for (j = ocnt + 1; j > i; j--)
175 offs[j] = offs[j - 1];
177 offs[i] = curoffs;
178 ocnt++;
181 for (i = 0; i < zcnt; i++)
182 if (sizes[i] == cursize)
183 break;
184 if (i == zcnt) {
185 # keep array sorted
186 for (i = 0; i < zcnt; i++)
187 if (sizes[i] > cursize)
188 break;
189 if (i < zcnt) {
190 for (j = zcnt + 1; j > i; j--)
191 sizes[j] = sizes[j - 1];
193 sizes[i] = cursize;
194 zcnt++;
197 END {
198 printf("/*\n");
199 printf(" * THIS IS A GENERATED FILE. DO NOT EDIT!\n");
200 printf(" */\n\n");
202 printf("#include <sys/param.h>\n");
203 printf("#include <sys/types.h>\n");
204 printf("\n");
206 # structure definitions
208 printf("struct ddb_struct_info {\n");
209 printf("\tconst char *name;\n");
210 printf("\tsize_t size;\n");
211 printf("\tuint fmin, fmax;\n");
212 printf("};\n");
214 printf("struct ddb_field_info {\n");
215 printf("\tconst char *name;\n");
216 printf("\tuint sidx;\n");
217 printf("\tsize_t offs;\n");
218 printf("\tsize_t size;\n");
219 printf("\tuint nitems;\n");
220 printf("};\n");
222 printf("struct ddb_field_offsets {\n");
223 printf("\tsize_t offs;\n");
224 printf("\tconst uint *list;\n");
225 printf("};\n");
227 printf("struct ddb_field_sizes {\n");
228 printf("\tsize_t size;\n");
229 printf("\tconst uint *list;\n");
230 printf("};\n");
232 # forward arrays
234 printf("#define NSTRUCT %d\n", scnt);
235 printf("static const struct ddb_struct_info ddb_struct_info[NSTRUCT] = {\n");
236 for (i = 0; i < scnt; i++) {
237 printf("\t{ \"%s\", %d, %d, %d },\n",
238 sname[i], ssize[i], sfieldmin[i], sfieldmax[i]);
240 printf("};\n\n");
242 printf("#define NFIELD %d\n", fcnt);
243 printf("static const struct ddb_field_info ddb_field_info[NFIELD] = {\n");
244 printf("\t{ NULL, 0, 0, 0 },\n");
245 for (i = 1; i < fcnt; i++) {
246 printf("\t{ \"%s\", %d, %d, %d, %d },\n",
247 fname[i], fstruct[i], foffs[i], fsize[i], fitems[i]);
249 printf("};\n\n");
251 # reverse arrays
253 printf("static const uint ddb_fields_by_offset[] = {\n");
254 w = 0;
255 for (i = 0; i < ocnt; i++) {
256 cmp = offs[i];
257 ohead[i] = w;
258 for (f = 1; f < fcnt; f++)
259 if (foffs[f] == cmp) {
260 if ((w % 10) == 0)
261 printf("\t");
262 printf("%d, ", f);
263 w++;
264 if ((w % 10) == 0)
265 printf("\n");
267 if ((w % 10) == 0)
268 printf("\t");
269 printf("0, ");
270 w++;
271 if ((w % 10) == 0)
272 printf("\n");
274 if ((w % 10) != 0)
275 printf("\n");
276 printf("};\n\n");
278 printf("#define NOFFS %d\n", ocnt);
279 printf("static const struct ddb_field_offsets ddb_field_offsets[NOFFS] = {\n");
280 for (i = 0; i < ocnt; i++) {
281 printf("\t{ %d, ddb_fields_by_offset + %d },\n",
282 offs[i], ohead[i]);
284 printf("};\n\n");
286 printf("static const uint ddb_fields_by_size[] = {\n");
287 w = 0;
288 for (i = 0; i < zcnt; i++) {
289 cmp = sizes[i];
290 zhead[i] = w;
291 for (f = 1; f < fcnt; f++)
292 if (fsize[f] == cmp) {
293 if ((w % 10) == 0)
294 printf("\t");
295 printf("%d, ", f);
296 w++;
297 if ((w % 10) == 0)
298 printf("\n");
300 if ((w % 10) == 0)
301 printf("\t");
302 printf("0, ");
303 w++;
304 if ((w % 10) == 0)
305 printf("\n");
307 if ((w % 10) != 0)
308 printf("\n");
309 printf("};\n\n");
311 printf("#define NSIZES %d\n", zcnt);
312 printf("static const struct ddb_field_sizes ddb_field_sizes[NSIZES] = {\n");
313 for (i = 0; i < zcnt; i++) {
314 printf("\t{ %d, ddb_fields_by_size + %d },\n",
315 sizes[i], zhead[i]);
317 printf("};\n");