17d4dad21d021e52dc0e82a53b13bbafd694d0ce
[panamaz] / src / export.cc
1 /*
2  * export c types and prototypes to perl file.
3  *
4  * Copyright (c) 2019 Yonatan Goldschmidt
5  * Copyright (c) 2020,2021 Michael Zucchi
6  *
7  * The MIT License (MIT)
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25  * THE SOFTWARE.
26  */
27
28 /*
29    skeleton taken from structsizes.cc plugin by Richard W.M. Jones
30    https://rwmj.wordpress.com/2016/02/24/playing-with-gcc-plugins/
31    some other bits from
32    https://blog.adacore.com/bindings-gcc-plugins
33  */
34
35 /*
36
37 function declarations, i think
38
39                   chain            param type                 name              size
40 TYPE_DECL         TYPE_ARG_TYPES   TYPE_VALUE(item):TREE_LIST  <empty>           TYPE_SIZE(item_type)
41  /POINTER
42  /FUNCTION_TYPE
43 FUNCTION_DECL     DECL_ARGUENTS    TREE_TYPE(item):PARM_DECL   DECL_NAME(item)   DECL_SIZE(item)
44                                                                                  TYPE_SIZE(item_type)
45  */
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <gcc-plugin.h>
51 #include <tree.h>
52 #include <print-tree.h>
53 #include <tree-pretty-print.h>
54
55 #include "list.h"
56
57 #define D(x) do { x; } while(0)
58
59 extern const char *tree_codes[];
60 #define ZTREE_CODE(x) tree_codes[TREE_CODE(x)]
61
62 //Enums have a type, otherwise they're just integers
63 //#define TYPED_ENUMS
64
65 // remove some of the debug
66 //#define NDEBUG
67
68 int plugin_is_GPL_compatible; // must be defined for the plugin to run
69
70 static FILE *output_file;
71 static int debug_level = 0;
72
73 static void debug_tree_helper(tree t, const char *msg) {
74 #ifndef NDEBUG
75         if (debug_level > 2) {
76                 fflush(stdout);
77                 fprintf(stderr, "dumping tree: '%s'\n", msg);
78                 debug_tree(t);
79                 fprintf(stderr, "\n\n");
80                 fflush(stdout);
81         }
82 #endif
83 }
84
85 static struct hash dumped;
86 static struct list todump;
87 static struct list context_stack;
88 static struct list parameters;  // last list of params
89
90 static struct hash forward_types;
91
92 /*
93   Join all names in the stack, in reverse order.
94 */
95 static char *stack_path(struct list *stack, const char *sep) {
96         size_t total = 1;
97
98         for (struct node *n = stack->tail; n; n=n->link)
99                 total += strlen(n->name)+strlen(sep);
100
101         char *data = (char *)xmalloc(total);
102         char *p = data;
103
104         // FIXME: some other context name
105         for (struct node *n = stack->tail; n; n=n->link) {
106                 p = stpcpy(p, n->name);
107                 if (n->link)
108                         p = stpcpy(p, sep);
109         }
110
111         return data;
112 }
113
114 static void list_clear(struct list *list) {
115         struct node *node;
116
117         while ((node = list_remhead(list))) {
118                 if (debug_level > 2)
119                         fprintf(stderr, " free: %s\n", node->name);
120                 free(node);
121         }
122 }
123
124 // returns 0 if type has no size (i.e VOID_TYPE)
125 static bool is_struct_or_union(const_tree type) {
126         return RECORD_TYPE == TREE_CODE(type) || UNION_TYPE == TREE_CODE(type);
127 }
128
129 static void print_spaces(int n) {
130         for (int i = 0; i < n; ++i)
131                 fputc('\t', output_file);
132 }
133
134 static int is_ref_type(tree type) {
135         switch (TREE_CODE(type)) {
136         case VECTOR_TYPE:
137         case ARRAY_TYPE:
138         case POINTER_TYPE:
139         case REFERENCE_TYPE:
140                 return 1;
141         default:
142                 return 0;
143         }
144 }
145
146 static tree target_type(tree type) {
147         while (is_ref_type(type))
148                 type = TREE_TYPE(type);
149         return type;
150 }
151
152 static size_t value_size(tree n) {
153         return n ? tree_to_uhwi(n) : 0;
154 }
155
156 static const char *value_name(tree type) {
157         tree test = TYPE_IDENTIFIER(type);
158         const char *value = test ? IDENTIFIER_POINTER(test) : NULL;
159
160         // __va_list_tag is the final type beneath __builtin_va_list.
161         // it behaves different from other types - it has a TYPE_MAIN_VARIANT, but the main TYPE_NAME seems to give
162         // an unexpected tree, and therefore ORIG_TYPE_NAME returns a garbage value.
163         // I think this patch is good enough.
164         if (value && 0 == strcmp("__va_list_tag", value))
165                 return "__va_list_tag";
166
167         test = TYPE_MAIN_VARIANT(type);
168         test = test ? TYPE_NAME(test) : test;
169         test = test && TREE_CODE(test) == TYPE_DECL ? DECL_NAME(test) : test;
170
171         return test ? IDENTIFIER_POINTER(test) : value;
172 }
173
174 /*
175   Find a non-ref type in the type chain, i.e. skip pointers/arrays.
176 */
177 static tree simple_type(tree t) {
178         while (is_ref_type(t))
179                 t = TREE_TYPE(t);
180         return t;
181 }
182
183 /*
184   Create a 'panama' signature for a single type.
185 */
186 static void export_desc(tree field, tree field_type, struct buffer *b) {
187         const size_t data_size = value_size(TYPE_SIZE(field_type));
188
189         switch (TREE_CODE(field_type)) {
190         case VOID_TYPE:
191                 buffer_add(b, "v");
192                 break;
193         case VECTOR_TYPE:
194         case ARRAY_TYPE: {
195                 const size_t elem_size = tree_to_uhwi(TYPE_SIZE_UNIT(TREE_TYPE(field_type)));
196                 size_t num_elem;
197
198                 if (elem_size == 0 || NULL == TYPE_SIZE_UNIT(field_type)) {
199                         // it is a flexible array or empty types
200                         num_elem = 0;
201                 } else {
202                         // it might be 0 / elem_size, in which case we also end up with num_elem = 0.
203                         num_elem = tree_to_uhwi(TYPE_SIZE_UNIT(field_type)) / elem_size;
204                 }
205
206                 buffer_room(b, 16);
207                 b->pos += sprintf(b->data + b->pos, "[%zu", num_elem);
208                 export_desc(field, TREE_TYPE(field_type), b);
209                 buffer_add(b, "]");
210                 break;
211         }
212         case POINTER_TYPE:
213         case REFERENCE_TYPE:
214                 buffer_room(b, 16);
215                 b->pos += sprintf(b->data + b->pos, "u%zu:", data_size);
216                 export_desc(field, TREE_TYPE(field_type), b);
217                 break;
218         case FUNCTION_TYPE: {
219                 // TODO: handle void f() type -> null TYPE_ARG_TYPES()
220                 tree return_type = TREE_TYPE(field_type);
221
222                 buffer_add(b, "(");
223                 for (tree param = TYPE_ARG_TYPES(field_type); param != NULL; param = TREE_CHAIN(param)) {
224                         tree param_type = TREE_VALUE(param);
225
226                         if (TREE_CODE(param_type) == VOID_TYPE)
227                                 break;
228
229                         export_desc(param, param_type, b);
230                 }
231                 buffer_add(b, ")");
232                 export_desc(field, return_type, b);
233                 break;
234         }
235         case ENUMERAL_TYPE:
236 #if defined(TYPED_ENUMS)
237                 buffer_add(b, "${");
238                 buffer_add(b, TYPE_IDENTIFIER(field_type) ? value_name(field_type) : "enum");
239                 buffer_add(b, "}");
240 #else
241                 buffer_room(b, 16);
242                 b->pos += sprintf(b->data + b->pos, "%c%zu",
243                         TYPE_UNSIGNED(field_type) ? 'u' : 'i',
244                         data_size);
245 #endif
246                 break;
247         case RECORD_TYPE:
248         case UNION_TYPE:
249                 if (TYPE_IDENTIFIER(field_type)) {
250                         list_add(&todump, node_alloc(field_type, NULL));
251
252                         buffer_add(b, "${");
253                         buffer_add(b, value_name(field_type));
254                         buffer_add(b, "}");
255                 } else {
256                         char *name = stack_path(&context_stack, "_");
257
258                         list_add(&todump, node_alloc(field_type, name));
259
260                         buffer_add(b, "${");
261                         buffer_add(b, name);
262                         buffer_add(b, "}");
263
264                         free(name);
265                 }
266                 break;
267         case REAL_TYPE:
268                 buffer_room(b, 16);
269                 b->pos += sprintf(b->data + b->pos, "f%zu", data_size);
270                 break;
271         case INTEGER_TYPE:
272                 buffer_room(b, 16);
273                 b->pos += sprintf(b->data + b->pos, "%c%zu",
274                         TYPE_UNSIGNED(field_type) ? 'u' : 'i',
275                         data_size);
276                 break;
277         default:
278                 debug_tree_helper(field_type, "unknown type!");
279                 gcc_unreachable();
280                 break;
281         }
282 }
283
284 /*
285   Create a 'c' description of type.
286 */
287 static void export_cdesc(tree field, tree field_type, struct buffer *b) {
288         const size_t data_size = value_size(TYPE_SIZE(field_type));
289
290         switch (TREE_CODE(field_type)) {
291         case VOID_TYPE:
292                 buffer_add(b, "void");
293                 break;
294         case VECTOR_TYPE:
295         case ARRAY_TYPE: {
296                 const size_t elem_size = tree_to_uhwi(TYPE_SIZE_UNIT(TREE_TYPE(field_type)));
297                 size_t num_elem;
298
299                 if (elem_size == 0 || NULL == TYPE_SIZE_UNIT(field_type)) {
300                         // it is a flexible array or empty types
301                         num_elem = 0;
302                 } else {
303                         // it might be 0 / elem_size, in which case we also end up with num_elem = 0.
304                         num_elem = tree_to_uhwi(TYPE_SIZE_UNIT(field_type)) / elem_size;
305                 }
306
307                 export_cdesc(field, TREE_TYPE(field_type), b);
308
309                 buffer_room(b, 16);
310                 buffer_add(b, "[");
311                 if (num_elem)
312                         b->pos += sprintf(b->data + b->pos, "%zu", num_elem);
313                 buffer_add(b, "]");
314                 break;
315         }
316         case POINTER_TYPE:
317         case REFERENCE_TYPE:
318                 buffer_room(b, 16);
319                 buffer_add(b, "*");
320                 //b->pos += sprintf(b->data + b->pos, "u%zu:", data_size);
321                 export_cdesc(field, TREE_TYPE(field_type), b);
322                 break;
323         case FUNCTION_TYPE: {
324                 // TODO: handle void f() type -> null TYPE_ARG_TYPES()
325                 tree return_type = TREE_TYPE(field_type);
326                 int args = 0;
327
328                 export_cdesc(field, return_type, b);
329
330                 buffer_add(b, "(*)");
331                 buffer_add(b, "(");
332                 for (tree param = TYPE_ARG_TYPES(field_type); param != NULL; param = TREE_CHAIN(param)) {
333                         tree param_type = TREE_VALUE(param);
334
335                         // TREE_TYPE might? point to a type that a previous decl has also referenced
336
337                         if (args++)
338                                 buffer_add(b, ", ");
339
340                         if (TREE_CODE(param_type) == VOID_TYPE) {
341                                 buffer_add(b, "void");
342                                 break;
343                         }
344
345                         export_cdesc(param, param_type, b);
346                 }
347                 buffer_add(b, ")");
348                 break;
349         }
350         case ENUMERAL_TYPE:
351 #if defined(TYPED_ENUMS)
352                 buffer_add(b, "${");
353                 buffer_add(b, TYPE_IDENTIFIER(field_type) ? value_name(field_type) : "enum");
354                 buffer_add(b, "}");
355 #else
356                 buffer_room(b, 16);
357                 b->pos += sprintf(b->data + b->pos, "%c%zu",
358                         TYPE_UNSIGNED(field_type) ? 'u' : 'i',
359                         data_size);
360 #endif
361                 break;
362         case RECORD_TYPE:
363         case UNION_TYPE:
364                 if (TYPE_IDENTIFIER(field_type)) {
365                         list_add(&todump, node_alloc(field_type, NULL));
366
367                         buffer_add(b, "${");
368                         buffer_add(b, value_name(field_type));
369                         buffer_add(b, "}");
370                 } else {
371                         char *name = stack_path(&context_stack, "_");
372
373                         list_add(&todump, node_alloc(field_type, name));
374
375                         buffer_add(b, "${");
376                         buffer_add(b, name);
377                         buffer_add(b, "}");
378
379                         free(name);
380                 }
381                 break;
382         case REAL_TYPE:
383                 buffer_room(b, 16);
384                 b->pos += sprintf(b->data + b->pos, "f%zu", data_size);
385                 break;
386         case INTEGER_TYPE:
387                 buffer_room(b, 16);
388                 b->pos += sprintf(b->data + b->pos, "%c%zu",
389                         TYPE_UNSIGNED(field_type) ? 'u' : 'i',
390                         data_size);
391                 break;
392         default:
393                 debug_tree_helper(field_type, "unknown type!");
394                 gcc_unreachable();
395                 break;
396         }
397 }
398
399 /*
400   Print a single parameter or field.
401 */
402 static void export_param(tree field, tree field_type, size_t field_size) {
403         switch (TREE_CODE(field_type)) {
404         case VECTOR_TYPE:
405         case ARRAY_TYPE:
406         case POINTER_TYPE:
407         case REFERENCE_TYPE: {
408                 struct buffer b;
409
410                 buffer_init(&b, 256);
411                 export_desc(field, field_type, &b);
412                 fprintf(output_file, " deref => '%s',", b.data);
413                 free(b.data);
414
415                 field_type = simple_type(field_type);
416                 field_size = value_size(TYPE_SIZE(field_type));
417
418                 export_param(field, field_type, field_size);
419                 break;
420         }
421         case VOID_TYPE:
422                 fprintf(output_file, " type => 'void',");
423                 fprintf(output_file, " ctype => 'void',");
424                 break;
425         case ENUMERAL_TYPE: {
426 #if defined(TYPED_ENUMS)
427                 const char *names = TYPE_IDENTIFIER(field_type) ? value_name(field_type) : "enum";
428                 fprintf(output_file, " type => 'enum:%s',", names);
429 #else
430                 fprintf(output_file, " type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', field_size);
431 #endif
432                 fprintf(output_file, " ctype => 'enum %s',", value_name(field_type));
433                 break;
434         }
435         case FUNCTION_TYPE: {
436                 struct buffer b;
437                 tree root_type = TREE_TYPE(field);
438
439                 // If this is a typedef we might have a name for the type, otherwise it's a signature based name
440                 if (root_type && TYPE_IDENTIFIER(root_type)) {
441                         fprintf(output_file, " type => 'call:%s', ", value_name(root_type));
442                 } else {
443                         fprintf(stderr, "save for later param type %p\n", field_type);
444                         buffer_init(&b, 256);
445                         export_desc(field, field_type, &b);
446                         list_add(&todump, node_alloc(field_type, b.data));
447                         fprintf(output_file, " type => 'call:%s', ", b.data);
448                 }
449
450                 buffer_init(&b, 256);
451                 export_cdesc(field, field_type, &b);
452                 free(b.data);
453
454                 break;
455         }
456         case REAL_TYPE:
457                 fprintf(output_file, " ctype => '%s',", value_name(field_type));
458                 fprintf(output_file, " type => 'f%zu',", field_size);
459                 break;
460         case INTEGER_TYPE:
461                 if (TREE_CODE(field) == FIELD_DECL && DECL_BIT_FIELD(field)) {
462                         fprintf(output_file, " ctype => 'bitfield',");
463                         fprintf(output_file, " type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', value_size(DECL_SIZE(field)));
464                 } else {
465                         fprintf(output_file, " ctype => '%s',", value_name(field_type));
466                         fprintf(output_file, " type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', field_size);
467                 }
468                 break;
469         case RECORD_TYPE:
470         case UNION_TYPE: {
471                 const char *us = TREE_CODE(field_type) == RECORD_TYPE ? "struct" : "union";
472
473                 if (TYPE_IDENTIFIER(field_type)) {
474                         fprintf(output_file, " type => '%s:%s',", us, value_name(field_type));
475                 } else {
476                         char *name = stack_path(&context_stack, "_");
477
478                         list_add(&todump, node_alloc(field_type, name));
479                         fprintf(output_file, " type => '%s:%s',", us, name);
480                         free(name);
481                 }
482                 break;
483         }
484         default:
485                 fprintf(stderr, "unknown param type: %s\n", ZTREE_CODE(field_type));
486                 gcc_unreachable();
487         }
488 }
489
490 /*
491   Export a chain of parameters
492 */
493 static void export_params(tree func) {
494         int id = 0;
495         char nameb[32];
496         struct list args = { 0 };
497         struct node *name;
498         struct node *fwd = hash_lookup_bytype(&forward_types, func);
499
500         if (fwd) {
501                 // use the forward reference to find the names
502                 fprintf(stderr, "found forward reference @ %p\n", fwd);
503                 name = fwd->list.head;
504         } else {
505                 // paramter names are in the paramters list
506                 // but they are in reverse order
507                 int id = 0;
508                 for (tree param = TYPE_ARG_TYPES(func); param; param = TREE_CHAIN(param)) {
509                         tree param_type = TREE_VALUE(param);
510
511                         if (!TREE_CHAIN(param) && TREE_CODE(param_type) == VOID_TYPE)
512                                 break;
513
514                         struct node *decl = stack_pull(&parameters);
515                         if (decl) {
516                                 fprintf(stderr, "(pull parameter '%s')\n", decl->name);
517                                 stack_push(&args, decl);
518                         } else
519                                 fprintf(stderr, "ERROR: parameter %d missing parameter declaration\n", id);
520                         id++;
521                 }
522                 name = args.head;
523         }
524
525         for (tree param = TYPE_ARG_TYPES(func); param; param = TREE_CHAIN(param)) {
526                 tree param_type = TREE_VALUE(param);
527                 const size_t data_size = value_size(TYPE_SIZE(param_type));
528                 const char *names = NULL;
529
530                 // non-varags functions end in VOID_TYPE
531                 if (!TREE_CHAIN(param) && TREE_CODE(param_type) == VOID_TYPE)
532                         break;
533
534                 fprintf(output_file, "\t\t{");
535
536                 // size: do we need it?
537                 fprintf(output_file, " size => %zu,", data_size);
538
539                 if (name) {
540                         // this should be a parm_decl with an identifier of the name
541                         names = name->name;
542
543                         // can one check it's a matching type?
544                         name = name->next;
545                 }
546
547                 if (!names || !names[0]) {
548                         sprintf(nameb, "arg_%d", id);
549                         names = nameb;
550                 }
551
552                 fprintf(output_file, " name => '%s',", names);
553                 stack_push(&context_stack, node_alloc(param, names));
554
555                 // value: details
556                 export_param(param, param_type, data_size);
557
558                 free(stack_pull(&context_stack));
559
560                 fprintf(output_file, "},\n");
561                 id++;
562         }
563
564         list_clear(&args);
565 }
566
567 /*
568   Export a chain of fields.
569 */
570 static void export_fields(tree first_field, size_t base_offset, int indent) {
571         for (tree field = first_field; field; field = TREE_CHAIN(field)) {
572                 gcc_assert(TREE_CODE(field) == FIELD_DECL);
573
574                 tree field_type = TREE_TYPE(field);
575                 const size_t field_size = value_size(DECL_SIZE(field));
576                 size_t offset = base_offset + tree_to_uhwi(DECL_FIELD_OFFSET(field)) * 8 + tree_to_uhwi(DECL_FIELD_BIT_OFFSET(field));
577
578                 // name: if none, then inline
579                 if (!DECL_NAME(field)) {
580                         if (is_struct_or_union(field_type))
581                                 export_fields(TYPE_FIELDS(field_type), offset, indent);
582                 } else {
583                         const char *names = IDENTIFIER_POINTER(DECL_NAME(field));
584
585                         if (debug_level > 1)
586                                 fprintf(stderr, "   field: %s\n", names);
587                         print_spaces(indent+1);
588                         fprintf(output_file, "{ name => '%s', size => %zu, offset => %zu,", names, field_size, offset);
589                         stack_push(&context_stack, node_alloc(field, names));
590
591                         // value: details
592                         export_param(field, field_type, field_size);
593
594                         free(stack_pull(&context_stack));
595
596                         fprintf(output_file, "},\n");
597                 }
598         }
599 }
600
601 /*
602   Main entry point for exporting any type.
603 */
604 static void export_type(tree type, const char *names) {
605         tree name;
606         tree deftype;
607         tree target;
608
609         if (debug_level > 1)
610                 fprintf(stderr, "export_type(%s, %s)\n", ZTREE_CODE(type), names);
611
612         switch (TREE_CODE(type)) {
613         case TYPE_DECL: {
614                 if (!names) {
615                         name = DECL_NAME(type);
616                         if (!name)
617                                 return;
618                         names = IDENTIFIER_POINTER(name);
619                 }
620                 if (hash_lookup(&dumped, names))
621                         return;
622                 hash_put(&dumped, node_alloc(type, names));
623
624                 if (debug_level > 1)
625                         fprintf(stderr, "export: %s %s\n", names, ZTREE_CODE(type));
626
627                 deftype = TREE_TYPE(type);
628                 target = target_type(deftype);
629                 switch (TREE_CODE(target)) {
630                 case FUNCTION_TYPE: {
631                         // function pointer typdef
632                         // I don't know if i even want this
633                         fprintf(output_file, "'call:%s' => { name => '%s', type => 'call',", names, names);
634
635                         // the deftype is always a pointer for a function_type
636
637                         struct buffer b;
638
639                         buffer_init(&b, 256);
640                         export_desc(type, deftype, &b);
641                         fprintf(output_file, " deref => '%s',", b.data);
642                         free(b.data);
643
644                         fprintf(output_file, " ctype => '%s',", print_generic_expr_to_str(target));
645
646                         // TODO: cleanup
647                         {
648                                 tree result_type = TREE_TYPE(target);
649                                 const size_t data_size = value_size(TYPE_SIZE(result_type));
650
651                                 fprintf(output_file, "\n\tresult => {");
652                                 export_param(target, result_type, data_size);
653                                 fprintf(output_file, " },");
654                         }
655
656                         fprintf(output_file, "\n\targuments => [\n");
657                         export_params(target);
658                         fprintf(output_file, "]},\n");
659                         break;
660                 }
661                 case ENUMERAL_TYPE: {
662                         // TODO: typedef of anonymous enumerations may be repeated
663                         // TODO: this could be detected in the frontend - e.g. don't include any
664                         // TODO: anon enum values if any are already there
665                         // TODO: or maybe duplicates could be detected here
666                         size_t size = tree_to_uhwi(TYPE_SIZE(target));
667
668                         if (size > 64) {
669                                 fprintf(stderr, "Warning: enum '%s' requires too many bits (%zu)\n", names, size);
670                                 return;
671                         }
672
673                         fprintf(output_file, "'enum:%s' => { name => '%s', type => 'enum', size => %zu, value_type => '%c%zu', values => [\n",
674                                 names, names, size, TYPE_UNSIGNED(target) ? 'u' : 'i', size);
675
676                         for (tree v = TYPE_VALUES(target); v != NULL; v = TREE_CHAIN (v)) {
677                                 fprintf(output_file, "\t{ label => '%s', value => '%ld' },\n",
678                                         IDENTIFIER_POINTER(TREE_PURPOSE(v)),
679                                         tree_to_shwi(TREE_VALUE(v)));
680                         }
681                         fprintf(output_file, "]},\n");
682                         break;
683                 }
684                 case RECORD_TYPE: // forward declaration or opaque types
685                 case UNION_TYPE:
686                 case VOID_TYPE:
687                 case INTEGER_TYPE:
688                 case REAL_TYPE:
689                         if (debug_level)
690                                 fprintf(stderr, "ignored %s: %s\n", ZTREE_CODE(target), names);
691                         break;
692                 default:
693                         fprintf(stderr, "unknown type def: %s\n", ZTREE_CODE(target));
694                         gcc_unreachable();
695                 }
696
697                 break;
698         }
699         case FUNCTION_DECL: {
700                 if (!names) {
701                         name = DECL_NAME(type);
702                         if (!name)
703                                 return;
704                         names = IDENTIFIER_POINTER(name);
705                 }
706                 if (hash_lookup(&dumped, names))
707                         return;
708                 hash_put(&dumped, node_alloc(type, names));
709
710                 if (debug_level > 1)
711                         fprintf(stderr, "export type func decl %s\n", names);
712
713                 fprintf(output_file, "'func:%s' => { name => '%s', type => 'func',", names, names);
714
715                 // FUNCTION_DECL -> FUNCTION_TYPE -> RESULT_TYPE, get FUNCTION_TYPE
716                 type = TREE_TYPE(type);
717
718                 fprintf(output_file, " ctype => '%s',", print_generic_expr_to_str(type));
719
720                 // TODO: cleanup
721                 debug_tree_helper(type, "function 1");
722                 {
723                         tree result_type = TREE_TYPE(type);
724                         const size_t data_size = value_size(TYPE_SIZE(result_type));
725
726                         fprintf(output_file, "\n\tresult => {");
727                         export_param(type, result_type, data_size);
728                         fprintf(output_file, " },");
729                 }
730
731                 fprintf(output_file, "\n\targuments => [\n");
732                 //export_decl_params(DECL_ARGUMENTS(type), 0);
733                 export_params(type);
734                 fprintf(output_file, "]},\n");
735                 break;
736         }
737         case FUNCTION_TYPE: {
738                 // This is called for un-typedef'd function pointers.
739                 // WHY IS THIS DIFFERENT TO ABOVE?
740                 if (!names) {
741                         name = TYPE_IDENTIFIER(type);
742                         if (!name)
743                                 return;
744                         names = IDENTIFIER_POINTER(name);
745                 }
746                 if (hash_lookup(&dumped, names))
747                         return;
748                 hash_put(&dumped, node_alloc(type, names));
749
750                 if (debug_level > 1)
751                         fprintf(stderr, "export: %s %s\n", names, ZTREE_CODE(type));
752
753                 fprintf(output_file, "'call:%s' => { name => '%s', type => 'call',", names, names);
754                 fprintf(output_file, " ctype => '%s',", print_generic_expr_to_str(type));
755
756                 debug_tree_helper(type, "function type");
757
758                 // TODO: cleanup
759                 // FUNCTION_TYPE -> RESULT_TYPE
760                 {
761                         tree result = TREE_TYPE(type);
762                         //tree result_type = TREE_TYPE(result);
763                         //printf(" result type type %s\n", ZTREE_CODE(result_type));
764                         const size_t data_size = value_size(TYPE_SIZE(result));
765
766                         if (debug_level > 2)
767                                 fprintf(stderr, " result size %zu\n", data_size);
768                         fprintf(output_file, "\n\tresult => {");
769                         export_param(type, result, data_size);
770                         fprintf(output_file, " },");
771                 }
772
773                 stack_push(&context_stack, node_alloc(type, names));
774                 fprintf(output_file, "\n\targuments => [\n");
775                 export_params(type);
776                 free(stack_pull(&context_stack));
777                 fprintf(output_file, "]},\n");
778                 break;
779         }
780         case RECORD_TYPE: // struct
781         case UNION_TYPE: {
782                 const char *su = TREE_CODE(type) == RECORD_TYPE ? "struct" : "union";
783
784                 // ignore empty types
785                 if (!TYPE_FIELDS(type))
786                         return;
787
788                 if (!names) {
789                         name = TYPE_IDENTIFIER(type);
790                         if (!name)
791                                 return;
792                         names = IDENTIFIER_POINTER(name);
793                 }
794                 if (hash_lookup(&dumped, names))
795                         return;
796                 hash_put(&dumped, node_alloc(type, names));
797
798                 if (debug_level > 1)
799                         fprintf(stderr, "export: %s %s\n", names, ZTREE_CODE(type));
800
801                 fprintf(output_file, "'%s:%s' => { name => '%s', type => '%s', size => %zu, fields => [\n",
802                         su, names, names, su, tree_to_uhwi(TYPE_SIZE(type)));
803
804                 stack_push(&context_stack, node_alloc(type, names));
805                 export_fields(TYPE_FIELDS(type), 0, 0);
806                 free(stack_pull(&context_stack));
807
808                 fprintf(output_file, "]},\n");
809                 break;
810         }
811         case ENUMERAL_TYPE: {
812                 // FIXME: see ENUMERAL_TYPE above regarding duplicate anon enums
813
814                 // ignore empty enums
815                 if (!TYPE_VALUES(type))
816                         return;
817
818                 // We can only assume a non-named enum type isn't repeatedly sent here
819                 if (!names) {
820                         name = TYPE_IDENTIFIER(type);
821                         if (name)
822                                 names = IDENTIFIER_POINTER(name);
823                 }
824                 if (names) {
825                         if (hash_lookup(&dumped, names))
826                                 return;
827                         hash_put(&dumped, node_alloc(type, names));
828                 }
829
830                 size_t size = tree_to_uhwi(TYPE_SIZE(type));
831
832                 if (size > 64) {
833                         fprintf(stderr, "Warning: enum '%s' requires too many bits (%zu)\n", names, size);
834                         return;
835                 }
836
837                 // FIXME: choose a better anon name
838                 char nameb[64];
839                 static int namei;
840
841                 if (!names) {
842                         sprintf(nameb, "enum$%d", namei++);
843                         names = nameb;
844                 }
845
846                 if (debug_level > 1)
847                         fprintf(stderr, "export: %s %s\n", names, ZTREE_CODE(type));
848
849                 fprintf(output_file, "'enum:%s' => { name => '%s', type => 'enum', size => %zu, value_type => '%c%zu', values => [\n",
850                         names, names, size, TYPE_UNSIGNED(type) ? 'u' : 'i', size);
851
852                 for (tree v = TYPE_VALUES(type); v != NULL; v = TREE_CHAIN (v)) {
853                         fprintf(output_file, "\t{ label => '%s', value => '%ld' },\n",
854                                 IDENTIFIER_POINTER(TREE_PURPOSE(v)),
855                                 tree_to_shwi(TREE_VALUE(v)));
856                 }
857                 fprintf(output_file, "]},\n");
858                 break;
859         }
860         case FIELD_DECL:
861                 break;
862         case PARM_DECL: {
863                 // capture PARM_DECLs so they can be used at next function declaration
864                 if (!names) {
865                         name = DECL_NAME(type);
866                         if (name)
867                                 names = IDENTIFIER_POINTER(name);
868                 }
869                 // if this is a function pointer typedef, need to suck out the arguments at this point
870                 deftype = TREE_TYPE(type);
871
872                 target = target_type(deftype);
873
874                 //fprintf(stderr, "type is '%s\n", ZTREE_CODE(deftype));
875                 //fprintf(stderr, "target is '%s\n", ZTREE_CODE(target));
876
877                 if (TREE_CODE(target) == FUNCTION_TYPE) {
878                         // We need to save the list of parameters for later,
879                         // it's keyed on target
880                         struct node *fwd = node_alloc(target, NULL);
881
882                         fprintf(stderr, "save forward reference function type %p\n", target);
883
884                         for (tree param = TYPE_ARG_TYPES(target); param != NULL; param = TREE_CHAIN(param)) {
885                                 tree param_type = TREE_VALUE(param);
886
887                                 if (TREE_CODE(param_type) == VOID_TYPE)
888                                         break;
889
890                                 struct node *decl = stack_pull(&parameters);
891                                 if (decl) {
892                                         fprintf(stderr, "(pull parameter '%s')\n", decl->name);
893                                         stack_push(&fwd->list, decl);
894                                 } else
895                                         fprintf(stderr, " missing parameter name\n");
896                         }
897
898                         hash_put_bytype(&forward_types, fwd);
899                 }
900
901                 fprintf(stderr, "(push parameter '%s')\n", names);
902                 stack_push(&parameters, node_alloc(type, names));
903
904                 break; }
905         case VAR_DECL:
906                 // global external variables, might want these
907                 // well, if there's a way to resolve them
908                 break;
909         default:
910                 fprintf(stderr, "unknown export: %s\n", ZTREE_CODE(type));
911                 gcc_unreachable();
912         }
913 }
914
915 static void plugin_finish_type(void *event_data, void *user_data) {
916         tree type = (tree)event_data;
917
918         if (debug_level > 0)
919                 fprintf(stderr, "finish_type\n");
920         if (debug_level > 1)
921                 debug_tree(type);
922
923         export_type(type, NULL);
924 }
925
926 static void plugin_finish_decl(void *event_data, void *user_data) {
927         tree type = (tree)event_data;
928
929         if (debug_level > 0)
930                 fprintf(stderr, "finish_decl %s\n", ZTREE_CODE(type));
931         if (debug_level > 1)
932                 debug_tree(type);
933
934         export_type(type, NULL);
935 }
936
937 static void plugin_finish(void *event_data, void *user_data) {
938         fprintf(stderr, "plugin finish\n");
939         for (struct node *n = todump.head; n; n=n->next) {
940                 if (COMPLETE_TYPE_P(n->type)) {
941                         if (n->name[0]) {
942                                 export_type(n->type, n->name);
943                         } else {
944                                 export_type(n->type, value_name(n->type));
945                         }
946                 }
947         }
948
949         fprintf(output_file, "# dumped structs:\n");
950         for (struct node *n = dumped.list.head; n; n=n->next)
951                 fprintf(output_file, "# %s\n", n->name);
952
953         fprintf(output_file, ");\n");
954         fclose(output_file);
955
956         fprintf(stderr, "unhandled paramters:\n");
957         list_clear(&parameters);
958 }
959
960 int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) {
961         const char *output = NULL;
962
963         for (int i = 0; i < plugin_info->argc; ++i) {
964                 if (0 == strcmp(plugin_info->argv[i].key, "output")) {
965                         output = plugin_info->argv[i].value;
966                 } else if (0 == strcmp(plugin_info->argv[i].key, "debug")) {
967                         debug_level = atoi(plugin_info->argv[i].value);
968                 }
969         }
970
971         if (NULL == output) {
972                 fprintf(stderr, "export plugin: missing parameter: -fplugin-arg-export-output=<output>\n");
973                 exit(EXIT_FAILURE);
974         }
975
976         output_file = fopen(output, "w");
977         if (NULL == output_file) {
978                 perror(output);
979                 exit(EXIT_FAILURE);
980         }
981
982         fprintf(output_file, "%%data = (\n");
983
984         register_callback(plugin_info->base_name, PLUGIN_FINISH_DECL, plugin_finish_decl, NULL);
985         register_callback(plugin_info->base_name, PLUGIN_FINISH_TYPE, plugin_finish_type, NULL);
986         register_callback(plugin_info->base_name, PLUGIN_FINISH, plugin_finish, NULL);
987
988         return 0;
989 }