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