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