ed1950184ea4c56b6c7c7033a28f2f91f86f1861
[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 Michael Zucchi
6  *
7  * The MIT License (MIT)
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25  * THE SOFTWARE.
26  */
27
28 /*
29    skeleton taken from structsizes.cc plugin by Richard W.M. Jones
30    https://rwmj.wordpress.com/2016/02/24/playing-with-gcc-plugins/
31    some other bits from
32    https://blog.adacore.com/bindings-gcc-plugins
33  */
34
35 /*
36
37 function declarations, i think
38
39                   chain            param type                 name              size
40 TYPE_DECL         TYPE_ARG_TYPES   TYPE_VALUE(item):TREE_LIST  <empty>           TYPE_SIZE(item_type)
41  /POINTER
42  /FUNCTION_TYPE
43 FUNCTION_DECL     DECL_ARGUENTS    TREE_TYPE(item):PARM_DECL   DECL_NAME(item)   DECL_SIZE(item)
44                                                                                  TYPE_SIZE(item_type)
45  */
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <gcc-plugin.h>
51 #include <tree.h>
52 #include <print-tree.h>
53
54 #include "tree-codes.h"
55 #include "list.h"
56
57 #define D(x) do { x; } while(0)
58
59 //Enums have a type, otherwise they're just integers
60 //#define TYPED_ENUMS
61
62 // remove some of the debug
63 //#define NDEBUG
64
65 int plugin_is_GPL_compatible; // must be defined for the plugin to run
66
67 static FILE *output_file;
68
69 static void debug_tree_helper(tree t, const char *msg) {
70 #ifndef NDEBUG
71         fflush(stdout);
72         fprintf(stderr, "dumping tree: '%s'\n", msg);
73         debug_tree(t);
74         fprintf(stderr, "\n\n");
75         fflush(stdout);
76 #endif
77 }
78
79 static struct hash dumped;
80 static struct list todump;
81 static struct list context_stack;
82
83 /*
84   Join all names in the stack, in reverse order.
85  */
86 static char *stack_path(struct list *stack, const char *sep) {
87         size_t total = 1;
88
89         for (struct node *n = stack->tail; n; n=n->link)
90                 total += strlen(n->name)+strlen(sep);
91
92         char *data = (char *)xmalloc(total);
93         char *p = data;
94
95         // FIXME: some other context name
96         for (struct node *n = stack->tail; n; n=n->link) {
97                 p = stpcpy(p, n->name);
98                 if (n->link)
99                         p = stpcpy(p, sep);
100         }
101
102         return data;
103 }
104
105 // returns 0 if type has no size (i.e VOID_TYPE)
106 static bool is_struct_or_union(const_tree type) {
107     return RECORD_TYPE == TREE_CODE(type) || UNION_TYPE == TREE_CODE(type);
108 }
109
110 static void print_spaces(int n) {
111     for (int i = 0; i < n; ++i)
112         fputc('\t', output_file);
113 }
114
115 static int is_ref_type(tree type) {
116         switch (TREE_CODE(type)) {
117         case VECTOR_TYPE:
118         case ARRAY_TYPE:
119         case POINTER_TYPE:
120         case REFERENCE_TYPE:
121                 return 1;
122         default:
123                 return 0;
124         }
125 }
126
127 static tree target_type(tree type) {
128         while (is_ref_type(type))
129                 type = TREE_TYPE(type);
130         return type;
131 }
132
133 static size_t value_size(tree n) {
134         return n ? tree_to_uhwi(n) : 0;
135 }
136
137 static const char *value_name(tree type) {
138         tree test = TYPE_IDENTIFIER(type);
139         const char *value = test ? IDENTIFIER_POINTER(test) : NULL;
140
141         // __va_list_tag is the final type beneath __builtin_va_list.
142         // it behaves different from other types - it has a TYPE_MAIN_VARIANT, but the main TYPE_NAME seems to give
143         // an unexpected tree, and therefore ORIG_TYPE_NAME returns a garbage value.
144         // I think this patch is good enough.
145         if (value && 0 == strcmp("__va_list_tag", value))
146                 return "__va_list_tag";
147
148         test = TYPE_MAIN_VARIANT(type);
149         test = test ? TYPE_NAME(test) : test;
150         test = test && TREE_CODE(test) == TYPE_DECL ? DECL_NAME(test) : test;
151
152         return test ? IDENTIFIER_POINTER(test) : value;
153 }
154
155 /*
156   Find a non-ref type in the type chain, i.e. skip pointers/arrays.
157  */
158 static tree simple_type(tree t) {
159         while (is_ref_type(t))
160                 t = TREE_TYPE(t);
161         return t;
162 }
163
164 /*
165   Create a 'panama' signature for a single type.
166  */
167 static void export_desc(tree field, tree field_type, struct buffer *b) {
168         const size_t data_size = value_size(TYPE_SIZE(field_type));
169
170         switch (TREE_CODE(field_type)) {
171         case VOID_TYPE:
172                 buffer_add(b, "v");
173                 break;
174         case VECTOR_TYPE:
175         case ARRAY_TYPE: {
176                 const size_t elem_size = tree_to_uhwi(TYPE_SIZE_UNIT(TREE_TYPE(field_type)));
177                 size_t num_elem;
178
179                 if (elem_size == 0 || NULL == TYPE_SIZE_UNIT(field_type)) {
180                         // it is a flexible array or empty types
181                         num_elem = 0;
182                 } else {
183                         // it might be 0 / elem_size, in which case we also end up with num_elem = 0.
184                         num_elem = tree_to_uhwi(TYPE_SIZE_UNIT(field_type)) / elem_size;
185                 }
186
187                 buffer_room(b, 16);
188                 b->pos += sprintf(b->data + b->pos, "[%zu", num_elem);
189                 export_desc(field, TREE_TYPE(field_type), b);
190                 buffer_add(b, "]");
191                 break;
192         }
193         case POINTER_TYPE:
194         case REFERENCE_TYPE:
195                 buffer_room(b, 16);
196                 b->pos += sprintf(b->data + b->pos, "u%zu:", data_size);
197                 export_desc(field, TREE_TYPE(field_type), b);
198                 break;
199         case FUNCTION_TYPE: {
200                 // TODO: handle void f() type -> null TYPE_ARG_TYPES()
201                 tree return_type = TREE_TYPE(field_type);
202
203                 buffer_add(b, "(");
204                 for (tree param = TYPE_ARG_TYPES(field_type); param != NULL; param = TREE_CHAIN(param)) {
205                         tree param_type = TREE_VALUE(param);
206
207                         if (TREE_CODE(param_type) == VOID_TYPE)
208                                 break;
209
210                         export_desc(param, param_type, b);
211                 }
212                 buffer_add(b, ")");
213                 export_desc(field, return_type, b);
214                 break;
215         }
216         case ENUMERAL_TYPE:
217 #if defined(TYPED_ENUMS)
218                 buffer_add(b, "${");
219                 buffer_add(b, TYPE_IDENTIFIER(field_type) ? value_name(field_type) : "enum");
220                 buffer_add(b, "}");
221 #else
222                 buffer_room(b, 16);
223                 b->pos += sprintf(b->data + b->pos, "%c%zu",
224                                   TYPE_UNSIGNED(field_type) ? 'u' : 'i',
225                                   data_size);
226 #endif
227                 break;
228         case RECORD_TYPE:
229         case UNION_TYPE:
230                 if (TYPE_IDENTIFIER(field_type)) {
231                         list_add(&todump, node_alloc(field_type, NULL));
232
233                         buffer_add(b, "${");
234                         buffer_add(b, value_name(field_type));
235                         buffer_add(b, "}");
236                 } else {
237                         char *name = stack_path(&context_stack, "_");
238
239                         list_add(&todump, node_alloc(field_type, name));
240
241                         buffer_add(b, "${");
242                         buffer_add(b, name);
243                         buffer_add(b, "}");
244
245                         free(name);
246                 }
247                 break;
248         case REAL_TYPE:
249                 buffer_room(b, 16);
250                 b->pos += sprintf(b->data + b->pos, "f%zu", data_size);
251                 break;
252         case INTEGER_TYPE:
253                 buffer_room(b, 16);
254                 b->pos += sprintf(b->data + b->pos, "%c%zu",
255                                   TYPE_UNSIGNED(field_type) ? 'u' : 'i',
256                                   data_size);
257                 break;
258         default:
259                 debug_tree_helper(field_type, "unknown type!");
260                 gcc_unreachable();
261                 break;
262         }
263 }
264
265 /*
266   Print a single parameter or field.
267  */
268 static void export_param(tree field, tree field_type, size_t field_size) {
269         switch (TREE_CODE(field_type)) {
270         case VECTOR_TYPE:
271         case ARRAY_TYPE:
272         case POINTER_TYPE:
273         case REFERENCE_TYPE: {
274                 struct buffer b;
275
276                 buffer_init(&b, 256);
277                 export_desc(field, field_type, &b);
278                 fprintf(output_file, " deref => '%s',", b.data);
279                 free(b.data);
280
281                 field_type = simple_type(field_type);
282                 field_size = value_size(TYPE_SIZE(field_type));
283
284                 export_param(field, field_type, field_size);
285                 break;
286         }
287         case VOID_TYPE:
288                 fprintf(output_file, " type => 'void',");
289                 break;
290         case ENUMERAL_TYPE: {
291 #if defined(TYPED_ENUMS)
292                 const char *names = TYPE_IDENTIFIER(field_type) ? value_name(field_type) : "enum";
293                 fprintf(output_file, " type => 'enum:%s',", names);
294 #else
295                 fprintf(output_file, " type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', field_size);
296 #endif
297                 break;
298         }
299         case FUNCTION_TYPE: {
300                 // If the function is a typedef we could use the name
301                 // but it's a pain to find up the tree, so don't bother.
302                 // Use the signature instead.  This is what jextract appears to use.
303                 struct buffer b;
304
305                 //char *name = stack_path(&context_stack);
306                 //fprintf(output_file, " type => 'call:%s', ", name);
307                 //free(name);
308
309                 buffer_init(&b, 256);
310
311                 export_desc(field, field_type, &b);
312                 list_add(&todump, node_alloc(field_type, b.data));
313                 fprintf(output_file, " type => 'call:%s', ", b.data);
314
315                 free(b.data);
316
317                 break;
318         }
319         case REAL_TYPE:
320                 fprintf(output_file, " ctype => '%s',", value_name(field_type));
321                 fprintf(output_file, " type => 'f%zu',", field_size);
322                 break;
323         case INTEGER_TYPE:
324                 if (TREE_CODE(field) == FIELD_DECL && DECL_BIT_FIELD(field)) {
325                         fprintf(output_file, " ctype => 'bitfield',");
326                         fprintf(output_file, " type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', value_size(DECL_SIZE(field)));
327                 } else {
328                         fprintf(output_file, " ctype => '%s',", value_name(field_type));
329                         fprintf(output_file, " type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', field_size);
330                 }
331                 break;
332         case RECORD_TYPE:
333         case UNION_TYPE: {
334                 const char *us = TREE_CODE(field_type) == RECORD_TYPE ? "struct" : "union";
335
336                 if (TYPE_IDENTIFIER(field_type)) {
337                         fprintf(output_file, " type => '%s:%s',", us, value_name(field_type));
338                 } else {
339                         char *name = stack_path(&context_stack, "_");
340
341                         list_add(&todump, node_alloc(field_type, name));
342                         fprintf(output_file, " type => '%s:%s',", us, name);
343                         free(name);
344                 }
345                 break;
346         }
347         default:
348                 printf("unknown param type: %s\n", ZTREE_CODE(field_type));
349                 gcc_unreachable();
350         }
351 }
352
353 /*
354   Export a chain of parameters
355 */
356 static void export_params(tree first_param, size_t indent_level) {
357         int id = 0;
358         char nameb[16];
359         const char *names = nameb;
360
361         for (tree param = first_param; param; param = TREE_CHAIN(param)) {
362                 tree param_type = TREE_VALUE(param);
363                 const size_t data_size = value_size(TYPE_SIZE(param_type));
364
365                 // non-varags functions end in VOID_TYPE
366                 if (!TREE_CHAIN(param) && TREE_CODE(param_type) == VOID_TYPE)
367                         break;
368
369                 fprintf(output_file, "\t\t{");
370
371                 // size: do we need it?
372                 fprintf(output_file, " size => %zu,", data_size);
373
374                 // name: none available, use position
375                 sprintf(nameb, "arg_%d", id);
376
377                 fprintf(output_file, " name => '%s',", names);
378                 stack_push(&context_stack, node_alloc(param, names));
379
380                 // value: details
381                 export_param(param, param_type, data_size);
382
383                 free(stack_pull(&context_stack));
384
385                 fprintf(output_file, "},\n");
386                 id++;
387         }
388 }
389
390 /*
391   Export a chain of fields.
392 */
393 static void export_fields(tree first_field, size_t base_offset, int indent) {
394         for (tree field = first_field; field; field = TREE_CHAIN(field)) {
395                 gcc_assert(TREE_CODE(field) == FIELD_DECL);
396
397                 tree field_type = TREE_TYPE(field);
398                 const size_t field_size = value_size(DECL_SIZE(field));
399                 size_t offset = base_offset + tree_to_uhwi(DECL_FIELD_OFFSET(field)) * 8 + tree_to_uhwi(DECL_FIELD_BIT_OFFSET(field));
400
401                 // name: if none, then inline
402                 if (!DECL_NAME(field)) {
403                         if (is_struct_or_union(field_type))
404                                 export_fields(TYPE_FIELDS(field_type), offset, indent);
405                 } else {
406                         const char *names = IDENTIFIER_POINTER(DECL_NAME(field));
407
408                         printf("   name=%s\n", names);
409                         print_spaces(indent+1);
410                         fprintf(output_file, "{ name => '%s', size => %zu, offset => %zu,", names, field_size, offset);
411                         stack_push(&context_stack, node_alloc(field, names));
412
413                         // value: details
414                         export_param(field, field_type, field_size);
415
416                         free(stack_pull(&context_stack));
417
418                         fprintf(output_file, "},\n");
419                 }
420         }
421 }
422
423 /*
424   Main entry point for exporting any type.
425 */
426 static void export_type(tree type, const char *names) {
427         tree name;
428         tree deftype;
429         tree target;
430
431         D(printf("export: %s %s\n", names, ZTREE_CODE(type)));
432
433         switch (TREE_CODE(type)) {
434         case TYPE_DECL: {
435                 if (!names) {
436                         name = DECL_NAME(type);
437                         if (!name)
438                                 return;
439                         names = IDENTIFIER_POINTER(name);
440                 }
441                 if (hash_lookup(&dumped, names))
442                         return;
443                 hash_put(&dumped, node_alloc(type, names));
444
445                 deftype = TREE_TYPE(type);
446                 target = target_type(deftype);
447                 switch (TREE_CODE(target)) {
448                 case FUNCTION_TYPE: {
449                         // I don't know if i even want this
450
451                         fprintf(output_file, "'call:%s' => { name => '%s',", names, names);
452
453                         // the deftype is always a pointer for a function_type
454
455                         struct buffer b;
456
457                         buffer_init(&b, 256);
458                         export_desc(type, deftype, &b);
459                         fprintf(output_file, " deref => '%s',", b.data);
460                         free(b.data);
461
462                         // TODO: cleanup
463                         {
464                                 tree result_type = TREE_TYPE(target);
465                                 const size_t data_size = value_size(TYPE_SIZE(result_type));
466
467                                 fprintf(output_file, "\n\tresult => {");
468                                 export_param(target, result_type, data_size);
469                                 fprintf(output_file, " },");
470                         }
471
472                         fprintf(output_file, "\n\targuments => [\n");
473                         export_params(TYPE_ARG_TYPES(target), 0);
474                         fprintf(output_file, "]},\n");
475                         break;
476                 }
477                 case RECORD_TYPE:
478                         printf(" typedef record: %s\n", names);
479                         break;
480                 case UNION_TYPE:
481                         printf(" typedef union: %s\n", names);
482                         break;
483                 case ENUMERAL_TYPE: {
484                         // TODO: typedef of anonymous enumerations may be repeated
485                         // TODO: this could be detected in the frontend - e.g. don't include any
486                         // TODO: anon enum values if any are already there
487                         // TODO: or maybe duplicates could be detected here
488                         size_t size = tree_to_uhwi(TYPE_SIZE(target));
489
490                         if (size > 64) {
491                                 fprintf(stderr, "Warning: enum '%s' requires too many bits (%zu)\n", names, size);
492                                 return;
493                         }
494
495                         fprintf(output_file, "'enum:%s' => { name => '%s', type => 'enum', size => %zu, value_type => '%c%zu', values => [\n",
496                                 names, names, size, TYPE_UNSIGNED(target) ? 'u' : 'i', size);
497
498                         for (tree v = TYPE_VALUES(target); v != NULL; v = TREE_CHAIN (v)) {
499                                 fprintf(output_file, "\t{ label => '%s', value => '%ld' },\n",
500                                         IDENTIFIER_POINTER(TREE_PURPOSE(v)),
501                                         tree_to_shwi(TREE_VALUE(v)));
502                         }
503                         fprintf(output_file, "]},\n");
504                         break;
505                 }
506                 case VOID_TYPE:
507                 case INTEGER_TYPE:
508                 case REAL_TYPE:
509                         break;
510                 default:
511                         printf("unknown type def: %s\n", ZTREE_CODE(target));
512                         gcc_unreachable();
513                 }
514
515                 break;
516         }
517         case FUNCTION_DECL: {
518                 if (!names) {
519                         name = DECL_NAME(type);
520                         if (!name)
521                                 return;
522                         names = IDENTIFIER_POINTER(name);
523                 }
524                 if (hash_lookup(&dumped, names))
525                         return;
526                 hash_put(&dumped, node_alloc(type, names));
527                 printf("export type func decl %s\n", names);
528
529                 fprintf(output_file, "'func:%s' => { name => '%s', type => 'func',", names, names);
530
531                 // FUNCTION_DECL -> FUNCTION_TYPE -> RESULT_TYPE, get FUNCTION_TYPE
532                 type = TREE_TYPE(type);
533
534                 // TODO: cleanup
535                 debug_tree_helper(type, "function 1");
536                 {
537                         tree result_type = TREE_TYPE(type);
538                         const size_t data_size = value_size(TYPE_SIZE(result_type));
539
540                         fprintf(output_file, "\n\tresult => {");
541                         export_param(type, result_type, data_size);
542                         fprintf(output_file, " },");
543                 }
544
545                 fprintf(output_file, "\n\targuments => [\n");
546                 //export_decl_params(DECL_ARGUMENTS(type), 0);
547                 export_params(TYPE_ARG_TYPES(type), 0);
548                 fprintf(output_file, "]},\n");
549                 break;
550         }
551         case FUNCTION_TYPE: {
552                 if (!names) {
553                         name = TYPE_IDENTIFIER(type);
554                         if (!name)
555                                 return;
556                         names = IDENTIFIER_POINTER(name);
557                 }
558                 if (hash_lookup(&dumped, names))
559                         return;
560                 hash_put(&dumped, node_alloc(type, names));
561                 printf("export type func %s\n", names);
562
563                 fprintf(output_file, "'call:%s' => { name => '%s', type => 'call',", names, names);
564
565                 debug_tree_helper(type, "function type");
566
567                 // TODO: cleanup
568                 // FUNCTION_TYPE -> RESULT_TYPE
569                 {
570                         tree result = TREE_TYPE(type);
571                         //tree result_type = TREE_TYPE(result);
572                         //printf(" result type type %s\n", ZTREE_CODE(result_type));
573                         const size_t data_size = value_size(TYPE_SIZE(result));
574
575                         printf(" result size %zu\n", data_size);
576                         fprintf(output_file, "\n\tresult => {");
577                         export_param(type, result, data_size);
578                         fprintf(output_file, " },");
579                 }
580
581                 stack_push(&context_stack, node_alloc(type, names));
582                 fprintf(output_file, "\n\targuments => [\n");
583                 export_params(TYPE_ARG_TYPES(type), 0);
584                 free(stack_pull(&context_stack));
585                 fprintf(output_file, "]},\n");
586                 break;
587         }
588         case RECORD_TYPE: // struct
589         case UNION_TYPE: {
590                 const char *su = TREE_CODE(type) == RECORD_TYPE ? "struct" : "union";
591
592                 // ignore empty types
593                 if (!TYPE_FIELDS(type))
594                         return;
595
596                 if (!names) {
597                         name = TYPE_IDENTIFIER(type);
598                         if (!name)
599                                 return;
600                         names = IDENTIFIER_POINTER(name);
601                 }
602                 if (hash_lookup(&dumped, names))
603                         return;
604                 hash_put(&dumped, node_alloc(type, names));
605
606                 fprintf(output_file, "'%s:%s' => { name => '%s', type => '%s', size => %zu, fields => [\n",
607                         su, names, names, su, tree_to_uhwi(TYPE_SIZE(type)));
608
609                 stack_push(&context_stack, node_alloc(type, names));
610                 export_fields(TYPE_FIELDS(type), 0, 0);
611                 free(stack_pull(&context_stack));
612
613                 fprintf(output_file, "]},\n");
614                 break;
615         }
616         case ENUMERAL_TYPE: {
617                 // FIXME: see ENUMERAL_TYPE above regarding duplicate anon enums
618
619                 // ignore empty enums
620                 if (!TYPE_VALUES(type))
621                         return;
622
623                 // We can only assume a non-named enum type isn't repeatedly sent here
624                 if (!names) {
625                         name = TYPE_IDENTIFIER(type);
626                         if (name)
627                                 names = IDENTIFIER_POINTER(name);
628                 }
629                 if (names) {
630                         if (hash_lookup(&dumped, names))
631                                 return;
632                         hash_put(&dumped, node_alloc(type, names));
633                 }
634
635                 size_t size = tree_to_uhwi(TYPE_SIZE(type));
636
637                 if (size > 64) {
638                         fprintf(stderr, "Warning: enum '%s' requires too many bits (%zu)\n", names, size);
639                         return;
640                 }
641
642                 // FIXME: choose a better anon name
643                 char nameb[64];
644                 static int namei;
645
646                 if (!names) {
647                         sprintf(nameb, "enum$%d", namei++);
648                         names = nameb;
649                 }
650                 fprintf(output_file, "'enum:%s' => { name => '%s', type => 'enum', size => %zu, value_type => '%c%zu', values => [\n",
651                         names, names, size, TYPE_UNSIGNED(type) ? 'u' : 'i', size);
652
653                 for (tree v = TYPE_VALUES(type); v != NULL; v = TREE_CHAIN (v)) {
654                         fprintf(output_file, "\t{ label => '%s', value => '%ld' },\n",
655                                 IDENTIFIER_POINTER(TREE_PURPOSE(v)),
656                                 tree_to_shwi(TREE_VALUE(v)));
657                 }
658                 fprintf(output_file, "]},\n");
659                 break;
660         }
661         case FIELD_DECL:
662         case PARM_DECL:
663                 break;
664         case VAR_DECL:
665                 // global external variables, might want these
666                 // well, if there's a way to resolve them
667                 break;
668         default:
669                 printf("unknown export: %s\n", ZTREE_CODE(type));
670                 gcc_unreachable();
671         }
672 }
673
674 static void plugin_finish_type(void *event_data, void *user_data) {
675         tree type = (tree)event_data;
676
677         export_type(type, NULL);
678 }
679
680 static void plugin_finish_decl(void *event_data, void *user_data) {
681         tree type = (tree)event_data;
682
683         export_type(type, NULL);
684 }
685
686 static void plugin_finish(void *event_data, void *user_data) {
687         for (struct node *n = todump.head; n; n=n->next) {
688                 if (COMPLETE_TYPE_P(n->type)) {
689                         if (n->name[0]) {
690                                 export_type(n->type, n->name);
691                         } else {
692                                 export_type(n->type, value_name(n->type));
693                         }
694                 }
695         }
696
697         fprintf(output_file, "# dumped structs:\n");
698         for (struct node *n = dumped.list.head; n; n=n->next)
699                 fprintf(output_file, "# %s\n", n->name);
700
701         fprintf(output_file, ");\n");
702         //fclose(output_file);
703 }
704
705 int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) {
706     const char *output = NULL;
707
708     for (int i = 0; i < plugin_info->argc; ++i) {
709         if (0 == strcmp(plugin_info->argv[i].key, "output")) {
710             output = plugin_info->argv[i].value;
711         }
712     }
713
714     if (NULL == output) {
715         fprintf(stderr, "export plugin: missing parameter: -fplugin-arg-export-output=<output>\n");
716         exit(EXIT_FAILURE);
717     }
718
719     output_file = fopen(output, "w");
720     if (NULL == output_file) {
721         perror(output);
722         exit(EXIT_FAILURE);
723     }
724
725     fprintf(output_file, "%%data = (\n");
726
727     register_callback(plugin_info->base_name, PLUGIN_FINISH_DECL, plugin_finish_decl, NULL);
728     register_callback(plugin_info->base_name, PLUGIN_FINISH_TYPE, plugin_finish_type, NULL);
729     register_callback(plugin_info->base_name, PLUGIN_FINISH, plugin_finish, NULL);
730
731     return 0;
732 }