godump.c (go_format_type): Check for invalid type names, pointer target types, and...
[gcc.git] / gcc / godump.c
1 /* Output Go language descriptions of types.
2 Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor <iant@google.com>.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 /* This file is used during the build process to emit Go language
22 descriptions of declarations from C header files. It uses the
23 debug info hooks to emit the descriptions. The Go language
24 descriptions then become part of the Go runtime support
25 library.
26
27 All global names are output with a leading underscore, so that they
28 are all hidden in Go. */
29
30 #include "config.h"
31 #include "system.h"
32 #include "coretypes.h"
33 #include "diagnostic-core.h"
34 #include "tree.h"
35 #include "ggc.h"
36 #include "pointer-set.h"
37 #include "obstack.h"
38 #include "debug.h"
39
40 /* We dump this information from the debug hooks. This gives us a
41 stable and maintainable API to hook into. In order to work
42 correctly when -g is used, we build our own hooks structure which
43 wraps the hooks we need to change. */
44
45 /* Our debug hooks. This is initialized by dump_go_spec_init. */
46
47 static struct gcc_debug_hooks go_debug_hooks;
48
49 /* The real debug hooks. */
50
51 static const struct gcc_debug_hooks *real_debug_hooks;
52
53 /* The file where we should write information. */
54
55 static FILE *go_dump_file;
56
57 /* A queue of decls to output. */
58
59 static GTY(()) VEC(tree,gc) *queue;
60
61 /* A hash table of macros we have seen. */
62
63 static htab_t macro_hash;
64
65 /* For the hash tables. */
66
67 static int
68 string_hash_eq (const void *y1, const void *y2)
69 {
70 return strcmp ((const char *) y1, (const char *) y2) == 0;
71 }
72
73 /* A macro definition. */
74
75 static void
76 go_define (unsigned int lineno, const char *buffer)
77 {
78 const char *p;
79 const char *name_end;
80 char *out_buffer;
81 char *q;
82 bool saw_operand;
83 bool need_operand;
84 char *copy;
85 hashval_t hashval;
86 void **slot;
87
88 real_debug_hooks->define (lineno, buffer);
89
90 /* Skip macro functions. */
91 for (p = buffer; *p != '\0' && *p != ' '; ++p)
92 if (*p == '(')
93 return;
94
95 if (*p == '\0')
96 return;
97
98 name_end = p;
99
100 ++p;
101 if (*p == '\0')
102 return;
103
104 copy = XNEWVEC (char, name_end - buffer + 1);
105 memcpy (copy, buffer, name_end - buffer);
106 copy[name_end - buffer] = '\0';
107
108 hashval = htab_hash_string (copy);
109 slot = htab_find_slot_with_hash (macro_hash, copy, hashval, NO_INSERT);
110 if (slot != NULL)
111 {
112 XDELETEVEC (copy);
113 return;
114 }
115
116 /* For simplicity, we force all names to be hidden by adding an
117 initial underscore, and let the user undo this as needed. */
118 out_buffer = XNEWVEC (char, strlen (p) * 2 + 1);
119 q = out_buffer;
120 saw_operand = false;
121 need_operand = false;
122 while (*p != '\0')
123 {
124 switch (*p)
125 {
126 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
127 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
128 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
129 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
130 case 'Y': case 'Z':
131 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
132 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
133 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
134 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
135 case 'y': case 'z':
136 case '_':
137 {
138 /* The start of an identifier. Technically we should also
139 worry about UTF-8 identifiers, but they are not a
140 problem for practical uses of -fdump-go-spec so we
141 don't worry about them. */
142 const char *start;
143 char *n;
144
145 if (saw_operand)
146 goto unknown;
147
148 start = p;
149 while (ISALNUM (*p) || *p == '_')
150 ++p;
151 n = XALLOCAVEC (char, p - start + 1);
152 memcpy (n, start, p - start);
153 n[p - start] = '\0';
154 slot = htab_find_slot (macro_hash, n, NO_INSERT);
155 if (slot == NULL || *slot == NULL)
156 {
157 /* This is a reference to a name which was not defined
158 as a macro. */
159 goto unknown;
160 }
161
162 *q++ = '_';
163 memcpy (q, start, p - start);
164 q += p - start;
165
166 saw_operand = true;
167 need_operand = false;
168 }
169 break;
170
171 case '.':
172 if (!ISDIGIT (p[1]))
173 goto unknown;
174 /* Fall through. */
175 case '0': case '1': case '2': case '3': case '4':
176 case '5': case '6': case '7': case '8': case '9':
177 {
178 const char *start;
179 bool is_hex;
180
181 start = p;
182 is_hex = false;
183 if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
184 {
185 p += 2;
186 is_hex = true;
187 }
188 while (ISDIGIT (*p) || *p == '.' || *p == 'e' || *p == 'E'
189 || (is_hex
190 && ((*p >= 'a' && *p <= 'f')
191 || (*p >= 'A' && *p <= 'F'))))
192 ++p;
193 memcpy (q, start, p - start);
194 q += p - start;
195 while (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L'
196 || *p == 'f' || *p == 'F'
197 || *p == 'd' || *p == 'D')
198 {
199 /* Go doesn't use any of these trailing type
200 modifiers. */
201 ++p;
202 }
203
204 /* We'll pick up the exponent, if any, as an
205 expression. */
206
207 saw_operand = true;
208 need_operand = false;
209 }
210 break;
211
212 case ' ': case '\t':
213 *q++ = *p++;
214 break;
215
216 case '(':
217 /* Always OK, not part of an operand, presumed to start an
218 operand. */
219 *q++ = *p++;
220 saw_operand = false;
221 need_operand = false;
222 break;
223
224 case ')':
225 /* OK if we don't need an operand, and presumed to indicate
226 an operand. */
227 if (need_operand)
228 goto unknown;
229 *q++ = *p++;
230 saw_operand = true;
231 break;
232
233 case '+': case '-':
234 /* Always OK, but not part of an operand. */
235 *q++ = *p++;
236 saw_operand = false;
237 break;
238
239 case '*': case '/': case '%': case '|': case '&': case '^':
240 /* Must be a binary operator. */
241 if (!saw_operand)
242 goto unknown;
243 *q++ = *p++;
244 saw_operand = false;
245 need_operand = true;
246 break;
247
248 case '=':
249 *q++ = *p++;
250 if (*p != '=')
251 goto unknown;
252 /* Must be a binary operator. */
253 if (!saw_operand)
254 goto unknown;
255 *q++ = *p++;
256 saw_operand = false;
257 need_operand = true;
258 break;
259
260 case '!':
261 *q++ = *p++;
262 if (*p == '=')
263 {
264 /* Must be a binary operator. */
265 if (!saw_operand)
266 goto unknown;
267 *q++ = *p++;
268 saw_operand = false;
269 need_operand = true;
270 }
271 else
272 {
273 /* Must be a unary operator. */
274 if (saw_operand)
275 goto unknown;
276 need_operand = true;
277 }
278 break;
279
280 case '<': case '>':
281 /* Must be a binary operand, may be << or >> or <= or >=. */
282 if (!saw_operand)
283 goto unknown;
284 *q++ = *p++;
285 if (*p == *(p - 1) || *p == '=')
286 *q++ = *p++;
287 saw_operand = false;
288 need_operand = true;
289 break;
290
291 case '~':
292 /* Must be a unary operand, must be translated for Go. */
293 if (saw_operand)
294 goto unknown;
295 *q++ = '^';
296 p++;
297 need_operand = true;
298 break;
299
300 case '"':
301 case '\'':
302 {
303 char quote;
304
305 if (saw_operand)
306 goto unknown;
307 quote = *p;
308 *q++ = *p++;
309 while (*p != quote)
310 {
311 int c;
312
313 if (*p == '\0')
314 goto unknown;
315
316 if (*p != '\\')
317 {
318 *q++ = *p++;
319 continue;
320 }
321
322 *q++ = *p++;
323 switch (*p)
324 {
325 case '0': case '1': case '2': case '3':
326 case '4': case '5': case '6': case '7':
327 c = 0;
328 while (*p >= '0' && *p <= '7')
329 {
330 *q++ = *p++;
331 ++c;
332 }
333 /* Go octal characters are always 3
334 digits. */
335 if (c != 3)
336 goto unknown;
337 break;
338
339 case 'x':
340 *q++ = *p++;
341 c = 0;
342 while (ISXDIGIT (*p))
343 {
344 *q++ = *p++;
345 ++c;
346 }
347 /* Go hex characters are always 2 digits. */
348 if (c != 2)
349 goto unknown;
350 break;
351
352 case 'a': case 'b': case 'f': case 'n': case 'r':
353 case 't': case 'v': case '\\': case '\'': case '"':
354 *q++ = *p++;
355 break;
356
357 default:
358 goto unknown;
359 }
360 }
361 *q++ = *p++;
362 break;
363 }
364
365 default:
366 goto unknown;
367 }
368 }
369
370 if (need_operand)
371 goto unknown;
372
373 *q = '\0';
374
375 slot = htab_find_slot_with_hash (macro_hash, copy, hashval, INSERT);
376 *slot = copy;
377
378 fprintf (go_dump_file, "const _%s = %s\n", copy, out_buffer);
379
380 XDELETEVEC (out_buffer);
381 return;
382
383 unknown:
384 fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
385 XDELETEVEC (out_buffer);
386 XDELETEVEC (copy);
387 }
388
389 /* A macro undef. */
390
391 static void
392 go_undef (unsigned int lineno, const char *buffer)
393 {
394 void **slot;
395
396 real_debug_hooks->undef (lineno, buffer);
397
398 slot = htab_find_slot (macro_hash, buffer, NO_INSERT);
399 if (slot == NULL)
400 return;
401 fprintf (go_dump_file, "// undef _%s\n", buffer);
402 /* We don't delete the slot from the hash table because that will
403 cause a duplicate const definition. */
404 }
405
406 /* A function or variable decl. */
407
408 static void
409 go_decl (tree decl)
410 {
411 if (!TREE_PUBLIC (decl)
412 || DECL_IS_BUILTIN (decl)
413 || DECL_NAME (decl) == NULL_TREE)
414 return;
415 VEC_safe_push (tree, gc, queue, decl);
416 }
417
418 /* A function decl. */
419
420 static void
421 go_function_decl (tree decl)
422 {
423 real_debug_hooks->function_decl (decl);
424 go_decl (decl);
425 }
426
427 /* A global variable decl. */
428
429 static void
430 go_global_decl (tree decl)
431 {
432 real_debug_hooks->global_decl (decl);
433 go_decl (decl);
434 }
435
436 /* A type declaration. */
437
438 static void
439 go_type_decl (tree decl, int local)
440 {
441 real_debug_hooks->type_decl (decl, local);
442
443 if (local || DECL_IS_BUILTIN (decl))
444 return;
445 if (DECL_NAME (decl) == NULL_TREE
446 && (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE
447 || TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE)
448 && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
449 return;
450 VEC_safe_push (tree, gc, queue, decl);
451 }
452
453 /* A container for the data we pass around when generating information
454 at the end of the compilation. */
455
456 struct godump_container
457 {
458 /* DECLs that we have already seen. */
459 struct pointer_set_t *decls_seen;
460
461 /* Types which may potentially have to be defined as dummy
462 types. */
463 struct pointer_set_t *pot_dummy_types;
464
465 /* Go keywords. */
466 htab_t keyword_hash;
467
468 /* Global type definitions. */
469 htab_t type_hash;
470
471 /* Invalid types. */
472 htab_t invalid_hash;
473
474 /* Obstack used to write out a type definition. */
475 struct obstack type_obstack;
476 };
477
478 /* Append an IDENTIFIER_NODE to OB. */
479
480 static void
481 go_append_string (struct obstack *ob, tree id)
482 {
483 obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
484 }
485
486 /* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
487 USE_TYPE_NAME is true if we can simply use a type name here without
488 needing to define it. IS_FUNC_OK is true if we can output a func
489 type here; the "func" keyword will already have been added. Return
490 true if the type can be represented in Go, false otherwise. */
491
492 static bool
493 go_format_type (struct godump_container *container, tree type,
494 bool use_type_name, bool is_func_ok)
495 {
496 bool ret;
497 struct obstack *ob;
498
499 ret = true;
500 ob = &container->type_obstack;
501
502 if (TYPE_NAME (type) != NULL_TREE
503 && (pointer_set_contains (container->decls_seen, type)
504 || pointer_set_contains (container->decls_seen, TYPE_NAME (type)))
505 && (AGGREGATE_TYPE_P (type)
506 || POINTER_TYPE_P (type)
507 || TREE_CODE (type) == FUNCTION_TYPE))
508 {
509 tree name;
510 void **slot;
511
512 name = TYPE_NAME (type);
513 if (TREE_CODE (name) == TYPE_DECL)
514 name = DECL_NAME (name);
515
516 slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
517 NO_INSERT);
518 if (slot != NULL)
519 ret = false;
520
521 obstack_1grow (ob, '_');
522 go_append_string (ob, name);
523 return ret;
524 }
525
526 pointer_set_insert (container->decls_seen, type);
527
528 switch (TREE_CODE (type))
529 {
530 case ENUMERAL_TYPE:
531 obstack_grow (ob, "int", 3);
532 break;
533
534 case TYPE_DECL:
535 {
536 void **slot;
537
538 slot = htab_find_slot (container->invalid_hash,
539 IDENTIFIER_POINTER (DECL_NAME (type)),
540 NO_INSERT);
541 if (slot != NULL)
542 ret = false;
543
544 obstack_1grow (ob, '_');
545 go_append_string (ob, DECL_NAME (type));
546 }
547 break;
548
549 case INTEGER_TYPE:
550 {
551 const char *s;
552 char buf[100];
553
554 switch (TYPE_PRECISION (type))
555 {
556 case 8:
557 s = TYPE_UNSIGNED (type) ? "uint8" : "int8";
558 break;
559 case 16:
560 s = TYPE_UNSIGNED (type) ? "uint16" : "int16";
561 break;
562 case 32:
563 s = TYPE_UNSIGNED (type) ? "uint32" : "int32";
564 break;
565 case 64:
566 s = TYPE_UNSIGNED (type) ? "uint64" : "int64";
567 break;
568 default:
569 snprintf (buf, sizeof buf, "INVALID-int-%u%s",
570 TYPE_PRECISION (type),
571 TYPE_UNSIGNED (type) ? "u" : "");
572 s = buf;
573 ret = false;
574 break;
575 }
576 obstack_grow (ob, s, strlen (s));
577 }
578 break;
579
580 case REAL_TYPE:
581 {
582 const char *s;
583 char buf[100];
584
585 switch (TYPE_PRECISION (type))
586 {
587 case 32:
588 s = "float32";
589 break;
590 case 64:
591 s = "float64";
592 break;
593 default:
594 snprintf (buf, sizeof buf, "INVALID-float-%u",
595 TYPE_PRECISION (type));
596 s = buf;
597 ret = false;
598 break;
599 }
600 obstack_grow (ob, s, strlen (s));
601 }
602 break;
603
604 case BOOLEAN_TYPE:
605 obstack_grow (ob, "bool", 4);
606 break;
607
608 case POINTER_TYPE:
609 if (use_type_name
610 && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
611 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
612 || (POINTER_TYPE_P (TREE_TYPE (type))
613 && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
614 == FUNCTION_TYPE))))
615 {
616 tree name;
617 void **slot;
618
619 name = TYPE_NAME (TREE_TYPE (type));
620 if (TREE_CODE (name) == TYPE_DECL)
621 name = DECL_NAME (name);
622
623 slot = htab_find_slot (container->invalid_hash,
624 IDENTIFIER_POINTER (name), NO_INSERT);
625 if (slot != NULL)
626 ret = false;
627
628 obstack_grow (ob, "*_", 2);
629 go_append_string (ob, name);
630
631 /* The pointer here can be used without the struct or union
632 definition. So this struct or union is a potential dummy
633 type. */
634 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
635 pointer_set_insert (container->pot_dummy_types,
636 IDENTIFIER_POINTER (name));
637
638 return ret;
639 }
640 if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
641 obstack_grow (ob, "func", 4);
642 else
643 obstack_1grow (ob, '*');
644 if (VOID_TYPE_P (TREE_TYPE (type)))
645 obstack_grow (ob, "byte", 4);
646 else
647 {
648 if (!go_format_type (container, TREE_TYPE (type), use_type_name,
649 true))
650 ret = false;
651 }
652 break;
653
654 case ARRAY_TYPE:
655 obstack_1grow (ob, '[');
656 if (TYPE_DOMAIN (type) != NULL_TREE
657 && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
658 && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
659 && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
660 && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
661 && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
662 && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
663 && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0))
664 {
665 char buf[100];
666
667 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
668 tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0));
669 obstack_grow (ob, buf, strlen (buf));
670 }
671 obstack_1grow (ob, ']');
672 if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
673 ret = false;
674 break;
675
676 case UNION_TYPE:
677 case RECORD_TYPE:
678 {
679 tree field;
680 int i;
681
682 obstack_grow (ob, "struct { ", 9);
683 i = 0;
684 for (field = TYPE_FIELDS (type);
685 field != NULL_TREE;
686 field = TREE_CHAIN (field))
687 {
688 if (DECL_NAME (field) == NULL)
689 {
690 char buf[100];
691
692 obstack_grow (ob, "Godump_", 2);
693 snprintf (buf, sizeof buf, "%d", i);
694 obstack_grow (ob, buf, strlen (buf));
695 i++;
696 }
697 else
698 {
699 const char *var_name;
700 void **slot;
701
702 /* Start variable name with an underscore if a keyword. */
703 var_name = IDENTIFIER_POINTER (DECL_NAME (field));
704 slot = htab_find_slot (container->keyword_hash, var_name,
705 NO_INSERT);
706 if (slot != NULL)
707 obstack_1grow (ob, '_');
708 go_append_string (ob, DECL_NAME (field));
709 }
710 obstack_1grow (ob, ' ');
711 if (DECL_BIT_FIELD (field))
712 {
713 obstack_grow (ob, "INVALID-bit-field", 17);
714 ret = false;
715 }
716 else
717 {
718 /* Do not expand type if a record or union type or a
719 function pointer. */
720 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
721 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
722 || (POINTER_TYPE_P (TREE_TYPE (field))
723 && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
724 == FUNCTION_TYPE))))
725 {
726 tree name;
727 void **slot;
728
729 name = TYPE_NAME (TREE_TYPE (field));
730 if (TREE_CODE (name) == TYPE_DECL)
731 name = DECL_NAME (name);
732
733 slot = htab_find_slot (container->invalid_hash,
734 IDENTIFIER_POINTER (name),
735 NO_INSERT);
736 if (slot != NULL)
737 ret = false;
738
739 obstack_1grow (ob, '_');
740 go_append_string (ob, name);
741 }
742 else
743 {
744 if (!go_format_type (container, TREE_TYPE (field), true,
745 false))
746 ret = false;
747 }
748 }
749 obstack_grow (ob, "; ", 2);
750
751 /* Only output the first field of a union, and hope for
752 the best. */
753 if (TREE_CODE (type) == UNION_TYPE)
754 break;
755 }
756 obstack_1grow (ob, '}');
757 }
758 break;
759
760 case FUNCTION_TYPE:
761 {
762 tree arg_type;
763 bool is_varargs;
764 tree result;
765 function_args_iterator iter;
766 bool seen_arg;
767
768 /* Go has no way to write a type which is a function but not a
769 pointer to a function. */
770 if (!is_func_ok)
771 {
772 obstack_grow (ob, "func*", 5);
773 ret = false;
774 }
775
776 obstack_1grow (ob, '(');
777 is_varargs = stdarg_p (type);
778 seen_arg = false;
779 FOREACH_FUNCTION_ARGS (type, arg_type, iter)
780 {
781 if (VOID_TYPE_P (arg_type))
782 break;
783 if (seen_arg)
784 obstack_grow (ob, ", ", 2);
785 if (!go_format_type (container, arg_type, true, false))
786 ret = false;
787 seen_arg = true;
788 }
789 if (is_varargs)
790 {
791 if (prototype_p (type))
792 obstack_grow (ob, ", ", 2);
793 obstack_grow (ob, "...interface{}", 14);
794 }
795 obstack_1grow (ob, ')');
796
797 result = TREE_TYPE (type);
798 if (!VOID_TYPE_P (result))
799 {
800 obstack_1grow (ob, ' ');
801 if (!go_format_type (container, result, use_type_name, false))
802 ret = false;
803 }
804 }
805 break;
806
807 default:
808 obstack_grow (ob, "INVALID-type", 12);
809 ret = false;
810 break;
811 }
812
813 return ret;
814 }
815
816 /* Output the type which was built on the type obstack, and then free
817 it. */
818
819 static void
820 go_output_type (struct godump_container *container)
821 {
822 struct obstack *ob;
823
824 ob = &container->type_obstack;
825 obstack_1grow (ob, '\0');
826 fputs (obstack_base (ob), go_dump_file);
827 obstack_free (ob, obstack_base (ob));
828 }
829
830 /* Output a function declaration. */
831
832 static void
833 go_output_fndecl (struct godump_container *container, tree decl)
834 {
835 if (!go_format_type (container, TREE_TYPE (decl), false, true))
836 fprintf (go_dump_file, "// ");
837 fprintf (go_dump_file, "func _%s ",
838 IDENTIFIER_POINTER (DECL_NAME (decl)));
839 go_output_type (container);
840 fprintf (go_dump_file, " __asm__(\"%s\")\n",
841 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
842 }
843
844 /* Output a typedef or something like a struct definition. */
845
846 static void
847 go_output_typedef (struct godump_container *container, tree decl)
848 {
849 /* If we have an enum type, output the enum constants
850 separately. */
851 if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
852 && TYPE_SIZE (TREE_TYPE (decl)) != 0
853 && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
854 && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
855 || !pointer_set_contains (container->decls_seen,
856 TYPE_CANONICAL (TREE_TYPE (decl)))))
857 {
858 tree element;
859
860 for (element = TYPE_VALUES (TREE_TYPE (decl));
861 element != NULL_TREE;
862 element = TREE_CHAIN (element))
863 {
864 const char *name;
865 void **slot;
866
867 name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
868
869 /* Sometimes a name will be defined as both an enum constant
870 and a macro. Avoid duplicate definition errors by
871 treating enum constants as macros. */
872 slot = htab_find_slot (macro_hash, name, INSERT);
873 if (*slot == NULL)
874 {
875 *slot = CONST_CAST (char *, name);
876 fprintf (go_dump_file,
877 "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
878 name, tree_low_cst (TREE_VALUE (element), 0));
879 }
880 }
881 pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
882 if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
883 pointer_set_insert (container->decls_seen,
884 TYPE_CANONICAL (TREE_TYPE (decl)));
885 }
886
887 if (DECL_NAME (decl) != NULL_TREE)
888 {
889 void **slot;
890 const char *type;
891
892 type = IDENTIFIER_POINTER (DECL_NAME (decl));
893 /* If type defined already, skip. */
894 slot = htab_find_slot (container->type_hash, type, INSERT);
895 if (*slot != NULL)
896 return;
897 *slot = CONST_CAST (void *, (const void *) type);
898
899 if (!go_format_type (container, TREE_TYPE (decl), false, false))
900 {
901 fprintf (go_dump_file, "// ");
902 slot = htab_find_slot (container->invalid_hash, type, INSERT);
903 *slot = CONST_CAST (void *, (const void *) type);
904 }
905 fprintf (go_dump_file, "type _%s ",
906 IDENTIFIER_POINTER (DECL_NAME (decl)));
907 go_output_type (container);
908 pointer_set_insert (container->decls_seen, decl);
909 }
910 else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
911 {
912 void **slot;
913 const char *type;
914
915 type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
916 /* If type defined already, skip. */
917 slot = htab_find_slot (container->type_hash, type, INSERT);
918 if (*slot != NULL)
919 return;
920 *slot = CONST_CAST (void *, (const void *) type);
921
922 if (!go_format_type (container, TREE_TYPE (decl), false, false))
923 {
924 fprintf (go_dump_file, "// ");
925 slot = htab_find_slot (container->invalid_hash, type, INSERT);
926 *slot = CONST_CAST (void *, (const void *) type);
927 }
928 fprintf (go_dump_file, "type _%s ",
929 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
930 go_output_type (container);
931 }
932 else
933 return;
934
935 fprintf (go_dump_file, "\n");
936 }
937
938 /* Output a variable. */
939
940 static void
941 go_output_var (struct godump_container *container, tree decl)
942 {
943 bool is_valid;
944
945 if (pointer_set_contains (container->decls_seen, decl)
946 || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
947 return;
948 pointer_set_insert (container->decls_seen, decl);
949 pointer_set_insert (container->decls_seen, DECL_NAME (decl));
950
951 is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
952 if (is_valid
953 && htab_find_slot (container->type_hash,
954 IDENTIFIER_POINTER (DECL_NAME (decl)),
955 NO_INSERT) != NULL)
956 {
957 /* There is already a type with this name, probably from a
958 struct tag. Prefer the type to the variable. */
959 is_valid = false;
960 }
961 if (!is_valid)
962 fprintf (go_dump_file, "// ");
963
964 fprintf (go_dump_file, "var _%s ",
965 IDENTIFIER_POINTER (DECL_NAME (decl)));
966 go_output_type (container);
967 fprintf (go_dump_file, "\n");
968
969 /* Sometimes an extern variable is declared with an unknown struct
970 type. */
971 if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
972 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
973 {
974 tree type_name = TYPE_NAME (TREE_TYPE (decl));
975 if (TREE_CODE (type_name) == IDENTIFIER_NODE)
976 pointer_set_insert (container->pot_dummy_types,
977 IDENTIFIER_POINTER (type_name));
978 else if (TREE_CODE (type_name) == TYPE_DECL)
979 pointer_set_insert (container->pot_dummy_types,
980 IDENTIFIER_POINTER (DECL_NAME (type_name)));
981 }
982 }
983
984 /* Build a hash table with the Go keywords. */
985
986 static const char * const keywords[] = {
987 "__asm__", "break", "case", "chan", "const", "continue", "default",
988 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
989 "import", "interface", "map", "package", "range", "return", "select",
990 "struct", "switch", "type", "var"
991 };
992
993 static void
994 keyword_hash_init (struct godump_container *container)
995 {
996 size_t i;
997 size_t count = sizeof (keywords) / sizeof (keywords[0]);
998 void **slot;
999
1000 for (i = 0; i < count; i++)
1001 {
1002 slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1003 *slot = CONST_CAST (void *, (const void *) keywords[i]);
1004 }
1005 }
1006
1007 /* Traversing the pot_dummy_types and seeing which types are present
1008 in the global types hash table and creating dummy definitions if
1009 not found. This function is invoked by pointer_set_traverse. */
1010
1011 static bool
1012 find_dummy_types (const void *ptr, void *adata)
1013 {
1014 struct godump_container *data = (struct godump_container *) adata;
1015 const char *type = (const char *) ptr;
1016 void **slot;
1017
1018 slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1019 if (slot == NULL)
1020 fprintf (go_dump_file, "type _%s struct {}\n", type);
1021 return true;
1022 }
1023
1024 /* Output symbols. */
1025
1026 static void
1027 go_finish (const char *filename)
1028 {
1029 struct godump_container container;
1030 unsigned int ix;
1031 tree decl;
1032
1033 real_debug_hooks->finish (filename);
1034
1035 container.decls_seen = pointer_set_create ();
1036 container.pot_dummy_types = pointer_set_create ();
1037 container.type_hash = htab_create (100, htab_hash_string,
1038 string_hash_eq, NULL);
1039 container.invalid_hash = htab_create (10, htab_hash_string,
1040 string_hash_eq, NULL);
1041 container.keyword_hash = htab_create (50, htab_hash_string,
1042 string_hash_eq, NULL);
1043 obstack_init (&container.type_obstack);
1044
1045 keyword_hash_init (&container);
1046
1047 FOR_EACH_VEC_ELT (tree, queue, ix, decl)
1048 {
1049 switch (TREE_CODE (decl))
1050 {
1051 case FUNCTION_DECL:
1052 go_output_fndecl (&container, decl);
1053 break;
1054
1055 case TYPE_DECL:
1056 go_output_typedef (&container, decl);
1057 break;
1058
1059 case VAR_DECL:
1060 go_output_var (&container, decl);
1061 break;
1062
1063 default:
1064 gcc_unreachable();
1065 }
1066 }
1067
1068 /* To emit dummy definitions. */
1069 pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
1070 (void *) &container);
1071
1072 pointer_set_destroy (container.decls_seen);
1073 pointer_set_destroy (container.pot_dummy_types);
1074 htab_delete (container.type_hash);
1075 htab_delete (container.invalid_hash);
1076 htab_delete (container.keyword_hash);
1077 obstack_free (&container.type_obstack, NULL);
1078
1079 queue = NULL;
1080
1081 if (fclose (go_dump_file) != 0)
1082 error ("could not close Go dump file: %m");
1083 go_dump_file = NULL;
1084 }
1085
1086 /* Set up our hooks. */
1087
1088 const struct gcc_debug_hooks *
1089 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1090 {
1091 go_dump_file = fopen (filename, "w");
1092 if (go_dump_file == NULL)
1093 {
1094 error ("could not open Go dump file %qs: %m", filename);
1095 return hooks;
1096 }
1097
1098 go_debug_hooks = *hooks;
1099 real_debug_hooks = hooks;
1100
1101 go_debug_hooks.finish = go_finish;
1102 go_debug_hooks.define = go_define;
1103 go_debug_hooks.undef = go_undef;
1104 go_debug_hooks.function_decl = go_function_decl;
1105 go_debug_hooks.global_decl = go_global_decl;
1106 go_debug_hooks.type_decl = go_type_decl;
1107
1108 macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
1109
1110 return &go_debug_hooks;
1111 }
1112
1113 #include "gt-godump.h"