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