611ab3f368b4038a2731b83bc9efb3a83cd3c190
[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         static tree enclosing_type = NULL;
424
425         if (debug_level > 1) {
426                 fprintf(stderr, "export_param (%s, %s)\n", ZTREE_CODE(field), ZTREE_CODE(field_type));
427                 //fprintf(stderr, " field name '%s'\n", TYPE_IDENTIFIER(field) ? IDENTIFIER_POINTER(TYPE_IDENTIFIER(field)) : "<unknown>");
428                 fprintf(stderr, " field_type name '%s'\n", TYPE_IDENTIFIER(field_type) ? IDENTIFIER_POINTER(TYPE_IDENTIFIER(field_type)) : "<unknown>");
429                 debug_tree(field_type);
430         }
431
432         switch (TREE_CODE(field_type)) {
433         case VECTOR_TYPE:
434         case ARRAY_TYPE:
435         case POINTER_TYPE:
436         case REFERENCE_TYPE: {
437                 tree base_type;
438                 size_t base_size;
439                 struct buffer b;
440
441                 buffer_init(&b, 256);
442                 export_desc(field, field_type, &b);
443                 generate(" deref => '%s',", b.data);
444                 free(b.data);
445
446                 base_type = simple_type(field_type);
447                 base_size = value_size(TYPE_SIZE(base_type));
448
449                 if (debug_level > 1)
450                         fprintf(stderr, "recurse %s %s\n", ZTREE_CODE(field_type), ZTREE_CODE(base_type));
451
452                 enclosing_type = field_type;
453                 export_param(field, base_type, base_size);
454                 enclosing_type = NULL;
455                 break;
456         }
457         case VOID_TYPE:
458                 generate(" type => 'void',");
459                 generate(" ctype => 'void',");
460                 break;
461         case ENUMERAL_TYPE: {
462 #if defined(TYPED_ENUMS)
463                 const char *names = TYPE_IDENTIFIER(field_type) ? value_name(field_type) : "enum";
464                 generate(" type => 'enum:%s',", names);
465 #else
466                 generate(" type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', field_size);
467 #endif
468                 generate(" ctype => 'enum %s',", value_name(field_type));
469                 break;
470         }
471         case FUNCTION_TYPE: {
472                 struct buffer b;
473                 tree root_type = TREE_TYPE(field);
474
475                 if (root_type == NULL || !TYPE_IDENTIFIER(root_type))
476                         root_type = enclosing_type;
477
478                 // If this is a typedef we might have a name for the type, otherwise it's a signature based name
479                 if (root_type && TYPE_IDENTIFIER(root_type)) {
480                         generate(" type => 'call:%s', ", value_name(root_type));
481                 } else {
482                         // note it is added to todump in reverse
483                         buffer_init(&b, 256);
484                         export_desc(field, field_type, &b);
485                         list_addhead(&todump, node_alloc(field_type, b.data));
486                         generate(" type => 'call:%s', ", b.data);
487                         if (debug_level > 0) {
488                                 fprintf(stderr, "save for later param type %p root type %p '%s'\n", field_type, root_type, b.data);
489
490                                 if (root_type) {
491                                         fprintf(stderr, "type is '%s\n", ZTREE_CODE(root_type));
492                                         fprintf(stderr, "type name is '%s'\n", TYPE_IDENTIFIER(root_type) ? IDENTIFIER_POINTER(TYPE_IDENTIFIER(root_type)) : "<anon>");
493                                         fprintf(stderr, "target is '%s'\n", ZTREE_CODE(target_type(root_type)));
494                                 }
495                         }
496                 }
497
498                 buffer_init(&b, 256);
499                 export_cdesc(field, field_type, &b);
500                 free(b.data);
501
502                 break;
503         }
504         case REAL_TYPE:
505                 generate(" ctype => '%s',", value_name(field_type));
506                 generate(" type => 'f%zu',", field_size);
507                 break;
508         case INTEGER_TYPE:
509                 if (TREE_CODE(field) == FIELD_DECL && DECL_BIT_FIELD(field)) {
510                         generate(" ctype => 'bitfield',");
511                         generate(" type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', value_size(DECL_SIZE(field)));
512                 } else {
513                         generate(" ctype => '%s',", value_name(field_type));
514                         generate(" type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', field_size);
515                 }
516                 break;
517         case RECORD_TYPE:
518         case UNION_TYPE: {
519                 const char *us = TREE_CODE(field_type) == RECORD_TYPE ? "struct" : "union";
520
521                 if (TYPE_IDENTIFIER(field_type)) {
522                         generate(" type => '%s:%s',", us, value_name(field_type));
523                 } else {
524                         char *name = stack_path(&context_stack, "_");
525
526                         list_add(&todump, node_alloc(field_type, name));
527                         generate(" type => '%s:%s',", us, name);
528                         free(name);
529                 }
530                 break;
531         }
532         default:
533                 fprintf(stderr, "unknown param type: %s\n", ZTREE_CODE(field_type));
534                 gcc_unreachable();
535         }
536 }
537
538 /*
539   Export a chain of parameters
540 */
541 static void export_params(tree func) {
542         int id = 0;
543         char nameb[32];
544         struct list args = { 0 };
545         struct node *name;
546         struct node *fwd = hash_lookup_bytype(&forward_types, func);
547
548         if (fwd) {
549                 // use the forward reference to find the names
550                 if (debug_level > 0)
551                         fprintf(stderr, "found forward reference @ %p\n", fwd);
552                 name = fwd->list.head;
553         } else {
554                 // paramter names are in the paramters list
555                 // but they are in reverse order
556                 int id = 0;
557                 for (tree param = TYPE_ARG_TYPES(func); param; param = TREE_CHAIN(param)) {
558                         tree param_type = TREE_VALUE(param);
559
560                         if (!TREE_CHAIN(param) && TREE_CODE(param_type) == VOID_TYPE) {
561                                 if (id == 0) {
562                                         struct node *decl = stack_pull(&parameters);
563                                         if (debug_level > 0)
564                                                 fprintf(stderr, "(pull parameter dummy '%s')\n", decl->name);
565                                 }
566                                 break;
567                         }
568
569                         struct node *decl = stack_pull(&parameters);
570                         if (decl) {
571                                 if (debug_level > 0)
572                                         fprintf(stderr, "(pull parameter args '%s')\n", decl->name);
573                                 stack_push(&args, decl);
574                         } else
575                                 fprintf(stderr, "ERROR: parameter %d missing parameter declaration\n", id);
576                         id++;
577                 }
578                 name = args.head;
579         }
580
581         for (tree param = TYPE_ARG_TYPES(func); param; param = TREE_CHAIN(param)) {
582                 tree param_type = TREE_VALUE(param);
583                 const size_t data_size = value_size(TYPE_SIZE(param_type));
584                 const char *names = NULL;
585
586                 // non-varags functions end in VOID_TYPE
587                 if (!TREE_CHAIN(param) && TREE_CODE(param_type) == VOID_TYPE)
588                         break;
589
590                 generate("\t\t{");
591
592                 // size: do we need it?
593                 generate(" size => %zu,", data_size);
594
595                 if (name) {
596                         // this should be a parm_decl with an identifier of the name
597                         names = name->name;
598
599                         // can one check it's a matching type?
600                         name = name->next;
601                 }
602
603                 if (!names || !names[0]) {
604                         sprintf(nameb, "arg$%d", id);
605                         names = nameb;
606                 }
607
608                 generate(" name => '%s',", names);
609                 stack_push(&context_stack, node_alloc(param, names));
610
611                 // value: details
612                 export_param(param, param_type, data_size);
613
614                 free(stack_pull(&context_stack));
615
616                 generate("},\n");
617                 id++;
618         }
619
620         list_clear(&args);
621 }
622
623 /*
624   Export a chain of fields.
625 */
626 static void export_fields(tree first_field, size_t base_offset, int indent) {
627         for (tree field = first_field; field; field = TREE_CHAIN(field)) {
628                 gcc_assert(TREE_CODE(field) == FIELD_DECL);
629
630                 tree field_type = TREE_TYPE(field);
631                 const size_t field_size = value_size(DECL_SIZE(field));
632                 size_t offset = base_offset + tree_to_uhwi(DECL_FIELD_OFFSET(field)) * 8 + tree_to_uhwi(DECL_FIELD_BIT_OFFSET(field));
633
634                 // name: if none, then inline
635                 if (!DECL_NAME(field)) {
636                         if (is_struct_or_union(field_type))
637                                 export_fields(TYPE_FIELDS(field_type), offset, indent);
638                 } else {
639                         const char *names = IDENTIFIER_POINTER(DECL_NAME(field));
640
641                         if (debug_level > 1)
642                                 fprintf(stderr, "   field: %s\n", names);
643                         print_spaces(indent+1);
644                         generate("{ name => '%s', size => %zu, offset => %zu,", names, field_size, offset);
645                         stack_push(&context_stack, node_alloc(field, names));
646
647                         // value: details
648                         export_param(field, field_type, field_size);
649
650                         free(stack_pull(&context_stack));
651
652                         generate("},\n");
653                 }
654         }
655 }
656
657 /*
658   Main entry point for exporting any type.
659 */
660 static void export_type(tree type, const char *names) {
661         tree name;
662         tree deftype;
663         tree target;
664
665         if (debug_level > 1)
666                 fprintf(stderr, "export_type(%s, %s)\n", ZTREE_CODE(type), names);
667
668         switch (TREE_CODE(type)) {
669         case TYPE_DECL: {
670                 if (!names) {
671                         name = DECL_NAME(type);
672                         if (!name)
673                                 return;
674                         names = IDENTIFIER_POINTER(name);
675                 }
676                 if (hash_lookup(&dumped, names))
677                         return;
678                 hash_put(&dumped, node_alloc(type, names));
679
680                 if (debug_level > 1)
681                         fprintf(stderr, "export: %s %s\n", names, ZTREE_CODE(type));
682
683                 deftype = TREE_TYPE(type);
684                 target = target_type(deftype);
685                 switch (TREE_CODE(target)) {
686                 case FUNCTION_TYPE: {
687                         // function pointer typdef
688                         // I don't know if i even want this
689                         generate("'call:%s' => { name => '%s', type => 'call',", names, names);
690
691                         // the deftype is always a pointer for a function_type
692
693                         struct buffer b;
694
695                         buffer_init(&b, 256);
696                         export_desc(type, deftype, &b);
697                         generate(" deref => '%s',", b.data);
698                         free(b.data);
699
700                         generate(" ctype => '%s',", print_generic_expr_to_str(target));
701
702                         // TODO: cleanup
703                         {
704                                 tree result_type = TREE_TYPE(target);
705                                 const size_t data_size = value_size(TYPE_SIZE(result_type));
706
707                                 generate("\n\tresult => {");
708                                 export_param(target, result_type, data_size);
709                                 generate(" },");
710                         }
711
712                         generate("\n\targuments => [\n");
713                         export_params(target);
714                         generate("]},\n");
715                         break;
716                 }
717                 case ENUMERAL_TYPE: {
718                         // TODO: typedef of anonymous enumerations may be repeated
719                         // TODO: this could be detected in the frontend - e.g. don't include any
720                         // TODO: anon enum values if any are already there
721                         // TODO: or maybe duplicates could be detected here
722                         size_t size = tree_to_uhwi(TYPE_SIZE(target));
723
724                         if (size > 64) {
725                                 fprintf(stderr, "Warning: enum '%s' requires too many bits (%zu)\n", names, size);
726                                 return;
727                         }
728
729                         generate("'enum:%s' => { name => '%s', type => 'enum', size => %zu, value_type => '%c%zu', values => [\n",
730                                 names, names, size, TYPE_UNSIGNED(target) ? 'u' : 'i', size);
731
732                         for (tree v = TYPE_VALUES(target); v != NULL; v = TREE_CHAIN (v)) {
733                                 generate("\t{ name => '%s', value => '%ld' },\n",
734                                         IDENTIFIER_POINTER(TREE_PURPOSE(v)),
735                                         tree_to_shwi(TREE_VALUE(v)));
736                         }
737                         generate("]},\n");
738                         break;
739                 }
740                 case RECORD_TYPE: // forward declaration or opaque types
741                 case UNION_TYPE:
742                 case VOID_TYPE:
743                 case INTEGER_TYPE:
744                 case REAL_TYPE:
745                         if (debug_level)
746                                 fprintf(stderr, "ignored %s: %s\n", ZTREE_CODE(target), names);
747                         break;
748                 default:
749                         fprintf(stderr, "unknown type def: %s\n", ZTREE_CODE(target));
750                         gcc_unreachable();
751                 }
752
753                 break;
754         }
755         case FUNCTION_DECL: {
756                 if (!names) {
757                         name = DECL_NAME(type);
758                         if (!name)
759                                 return;
760                         names = IDENTIFIER_POINTER(name);
761                 }
762                 if (hash_lookup(&dumped, names))
763                         return;
764                 hash_put(&dumped, node_alloc(type, names));
765
766                 if (debug_level > 1)
767                         fprintf(stderr, "export type func decl %s\n", names);
768
769                 generate("'func:%s' => { name => '%s', type => 'func',", names, names);
770
771                 // FUNCTION_DECL -> FUNCTION_TYPE -> RESULT_TYPE, get FUNCTION_TYPE
772                 type = TREE_TYPE(type);
773
774                 generate(" ctype => '%s',", print_generic_expr_to_str(type));
775
776                 // TODO: cleanup
777                 debug_tree_helper(type, "function 1");
778                 {
779                         tree result_type = TREE_TYPE(type);
780                         const size_t data_size = value_size(TYPE_SIZE(result_type));
781
782                         generate("\n\tresult => {");
783                         export_param(type, result_type, data_size);
784                         generate(" },");
785                 }
786
787                 generate("\n\targuments => [\n");
788                 //export_decl_params(DECL_ARGUMENTS(type), 0);
789                 export_params(type);
790                 generate("]},\n");
791                 break;
792         }
793         case FUNCTION_TYPE: {
794                 int output_save = output_enabled;
795
796                 // This is called for un-typedef'd function pointers.
797                 // WHY IS THIS DIFFERENT TO ABOVE?
798                 if (!names) {
799                         name = TYPE_IDENTIFIER(type);
800                         if (!name)
801                                 return;
802                         names = IDENTIFIER_POINTER(name);
803                 }
804                 if (hash_lookup(&dumped, names)) {
805                         if (debug_level > 0)
806                                 fprintf(stderr, " - type already output, supressing generation\n");
807                         output_enabled = 0;
808                 }
809                 hash_put(&dumped, node_alloc(type, names));
810
811                 if (debug_level > 1)
812                         fprintf(stderr, "export: %s %s\n", names, ZTREE_CODE(type));
813
814                 generate("'call:%s' => { name => '%s', type => 'call',", names, names);
815                 generate(" ctype => '%s',", print_generic_expr_to_str(type));
816
817                 debug_tree_helper(type, "function type");
818
819                 // TODO: cleanup
820                 // FUNCTION_TYPE -> RESULT_TYPE
821                 {
822                         tree result = TREE_TYPE(type);
823                         //tree result_type = TREE_TYPE(result);
824                         //printf(" result type type %s\n", ZTREE_CODE(result_type));
825                         const size_t data_size = value_size(TYPE_SIZE(result));
826
827                         if (debug_level > 2)
828                                 fprintf(stderr, " result size %zu\n", data_size);
829                         generate("\n\tresult => {");
830                         export_param(type, result, data_size);
831                         generate(" },");
832                 }
833
834                 stack_push(&context_stack, node_alloc(type, names));
835                 generate("\n\targuments => [\n");
836                 export_params(type);
837                 free(stack_pull(&context_stack));
838                 generate("]},\n");
839
840                 output_enabled = output_save;
841                 break;
842         }
843         case RECORD_TYPE: // struct
844         case UNION_TYPE: {
845                 const char *su = TREE_CODE(type) == RECORD_TYPE ? "struct" : "union";
846
847                 // ignore empty types
848                 if (!TYPE_FIELDS(type))
849                         return;
850
851                 if (!names) {
852                         name = TYPE_IDENTIFIER(type);
853                         if (!name)
854                                 return;
855                         names = IDENTIFIER_POINTER(name);
856                 }
857                 if (hash_lookup(&dumped, names))
858                         return;
859                 hash_put(&dumped, node_alloc(type, names));
860
861                 if (debug_level > 1)
862                         fprintf(stderr, "export: %s %s\n", names, ZTREE_CODE(type));
863
864                 generate("'%s:%s' => { name => '%s', type => '%s', size => %zu, fields => [\n",
865                         su, names, names, su, tree_to_uhwi(TYPE_SIZE(type)));
866
867                 stack_push(&context_stack, node_alloc(type, names));
868                 export_fields(TYPE_FIELDS(type), 0, 0);
869                 free(stack_pull(&context_stack));
870
871                 generate("]},\n");
872                 break;
873         }
874         case ENUMERAL_TYPE: {
875                 // FIXME: see ENUMERAL_TYPE above regarding duplicate anon enums
876
877                 // ignore empty enums
878                 if (!TYPE_VALUES(type))
879                         return;
880
881                 // We can only assume a non-named enum type isn't repeatedly sent here
882                 if (!names) {
883                         name = TYPE_IDENTIFIER(type);
884                         if (name)
885                                 names = IDENTIFIER_POINTER(name);
886                 }
887                 if (names) {
888                         if (hash_lookup(&dumped, names))
889                                 return;
890                         hash_put(&dumped, node_alloc(type, names));
891                 }
892
893                 size_t size = tree_to_uhwi(TYPE_SIZE(type));
894
895                 if (size > 64) {
896                         fprintf(stderr, "Warning: enum '%s' requires too many bits (%zu)\n", names, size);
897                         return;
898                 }
899
900                 // FIXME: choose a better anon name
901                 char nameb[64];
902                 static int namei;
903
904                 if (!names) {
905                         sprintf(nameb, "enum$%d", namei++);
906                         names = nameb;
907                 }
908
909                 if (debug_level > 1)
910                         fprintf(stderr, "export: %s %s\n", names, ZTREE_CODE(type));
911
912                 generate("'enum:%s' => { name => '%s', type => 'enum', size => %zu, value_type => '%c%zu', values => [\n",
913                         names, names, size, TYPE_UNSIGNED(type) ? 'u' : 'i', size);
914
915                 for (tree v = TYPE_VALUES(type); v != NULL; v = TREE_CHAIN (v)) {
916                         generate("\t{ name => '%s', value => '%ld' },\n",
917                                 IDENTIFIER_POINTER(TREE_PURPOSE(v)),
918                                 tree_to_shwi(TREE_VALUE(v)));
919                 }
920                 generate("]},\n");
921                 break;
922         }
923         case FIELD_DECL: {
924                 if (!names) {
925                         name = DECL_NAME(type);
926                         if (name)
927                                 names = IDENTIFIER_POINTER(name);
928                 }
929
930                 deftype = TREE_TYPE(type);
931                 target = target_type(deftype);
932
933                 if (debug_level > 1) {
934                         fprintf(stderr, "field_decl type is '%s\n", ZTREE_CODE(deftype));
935                         fprintf(stderr, "type name is '%s'\n", TYPE_IDENTIFIER(deftype) ? IDENTIFIER_POINTER(TYPE_IDENTIFIER(deftype)) : "<anon>");
936                         fprintf(stderr, "target is '%s'\n", ZTREE_CODE(target));
937                 }
938
939                 // nb almost same as next case below, but we don't save the param info here
940                 if (TREE_CODE(target) == FUNCTION_TYPE && !TYPE_IDENTIFIER(deftype)) {
941                         // We need to save the list of parameters for later,
942                         // it's keyed on target
943                         struct node *fwd = node_alloc(target, NULL);
944
945                         if (debug_level > 0) {
946                                 struct buffer b;
947
948                                 buffer_init(&b, 256);
949                                 export_desc(deftype, target, &b);
950
951                                 fprintf(stderr, "save forward reference field function type %p '%s' '%s'\n", target, names, b.data);
952                                 // or should be todump?
953                                 free(b.data);
954                         }
955
956                         for (tree param = TYPE_ARG_TYPES(target); param != NULL; param = TREE_CHAIN(param)) {
957                                 tree param_type = TREE_VALUE(param);
958
959                                 if (TREE_CODE(param_type) == VOID_TYPE)
960                                         break;
961
962                                 struct node *decl = stack_pull(&parameters);
963                                 if (decl) {
964                                         if (debug_level > 0)
965                                                 fprintf(stderr, "(pull parameter '%s')\n", decl->name);
966                                         stack_push(&fwd->list, decl);
967                                 } else
968                                         fprintf(stderr, "WARNING: stack is missing parameter name function %s\n", names);
969                         }
970
971                         hash_put_bytype(&forward_types, fwd);
972
973                         // make sure it's dumped somewhere
974                         // what if it's a typedef?
975
976                         // ... we don't know if'ts a typedef though right?
977                         // note it is added to todump in reverse
978                         if (0) {
979                                 struct buffer b;
980
981                                 buffer_init(&b, 256);
982                                 export_desc(deftype, target, &b);
983                                 list_addhead(&todump, node_alloc(target, b.data));
984
985                                 if (debug_level > 0)
986                                         fprintf(stderr, "save for later param type %p '%s'\n", target, b.data);
987
988                                 free(b.data);
989                         }
990                 }
991
992                 break;
993         }
994         case PARM_DECL: {
995                 // capture PARM_DECLs so they can be used at next function declaration
996                 if (!names) {
997                         name = DECL_NAME(type);
998                         if (name)
999                                 names = IDENTIFIER_POINTER(name);
1000                 }
1001                 // if this is a function pointer typedef, need to suck out the arguments at this point
1002                 deftype = TREE_TYPE(type);
1003                 target = target_type(deftype);
1004
1005                 if (debug_level > 1) {
1006                         fprintf(stderr, "type is '%s\n", ZTREE_CODE(deftype));
1007                         fprintf(stderr, "type name is '%s'\n", TYPE_IDENTIFIER(deftype) ? IDENTIFIER_POINTER(TYPE_IDENTIFIER(deftype)) : "<anon>");
1008                         fprintf(stderr, "target is '%s'\n", ZTREE_CODE(target));
1009                 }
1010
1011                 if (TREE_CODE(target) == FUNCTION_TYPE && !TYPE_IDENTIFIER(deftype)) {
1012                         // We need to save the list of parameters for later,
1013                         // it's keyed on target
1014                         struct node *fwd = node_alloc(target, NULL);
1015
1016                         if (debug_level > 0) {
1017                                 struct buffer b;
1018
1019                                 buffer_init(&b, 256);
1020                                 export_desc(deftype, target, &b);
1021
1022                                 fprintf(stderr, "save forward reference function type %p '%s' '%s'\n", target, names, b.data);
1023                                 free(b.data);
1024                         }
1025
1026                         for (tree param = TYPE_ARG_TYPES(target); param != NULL; param = TREE_CHAIN(param)) {
1027                                 tree param_type = TREE_VALUE(param);
1028
1029                                 if (TREE_CODE(param_type) == VOID_TYPE)
1030                                         break;
1031
1032                                 struct node *decl = stack_pull(&parameters);
1033                                 if (decl) {
1034                                         if (debug_level > 0)
1035                                                 fprintf(stderr, "(pull parameter '%s')\n", decl->name);
1036                                         stack_push(&fwd->list, decl);
1037                                 } else
1038                                         fprintf(stderr, "WARNING: stack is missing parameter name function %s\n", names);
1039                         }
1040
1041                         hash_put_bytype(&forward_types, fwd);
1042
1043                         // make sure it's dumped somewhere
1044                         // what if it's a typedef?
1045
1046                         // ... we don't know if'ts a typedef though right?
1047                         // note it is added to todump in reverse
1048                         if (1) {
1049                                 struct buffer b;
1050
1051                                 buffer_init(&b, 256);
1052                                 export_desc(deftype, target, &b);
1053                                 list_addhead(&todump, node_alloc(target, b.data));
1054
1055                                 if (debug_level > 0)
1056                                         fprintf(stderr, "save for later param type %p '%s'\n", target, b.data);
1057
1058                                 free(b.data);
1059                         }
1060
1061                 }
1062
1063                 if (debug_level > 0)
1064                         fprintf(stderr, "(push parameter '%s')\n", names);
1065                 stack_push(&parameters, node_alloc(type, names));
1066
1067                 break; }
1068         case VAR_DECL:
1069                 // global external variables, might want these
1070                 // well, if there's a way to resolve them
1071                 break;
1072         default:
1073                 fprintf(stderr, "unknown export: %s\n", ZTREE_CODE(type));
1074                 gcc_unreachable();
1075         }
1076 }
1077
1078 static void plugin_finish_type(void *event_data, void *user_data) {
1079         tree type = (tree)event_data;
1080
1081         if (debug_level > 0)
1082                 fprintf(stderr, "finish_type\n");
1083         if (debug_level > 1)
1084                 debug_tree(type);
1085
1086         export_type(type, NULL);
1087 }
1088
1089 static void plugin_finish_decl(void *event_data, void *user_data) {
1090         tree type = (tree)event_data;
1091
1092         if (debug_level > 0)
1093                 fprintf(stderr, "finish_decl %s\n", ZTREE_CODE(type));
1094         if (debug_level > 1)
1095                 debug_tree(type);
1096
1097         export_type(type, NULL);
1098 }
1099
1100 static void plugin_finish(void *event_data, void *user_data) {
1101         if (debug_level > 0)
1102                 fprintf(stderr, "\n\n----------------------------------------\nplugin finish\n");
1103         generate("# forward references:\n");
1104         for (struct node *n = todump.head; n; n=n->next) {
1105                 if (COMPLETE_TYPE_P(n->type)) {
1106                         if (n->name[0]) {
1107                                 export_type(n->type, n->name);
1108                         } else {
1109                                 export_type(n->type, value_name(n->type));
1110                         }
1111                 }
1112         }
1113
1114         generate("# dumped structs:\n");
1115         for (struct node *n = dumped.list.head; n; n=n->next)
1116                 generate("# %s\n", n->name);
1117
1118         generate("}\n");
1119         fclose(output_file);
1120
1121         if (debug_level > 0)
1122                 fprintf(stderr, "unhandled paramters:\n");
1123         list_clear(&parameters);
1124 }
1125
1126 int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) {
1127         const char *output = NULL;
1128
1129         for (int i = 0; i < plugin_info->argc; ++i) {
1130                 if (0 == strcmp(plugin_info->argv[i].key, "output")) {
1131                         output = plugin_info->argv[i].value;
1132                 } else if (0 == strcmp(plugin_info->argv[i].key, "debug")) {
1133                         debug_level = atoi(plugin_info->argv[i].value);
1134                 }
1135         }
1136
1137         if (NULL == output) {
1138                 fprintf(stderr, "export plugin: missing parameter: -fplugin-arg-export-output=<output>\n");
1139                 exit(EXIT_FAILURE);
1140         }
1141
1142         output_file = fopen(output, "w");
1143         if (NULL == output_file) {
1144                 perror(output);
1145                 exit(EXIT_FAILURE);
1146         }
1147
1148         generate("{\n");
1149
1150         register_callback(plugin_info->base_name, PLUGIN_FINISH_DECL, plugin_finish_decl, NULL);
1151         register_callback(plugin_info->base_name, PLUGIN_FINISH_TYPE, plugin_finish_type, NULL);
1152         register_callback(plugin_info->base_name, PLUGIN_FINISH, plugin_finish, NULL);
1153
1154         return 0;
1155 }