1 /* Output Go language descriptions of types.
2    Copyright (C) 2008-2020 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 "tree.h"
34 #include "diagnostic-core.h"
35 #include "debug.h"
36 #include "stor-layout.h"
37 
38 /* We dump this information from the debug hooks.  This gives us a
39    stable and maintainable API to hook into.  In order to work
40    correctly when -g is used, we build our own hooks structure which
41    wraps the hooks we need to change.  */
42 
43 /* Our debug hooks.  This is initialized by dump_go_spec_init.  */
44 
45 static struct gcc_debug_hooks go_debug_hooks;
46 
47 /* The real debug hooks.  */
48 
49 static const struct gcc_debug_hooks *real_debug_hooks;
50 
51 /* The file where we should write information.  */
52 
53 static FILE *go_dump_file;
54 
55 /* A queue of decls to output.  */
56 
57 static GTY(()) vec<tree, va_gc> *queue;
58 
59 /* A hash table of macros we have seen.  */
60 
61 static htab_t macro_hash;
62 
63 /* The type of a value in macro_hash.  */
64 
65 struct macro_hash_value
66 {
67   /* The name stored in the hash table.  */
68   char *name;
69   /* The value of the macro.  */
70   char *value;
71 };
72 
73 /* Returns the number of units necessary to represent an integer with the given
74    PRECISION (in bits).  */
75 
76 static inline unsigned int
precision_to_units(unsigned int precision)77 precision_to_units (unsigned int precision)
78 {
79   return (precision + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
80 }
81 
82 /* Calculate the hash value for an entry in the macro hash table.  */
83 
84 static hashval_t
macro_hash_hashval(const void * val)85 macro_hash_hashval (const void *val)
86 {
87   const struct macro_hash_value *mhval = (const struct macro_hash_value *) val;
88   return htab_hash_string (mhval->name);
89 }
90 
91 /* Compare values in the macro hash table for equality.  */
92 
93 static int
macro_hash_eq(const void * v1,const void * v2)94 macro_hash_eq (const void *v1, const void *v2)
95 {
96   const struct macro_hash_value *mhv1 = (const struct macro_hash_value *) v1;
97   const struct macro_hash_value *mhv2 = (const struct macro_hash_value *) v2;
98   return strcmp (mhv1->name, mhv2->name) == 0;
99 }
100 
101 /* Free values deleted from the macro hash table.  */
102 
103 static void
macro_hash_del(void * v)104 macro_hash_del (void *v)
105 {
106   struct macro_hash_value *mhv = (struct macro_hash_value *) v;
107   XDELETEVEC (mhv->name);
108   XDELETEVEC (mhv->value);
109   XDELETE (mhv);
110 }
111 
112 /* For the string hash tables.  */
113 
114 static int
string_hash_eq(const void * y1,const void * y2)115 string_hash_eq (const void *y1, const void *y2)
116 {
117   return strcmp ((const char *) y1, (const char *) y2) == 0;
118 }
119 
120 /* A macro definition.  */
121 
122 static void
go_define(unsigned int lineno,const char * buffer)123 go_define (unsigned int lineno, const char *buffer)
124 {
125   const char *p;
126   const char *name_end;
127   size_t out_len;
128   char *out_buffer;
129   char *q;
130   bool saw_operand;
131   bool need_operand;
132   struct macro_hash_value *mhval;
133   char *copy;
134   hashval_t hashval;
135   void **slot;
136 
137   real_debug_hooks->define (lineno, buffer);
138 
139   /* Skip macro functions.  */
140   for (p = buffer; *p != '\0' && *p != ' '; ++p)
141     if (*p == '(')
142       return;
143 
144   if (*p == '\0')
145     return;
146 
147   name_end = p;
148 
149   ++p;
150   if (*p == '\0')
151     return;
152 
153   copy = XNEWVEC (char, name_end - buffer + 1);
154   memcpy (copy, buffer, name_end - buffer);
155   copy[name_end - buffer] = '\0';
156 
157   mhval = XNEW (struct macro_hash_value);
158   mhval->name = copy;
159   mhval->value = NULL;
160 
161   hashval = htab_hash_string (copy);
162   slot = htab_find_slot_with_hash (macro_hash, mhval, hashval, NO_INSERT);
163 
164   /* For simplicity, we force all names to be hidden by adding an
165      initial underscore, and let the user undo this as needed.  */
166   out_len = strlen (p) * 2 + 1;
167   out_buffer = XNEWVEC (char, out_len);
168   q = out_buffer;
169   saw_operand = false;
170   need_operand = false;
171   while (*p != '\0')
172     {
173       switch (*p)
174 	{
175 	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
176 	case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
177 	case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
178 	case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
179 	case 'Y': case 'Z':
180 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
181 	case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
182 	case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
183 	case 's': case 't': case 'u': case 'v': case 'w': case 'x':
184 	case 'y': case 'z':
185 	case '_':
186 	  {
187 	    /* The start of an identifier.  Technically we should also
188 	       worry about UTF-8 identifiers, but they are not a
189 	       problem for practical uses of -fdump-go-spec so we
190 	       don't worry about them.  */
191 	    const char *start;
192 	    char *n;
193 	    struct macro_hash_value idval;
194 
195 	    if (saw_operand)
196 	      goto unknown;
197 
198 	    start = p;
199 	    while (ISALNUM (*p) || *p == '_')
200 	      ++p;
201 	    n = XALLOCAVEC (char, p - start + 1);
202 	    memcpy (n, start, p - start);
203 	    n[p - start] = '\0';
204 	    idval.name = n;
205 	    idval.value = NULL;
206 	    if (htab_find (macro_hash, &idval) == NULL)
207 	      {
208 		/* This is a reference to a name which was not defined
209 		   as a macro.  */
210 		goto unknown;
211 	      }
212 
213 	    *q++ = '_';
214 	    memcpy (q, start, p - start);
215 	    q += p - start;
216 
217 	    saw_operand = true;
218 	    need_operand = false;
219 	  }
220 	  break;
221 
222 	case '.':
223 	  if (!ISDIGIT (p[1]))
224 	    goto unknown;
225 	  /* Fall through.  */
226 	case '0': case '1': case '2': case '3': case '4':
227 	case '5': case '6': case '7': case '8': case '9':
228 	  {
229 	    const char *start;
230 	    bool is_hex;
231 
232 	    start = p;
233 	    is_hex = false;
234 	    if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
235 	      {
236 		p += 2;
237 		is_hex = true;
238 	      }
239 	    while (ISDIGIT (*p) || *p == '.' || *p == 'e' || *p == 'E'
240 		   || (is_hex
241 		       && ((*p >= 'a' && *p <= 'f')
242 			   || (*p >= 'A' && *p <= 'F'))))
243 	      ++p;
244 	    memcpy (q, start, p - start);
245 	    q += p - start;
246 	    while (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L'
247 		   || *p == 'f' || *p == 'F'
248 		   || *p == 'd' || *p == 'D')
249 	      {
250 		/* Go doesn't use any of these trailing type
251 		   modifiers.  */
252 		++p;
253 	      }
254 
255 	    /* We'll pick up the exponent, if any, as an
256 	       expression.  */
257 
258 	    saw_operand = true;
259 	    need_operand = false;
260 	  }
261 	  break;
262 
263 	case ' ': case '\t':
264 	  *q++ = *p++;
265 	  break;
266 
267 	case '(':
268 	  /* Always OK, not part of an operand, presumed to start an
269 	     operand.  */
270 	  *q++ = *p++;
271 	  saw_operand = false;
272 	  need_operand = false;
273 	  break;
274 
275 	case ')':
276 	  /* OK if we don't need an operand, and presumed to indicate
277 	     an operand.  */
278 	  if (need_operand)
279 	    goto unknown;
280 	  *q++ = *p++;
281 	  saw_operand = true;
282 	  break;
283 
284 	case '+': case '-':
285 	  /* Always OK, but not part of an operand.  */
286 	  *q++ = *p++;
287 	  saw_operand = false;
288 	  break;
289 
290 	case '*': case '/': case '%': case '|': case '&': case '^':
291 	  /* Must be a binary operator.  */
292 	  if (!saw_operand)
293 	    goto unknown;
294 	  *q++ = *p++;
295 	  saw_operand = false;
296 	  need_operand = true;
297 	  break;
298 
299 	case '=':
300 	  *q++ = *p++;
301 	  if (*p != '=')
302 	    goto unknown;
303 	  /* Must be a binary operator.  */
304 	  if (!saw_operand)
305 	    goto unknown;
306 	  *q++ = *p++;
307 	  saw_operand = false;
308 	  need_operand = true;
309 	  break;
310 
311 	case '!':
312 	  *q++ = *p++;
313 	  if (*p == '=')
314 	    {
315 	      /* Must be a binary operator.  */
316 	      if (!saw_operand)
317 		goto unknown;
318 	      *q++ = *p++;
319 	      saw_operand = false;
320 	      need_operand = true;
321 	    }
322 	  else
323 	    {
324 	      /* Must be a unary operator.  */
325 	      if (saw_operand)
326 		goto unknown;
327 	      need_operand = true;
328 	    }
329 	  break;
330 
331 	case '<': case '>':
332 	  /* Must be a binary operand, may be << or >> or <= or >=.  */
333 	  if (!saw_operand)
334 	    goto unknown;
335 	  *q++ = *p++;
336 	  if (*p == *(p - 1) || *p == '=')
337 	    *q++ = *p++;
338 	  saw_operand = false;
339 	  need_operand = true;
340 	  break;
341 
342 	case '~':
343 	  /* Must be a unary operand, must be translated for Go.  */
344 	  if (saw_operand)
345 	    goto unknown;
346 	  *q++ = '^';
347 	  p++;
348 	  need_operand = true;
349 	  break;
350 
351 	case '"':
352 	case '\'':
353 	  {
354 	    char quote;
355 	    int count;
356 
357 	    if (saw_operand)
358 	      goto unknown;
359 	    quote = *p;
360 	    *q++ = *p++;
361 	    count = 0;
362 	    while (*p != quote)
363 	      {
364 		int c;
365 
366 		if (*p == '\0')
367 		  goto unknown;
368 
369 		++count;
370 
371 		if (*p != '\\')
372 		  {
373 		    *q++ = *p++;
374 		    continue;
375 		  }
376 
377 		*q++ = *p++;
378 		switch (*p)
379 		  {
380 		  case '0': case '1': case '2': case '3':
381 		  case '4': case '5': case '6': case '7':
382 		    c = 0;
383 		    while (*p >= '0' && *p <= '7')
384 		      {
385 			*q++ = *p++;
386 			++c;
387 		      }
388 		    /* Go octal characters are always 3
389 		       digits.  */
390 		    if (c != 3)
391 		      goto unknown;
392 		    break;
393 
394 		  case 'x':
395 		    *q++ = *p++;
396 		    c = 0;
397 		    while (ISXDIGIT (*p))
398 		      {
399 			*q++ = *p++;
400 			++c;
401 		      }
402 		    /* Go hex characters are always 2 digits.  */
403 		    if (c != 2)
404 		      goto unknown;
405 		    break;
406 
407 		  case 'a': case 'b': case 'f': case 'n': case 'r':
408 		  case 't': case 'v': case '\\': case '\'': case '"':
409 		    *q++ = *p++;
410 		    break;
411 
412 		  default:
413 		    goto unknown;
414 		  }
415 	      }
416 
417 	    *q++ = *p++;
418 
419 	    if (quote == '\'' && count != 1)
420 	      goto unknown;
421 
422 	    saw_operand = true;
423 	    need_operand = false;
424 
425 	    break;
426 	  }
427 
428 	default:
429 	  goto unknown;
430 	}
431     }
432 
433   if (need_operand)
434     goto unknown;
435 
436   gcc_assert ((size_t) (q - out_buffer) < out_len);
437   *q = '\0';
438 
439   mhval->value = out_buffer;
440 
441   if (slot == NULL)
442     {
443       slot = htab_find_slot_with_hash (macro_hash, mhval, hashval, INSERT);
444       gcc_assert (slot != NULL && *slot == NULL);
445     }
446   else
447     {
448       if (*slot != NULL)
449 	macro_hash_del (*slot);
450     }
451 
452   *slot = mhval;
453 
454   return;
455 
456  unknown:
457   fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
458   if (slot != NULL)
459     htab_clear_slot (macro_hash, slot);
460   XDELETEVEC (out_buffer);
461   XDELETEVEC (copy);
462 }
463 
464 /* A macro undef.  */
465 
466 static void
go_undef(unsigned int lineno,const char * buffer)467 go_undef (unsigned int lineno, const char *buffer)
468 {
469   struct macro_hash_value mhval;
470   void **slot;
471 
472   real_debug_hooks->undef (lineno, buffer);
473 
474   mhval.name = CONST_CAST (char *, buffer);
475   mhval.value = NULL;
476   slot = htab_find_slot (macro_hash, &mhval, NO_INSERT);
477   if (slot != NULL)
478     htab_clear_slot (macro_hash, slot);
479 }
480 
481 /* A function or variable decl.  */
482 
483 static void
go_decl(tree decl)484 go_decl (tree decl)
485 {
486   if (!TREE_PUBLIC (decl)
487       || DECL_IS_BUILTIN (decl)
488       || DECL_NAME (decl) == NULL_TREE)
489     return;
490   vec_safe_push (queue, decl);
491 }
492 
493 /* A function decl.  */
494 
495 static void
go_function_decl(tree decl)496 go_function_decl (tree decl)
497 {
498   real_debug_hooks->function_decl (decl);
499   go_decl (decl);
500 }
501 
502 static void
go_early_global_decl(tree decl)503 go_early_global_decl (tree decl)
504 {
505   go_decl (decl);
506   if (TREE_CODE (decl) != FUNCTION_DECL || DECL_STRUCT_FUNCTION (decl) != NULL)
507     real_debug_hooks->early_global_decl (decl);
508 }
509 
510 /* A global variable decl.  */
511 
512 static void
go_late_global_decl(tree decl)513 go_late_global_decl (tree decl)
514 {
515   real_debug_hooks->late_global_decl (decl);
516 }
517 
518 /* A type declaration.  */
519 
520 static void
go_type_decl(tree decl,int local)521 go_type_decl (tree decl, int local)
522 {
523   real_debug_hooks->type_decl (decl, local);
524 
525   if (local || DECL_IS_BUILTIN (decl))
526     return;
527   if (DECL_NAME (decl) == NULL_TREE
528       && (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE
529 	  || TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE)
530       && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
531     return;
532   vec_safe_push (queue, decl);
533 }
534 
535 /* A container for the data we pass around when generating information
536    at the end of the compilation.  */
537 
538 class godump_container
539 {
540 public:
541   /* DECLs that we have already seen.  */
542   hash_set<tree> decls_seen;
543 
544   /* Types which may potentially have to be defined as dummy
545      types.  */
546   hash_set<const char *> pot_dummy_types;
547 
548   /* Go keywords.  */
549   htab_t keyword_hash;
550 
551   /* Global type definitions.  */
552   htab_t type_hash;
553 
554   /* Invalid types.  */
555   htab_t invalid_hash;
556 
557   /* Obstack used to write out a type definition.  */
558   struct obstack type_obstack;
559 };
560 
561 /* Append an IDENTIFIER_NODE to OB.  */
562 
563 static void
go_append_string(struct obstack * ob,tree id)564 go_append_string (struct obstack *ob, tree id)
565 {
566   obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
567 }
568 
569 /* Given an integer PRECISION in bits, returns a constant string that is the
570    matching go int or uint type (depending on the IS_UNSIGNED flag).  Returns a
571    NULL pointer if there is no matching go type.  */
572 
573 static const char *
go_get_uinttype_for_precision(unsigned int precision,bool is_unsigned)574 go_get_uinttype_for_precision (unsigned int precision, bool is_unsigned)
575 {
576   switch (precision)
577     {
578     case 8:
579       return is_unsigned ? "uint8" : "int8";
580     case 16:
581       return is_unsigned ? "uint16" : "int16";
582     case 32:
583       return is_unsigned ? "uint32" : "int32";
584     case 64:
585       return is_unsigned ? "uint64" : "int64";
586     default:
587       return NULL;
588     }
589 }
590 
591 /* Append an artificial variable name with the suffix _INDEX to OB.  Returns
592    INDEX + 1.  */
593 
594 static unsigned int
go_append_artificial_name(struct obstack * ob,unsigned int index)595 go_append_artificial_name (struct obstack *ob, unsigned int index)
596 {
597   char buf[100];
598 
599   /* FIXME: identifier may not be unique.  */
600   obstack_grow (ob, "Godump_", 7);
601   snprintf (buf, sizeof buf, "%u", index);
602   obstack_grow (ob, buf, strlen (buf));
603 
604   return index + 1;
605 }
606 
607 /* Append the variable name from DECL to OB.  If the name is in the
608    KEYWORD_HASH, prepend an '_'.  */
609 
610 static void
go_append_decl_name(struct obstack * ob,tree decl,htab_t keyword_hash)611 go_append_decl_name (struct obstack *ob, tree decl, htab_t keyword_hash)
612 {
613   const char *var_name;
614   void **slot;
615 
616   /* Start variable name with an underscore if a keyword.  */
617   var_name = IDENTIFIER_POINTER (DECL_NAME (decl));
618   slot = htab_find_slot (keyword_hash, var_name, NO_INSERT);
619   if (slot != NULL)
620     obstack_1grow (ob, '_');
621   go_append_string (ob, DECL_NAME (decl));
622 }
623 
624 /* Appends a byte array with the necessary number of elements and the name
625    "Godump_INDEX_pad" to pad from FROM_OFFSET to TO_OFFSET to OB assuming that
626    the next field is automatically aligned to ALIGN_UNITS.  Returns INDEX + 1,
627    or INDEX if no padding had to be appended.  The resulting offset where the
628    next field is allocated is returned through RET_OFFSET.  */
629 
630 static unsigned int
go_append_padding(struct obstack * ob,unsigned int from_offset,unsigned int to_offset,unsigned int align_units,unsigned int index,unsigned int * ret_offset)631 go_append_padding (struct obstack *ob, unsigned int from_offset,
632 		   unsigned int to_offset, unsigned int align_units,
633 		   unsigned int index, unsigned int *ret_offset)
634 {
635   if (from_offset % align_units > 0)
636     from_offset += align_units - (from_offset % align_units);
637   gcc_assert (to_offset >= from_offset);
638   if (to_offset > from_offset)
639     {
640       char buf[100];
641 
642       index = go_append_artificial_name (ob, index);
643       snprintf (buf, sizeof buf, "_pad [%u]byte; ", to_offset - from_offset);
644       obstack_grow (ob, buf, strlen (buf));
645     }
646   *ret_offset = to_offset;
647 
648   return index;
649 }
650 
651 /* Appends an array of type TYPE_STRING with zero elements and the name
652    "Godump_INDEX_align" to OB.  If TYPE_STRING is a null pointer, ERROR_STRING
653    is appended instead of the type.  Returns INDEX + 1.  */
654 
655 static unsigned int
go_force_record_alignment(struct obstack * ob,const char * type_string,unsigned int index,const char * error_string)656 go_force_record_alignment (struct obstack *ob, const char *type_string,
657 			   unsigned int index, const char *error_string)
658 {
659   index = go_append_artificial_name (ob, index);
660   obstack_grow (ob, "_align ", 7);
661   if (type_string == NULL)
662     obstack_grow (ob, error_string, strlen (error_string));
663   else
664     {
665       obstack_grow (ob, "[0]", 3);
666       obstack_grow (ob, type_string, strlen (type_string));
667     }
668   obstack_grow (ob, "; ", 2);
669 
670   return index;
671 }
672 
673 /* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
674    USE_TYPE_NAME is true if we can simply use a type name here without
675    needing to define it.  IS_FUNC_OK is true if we can output a func
676    type here; the "func" keyword will already have been added.
677    Return true if the type can be represented in Go, false otherwise.
678    P_ART_I is used for indexing artificial elements in nested structures and
679    should always be a NULL pointer when called, except by certain recursive
680    calls from go_format_type() itself.  */
681 
682 static bool
go_format_type(class godump_container * container,tree type,bool use_type_name,bool is_func_ok,unsigned int * p_art_i,bool is_anon_record_or_union)683 go_format_type (class godump_container *container, tree type,
684 		bool use_type_name, bool is_func_ok, unsigned int *p_art_i,
685 		bool is_anon_record_or_union)
686 {
687   bool ret;
688   struct obstack *ob;
689   unsigned int art_i_dummy;
690   bool is_union = false;
691 
692   if (p_art_i == NULL)
693     {
694       art_i_dummy = 0;
695       p_art_i = &art_i_dummy;
696     }
697   ret = true;
698   ob = &container->type_obstack;
699 
700   if (TYPE_NAME (type) != NULL_TREE
701       && (container->decls_seen.contains (type)
702 	  || container->decls_seen.contains (TYPE_NAME (type)))
703       && (AGGREGATE_TYPE_P (type)
704 	  || POINTER_TYPE_P (type)
705 	  || TREE_CODE (type) == FUNCTION_TYPE))
706     {
707       tree name;
708       void **slot;
709 
710       name = TYPE_IDENTIFIER (type);
711 
712       slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
713 			     NO_INSERT);
714       if (slot != NULL)
715 	ret = false;
716 
717       obstack_1grow (ob, '_');
718       go_append_string (ob, name);
719       return ret;
720     }
721 
722   container->decls_seen.add (type);
723 
724   switch (TREE_CODE (type))
725     {
726     case TYPE_DECL:
727       {
728 	void **slot;
729 
730 	slot = htab_find_slot (container->invalid_hash,
731 			       IDENTIFIER_POINTER (DECL_NAME (type)),
732 			       NO_INSERT);
733 	if (slot != NULL)
734 	  ret = false;
735 
736 	obstack_1grow (ob, '_');
737 	go_append_string (ob, DECL_NAME (type));
738       }
739       break;
740 
741     case ENUMERAL_TYPE:
742     case INTEGER_TYPE:
743       {
744 	const char *s;
745 	char buf[100];
746 
747 	s = go_get_uinttype_for_precision (TYPE_PRECISION (type),
748 					   TYPE_UNSIGNED (type));
749 	if (s == NULL)
750 	  {
751 	    snprintf (buf, sizeof buf, "INVALID-int-%u%s",
752 		      TYPE_PRECISION (type),
753 		      TYPE_UNSIGNED (type) ? "u" : "");
754 	    s = buf;
755 	    ret = false;
756 	  }
757 	obstack_grow (ob, s, strlen (s));
758       }
759       break;
760 
761     case REAL_TYPE:
762       {
763 	const char *s;
764 	char buf[100];
765 
766 	switch (TYPE_PRECISION (type))
767 	  {
768 	  case 32:
769 	    s = "float32";
770 	    break;
771 	  case 64:
772 	    s = "float64";
773 	    break;
774 	  default:
775 	    snprintf (buf, sizeof buf, "INVALID-float-%u",
776 		      TYPE_PRECISION (type));
777 	    s = buf;
778 	    ret = false;
779 	    break;
780 	  }
781 	obstack_grow (ob, s, strlen (s));
782       }
783       break;
784 
785     case COMPLEX_TYPE:
786       {
787 	const char *s;
788 	char buf[100];
789 	tree real_type;
790 
791 	real_type = TREE_TYPE (type);
792 	if (TREE_CODE (real_type) == REAL_TYPE)
793 	  {
794 	    switch (TYPE_PRECISION (real_type))
795 	      {
796 	      case 32:
797 		s = "complex64";
798 		break;
799 	      case 64:
800 		s = "complex128";
801 		break;
802 	      default:
803 		snprintf (buf, sizeof buf, "INVALID-complex-%u",
804 			  2 * TYPE_PRECISION (real_type));
805 		s = buf;
806 		ret = false;
807 		break;
808 	      }
809 	  }
810 	else
811 	  {
812 	    s = "INVALID-complex-non-real";
813 	    ret = false;
814 	  }
815 	obstack_grow (ob, s, strlen (s));
816       }
817       break;
818 
819     case BOOLEAN_TYPE:
820       obstack_grow (ob, "bool", 4);
821       break;
822 
823     case POINTER_TYPE:
824       if (use_type_name
825           && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
826           && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
827 	      || (POINTER_TYPE_P (TREE_TYPE (type))
828                   && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
829 		      == FUNCTION_TYPE))))
830         {
831 	  tree name;
832 	  void **slot;
833 
834 	  name = TYPE_IDENTIFIER (TREE_TYPE (type));
835 
836 	  slot = htab_find_slot (container->invalid_hash,
837 				 IDENTIFIER_POINTER (name), NO_INSERT);
838 	  if (slot != NULL)
839 	    ret = false;
840 
841 	  obstack_grow (ob, "*_", 2);
842 	  go_append_string (ob, name);
843 
844 	  /* The pointer here can be used without the struct or union
845 	     definition.  So this struct or union is a potential dummy
846 	     type.  */
847 	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
848 	    container->pot_dummy_types.add (IDENTIFIER_POINTER (name));
849 
850 	  return ret;
851         }
852       if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
853 	obstack_grow (ob, "func", 4);
854       else
855 	obstack_1grow (ob, '*');
856       if (VOID_TYPE_P (TREE_TYPE (type)))
857 	obstack_grow (ob, "byte", 4);
858       else
859 	{
860 	  if (!go_format_type (container, TREE_TYPE (type), use_type_name,
861 			       true, NULL, false))
862 	    ret = false;
863 	}
864       break;
865 
866     case ARRAY_TYPE:
867       obstack_1grow (ob, '[');
868       if (TYPE_DOMAIN (type) != NULL_TREE
869 	  && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
870 	  && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
871 	  && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
872 	  && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
873 	  && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
874 	  && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
875 	  && tree_fits_shwi_p (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
876 	{
877 	  char buf[100];
878 
879 	  snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
880 		    tree_to_shwi (TYPE_MAX_VALUE (TYPE_DOMAIN (type))));
881 	  obstack_grow (ob, buf, strlen (buf));
882 	}
883       else
884 	obstack_1grow (ob, '0');
885       obstack_1grow (ob, ']');
886       if (!go_format_type (container, TREE_TYPE (type), use_type_name, false,
887 			   NULL, false))
888 	ret = false;
889       break;
890 
891     case UNION_TYPE:
892       is_union = true;
893       /* Fall through to RECORD_TYPE case.  */
894       gcc_fallthrough ();
895     case RECORD_TYPE:
896       {
897 	unsigned int prev_field_end;
898 	unsigned int known_alignment;
899 	tree field;
900 	bool emitted_a_field;
901 
902 	/* FIXME: Why is this necessary?  Without it we can get a core
903 	   dump on the s390x headers, or from a file containing simply
904 	   "typedef struct S T;".  */
905 	layout_type (type);
906 
907 	prev_field_end = 0;
908 	known_alignment = 1;
909 	/* Anonymous records and unions are flattened, i.e. they are not put
910 	   into "struct { ... }".  */
911 	if (!is_anon_record_or_union)
912 	  obstack_grow (ob, "struct { ", 9);
913 	for (field = TYPE_FIELDS (type), emitted_a_field = false;
914 	     field != NULL_TREE;
915 	     field = TREE_CHAIN (field))
916 	  {
917 	    if (TREE_CODE (field) != FIELD_DECL)
918 	      continue;
919 	    if (DECL_BIT_FIELD (field))
920 	      /* Bit fields are replaced by padding.  */
921 	      continue;
922 	    /* Only the first non-bitfield field is emitted for unions.  */
923 	    if (!is_union || !emitted_a_field)
924 	      {
925 		/* Emit the field.  */
926 		bool field_ok;
927 		bool is_anon_substructure;
928 		unsigned int decl_align_unit;
929 		unsigned int decl_offset;
930 
931 		field_ok = true;
932 		emitted_a_field = true;
933 		is_anon_substructure =
934 		  (DECL_NAME (field) == NULL
935 		   && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
936 		       || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE));
937 		/* Keep track of the alignment of named substructures, either
938 		   of the whole record, or the alignment of the emitted field
939 		   (for unions).  */
940 		decl_align_unit = DECL_ALIGN_UNIT (field);
941 		if (!is_anon_substructure && decl_align_unit > known_alignment)
942 		  known_alignment = decl_align_unit;
943 		/* Pad to start of field.  */
944 		decl_offset =
945 		  TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field))
946 		  + precision_to_units
947 		  (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)));
948 		{
949 		  unsigned int align_unit;
950 
951 		  /* For anonymous records and unions there is no automatic
952 		     structure alignment, so use 1 as the alignment.  */
953 		  align_unit = (is_anon_substructure) ? 1 : decl_align_unit;
954 		  *p_art_i = go_append_padding
955 		    (ob, prev_field_end, decl_offset, align_unit, *p_art_i,
956 		     &prev_field_end);
957 		}
958 		if (DECL_SIZE_UNIT (field))
959 		  prev_field_end +=
960 		    TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
961 		/* Emit the field name, but not for anonymous records and
962 		   unions.  */
963 		if (!is_anon_substructure)
964 		  {
965 		    if (DECL_NAME (field) == NULL)
966 		      *p_art_i = go_append_artificial_name (ob, *p_art_i);
967 		    else
968 		      go_append_decl_name
969 			(ob, field, container->keyword_hash);
970 		    obstack_1grow (ob, ' ');
971 		  }
972 		/* Do not expand type if a record or union type or a function
973 		   pointer.  */
974 		if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
975 		    && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
976 			|| (POINTER_TYPE_P (TREE_TYPE (field))
977 			    && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
978 				== FUNCTION_TYPE))))
979 		  {
980 		    tree name;
981 		    void **slot;
982 
983 		    name = TYPE_IDENTIFIER (TREE_TYPE (field));
984 
985 		    slot = htab_find_slot (container->invalid_hash,
986 					   IDENTIFIER_POINTER (name),
987 					   NO_INSERT);
988 		    if (slot != NULL)
989 		      field_ok = false;
990 
991 		    obstack_1grow (ob, '_');
992 		    go_append_string (ob, name);
993 		  }
994 		else
995 		  {
996 		    if (!go_format_type (container, TREE_TYPE (field), true,
997 					 false, p_art_i, is_anon_substructure))
998 		      field_ok = false;
999 		  }
1000 		if (!is_anon_substructure)
1001 		  obstack_grow (ob, "; ", 2);
1002 		if (!field_ok)
1003 		  ret = false;
1004 	      }
1005 	  }
1006 	/* Padding.  */
1007 	*p_art_i = go_append_padding (ob, prev_field_end,
1008 				      TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)),
1009 				      1, *p_art_i, &prev_field_end);
1010 	/* Alignment.  */
1011 	if (!is_anon_record_or_union
1012 	    && known_alignment < TYPE_ALIGN_UNIT (type))
1013 	  {
1014 	    const char *s;
1015 	    char buf[100];
1016 
1017 	    /* Enforce proper record alignment.  */
1018 	    s = go_get_uinttype_for_precision
1019 	      (TYPE_ALIGN (type), TYPE_UNSIGNED (type));
1020 	    if (s == NULL)
1021 	      {
1022 		snprintf (buf, sizeof buf, "INVALID-int-%u%s",
1023 			  TYPE_ALIGN (type), TYPE_UNSIGNED (type) ? "u" : "");
1024 		s = buf;
1025 		ret = false;
1026 	      }
1027 	    *p_art_i = go_force_record_alignment (ob, s, *p_art_i, buf);
1028 	  }
1029 	if (!is_anon_record_or_union)
1030 	  obstack_1grow (ob, '}');
1031       }
1032     break;
1033 
1034     case FUNCTION_TYPE:
1035       {
1036 	tree arg_type;
1037 	bool is_varargs;
1038 	tree result;
1039 	function_args_iterator iter;
1040 	bool seen_arg;
1041 
1042 	/* Go has no way to write a type which is a function but not a
1043 	   pointer to a function.  */
1044 	if (!is_func_ok)
1045 	  {
1046 	    obstack_grow (ob, "func*", 5);
1047 	    ret = false;
1048 	  }
1049 
1050 	obstack_1grow (ob, '(');
1051 	is_varargs = stdarg_p (type);
1052 	seen_arg = false;
1053 	FOREACH_FUNCTION_ARGS (type, arg_type, iter)
1054 	  {
1055 	    if (VOID_TYPE_P (arg_type))
1056 	      break;
1057 	    if (seen_arg)
1058 	      obstack_grow (ob, ", ", 2);
1059 	    if (!go_format_type (container, arg_type, true, false, NULL, false))
1060 	      ret = false;
1061 	    seen_arg = true;
1062 	  }
1063 	if (is_varargs)
1064 	  {
1065 	    if (prototype_p (type))
1066 	      obstack_grow (ob, ", ", 2);
1067 	    obstack_grow (ob, "...interface{}", 14);
1068 	  }
1069 	obstack_1grow (ob, ')');
1070 
1071 	result = TREE_TYPE (type);
1072 	if (!VOID_TYPE_P (result))
1073 	  {
1074 	    obstack_1grow (ob, ' ');
1075 	    if (!go_format_type (container, result, use_type_name, false, NULL,
1076 				 false))
1077 	      ret = false;
1078 	  }
1079       }
1080       break;
1081 
1082     default:
1083       obstack_grow (ob, "INVALID-type", 12);
1084       ret = false;
1085       break;
1086     }
1087 
1088   return ret;
1089 }
1090 
1091 /* Output the type which was built on the type obstack, and then free
1092    it.  */
1093 
1094 static void
go_output_type(class godump_container * container)1095 go_output_type (class godump_container *container)
1096 {
1097   struct obstack *ob;
1098 
1099   ob = &container->type_obstack;
1100   obstack_1grow (ob, '\0');
1101   fputs ((char *) obstack_base (ob), go_dump_file);
1102   obstack_free (ob, obstack_base (ob));
1103 }
1104 
1105 /* Output a function declaration.  */
1106 
1107 static void
go_output_fndecl(class godump_container * container,tree decl)1108 go_output_fndecl (class godump_container *container, tree decl)
1109 {
1110   if (!go_format_type (container, TREE_TYPE (decl), false, true, NULL, false))
1111     fprintf (go_dump_file, "// ");
1112   fprintf (go_dump_file, "func _%s ",
1113 	   IDENTIFIER_POINTER (DECL_NAME (decl)));
1114   go_output_type (container);
1115   fprintf (go_dump_file, " __asm__(\"%s\")\n",
1116 	   IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
1117 }
1118 
1119 /* Output a typedef or something like a struct definition.  */
1120 
1121 static void
go_output_typedef(class godump_container * container,tree decl)1122 go_output_typedef (class godump_container *container, tree decl)
1123 {
1124   /* If we have an enum type, output the enum constants
1125      separately.  */
1126   if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
1127       && TYPE_SIZE (TREE_TYPE (decl)) != 0
1128       && !container->decls_seen.contains (TREE_TYPE (decl))
1129       && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
1130 	  || !container->decls_seen.contains
1131 				    (TYPE_CANONICAL (TREE_TYPE (decl)))))
1132     {
1133       tree element;
1134 
1135       for (element = TYPE_VALUES (TREE_TYPE (decl));
1136 	   element != NULL_TREE;
1137 	   element = TREE_CHAIN (element))
1138 	{
1139 	  const char *name;
1140 	  struct macro_hash_value *mhval;
1141 	  void **slot;
1142 	  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
1143 
1144 	  name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
1145 
1146 	  /* Sometimes a name will be defined as both an enum constant
1147 	     and a macro.  Avoid duplicate definition errors by
1148 	     treating enum constants as macros.  */
1149 	  mhval = XNEW (struct macro_hash_value);
1150 	  mhval->name = xstrdup (name);
1151 	  mhval->value = NULL;
1152 	  slot = htab_find_slot (macro_hash, mhval, INSERT);
1153 	  if (*slot != NULL)
1154 	    macro_hash_del (*slot);
1155 
1156 	  if (tree_fits_shwi_p (TREE_VALUE (element)))
1157 	    snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC,
1158 		     tree_to_shwi (TREE_VALUE (element)));
1159 	  else if (tree_fits_uhwi_p (TREE_VALUE (element)))
1160 	    snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_UNSIGNED,
1161 		      tree_to_uhwi (TREE_VALUE (element)));
1162 	  else
1163 	    print_hex (wi::to_wide (element), buf);
1164 
1165 	  mhval->value = xstrdup (buf);
1166 	  *slot = mhval;
1167 	}
1168       container->decls_seen.add (TREE_TYPE (decl));
1169       if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
1170 	container->decls_seen.add (TYPE_CANONICAL (TREE_TYPE (decl)));
1171     }
1172 
1173   if (DECL_NAME (decl) != NULL_TREE)
1174     {
1175       void **slot;
1176       const char *type;
1177 
1178       type = IDENTIFIER_POINTER (DECL_NAME (decl));
1179       /* If type defined already, skip.  */
1180       slot = htab_find_slot (container->type_hash, type, INSERT);
1181       if (*slot != NULL)
1182 	return;
1183       *slot = CONST_CAST (void *, (const void *) type);
1184 
1185       if (!go_format_type (container, TREE_TYPE (decl), true, false, NULL,
1186 			   false))
1187 	{
1188 	  fprintf (go_dump_file, "// ");
1189 	  slot = htab_find_slot (container->invalid_hash, type, INSERT);
1190 	  *slot = CONST_CAST (void *, (const void *) type);
1191 	}
1192       fprintf (go_dump_file, "type _%s ",
1193 	       IDENTIFIER_POINTER (DECL_NAME (decl)));
1194       go_output_type (container);
1195 
1196       if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1197 	{
1198 	  HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
1199 
1200 	  if (size > 0)
1201 	    fprintf (go_dump_file,
1202 		     "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1203 		     IDENTIFIER_POINTER (DECL_NAME (decl)),
1204 		     size);
1205 	}
1206 
1207       container->decls_seen.add (decl);
1208     }
1209   else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1210     {
1211        void **slot;
1212        const char *type;
1213        HOST_WIDE_INT size;
1214 
1215        type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
1216        /* If type defined already, skip.  */
1217        slot = htab_find_slot (container->type_hash, type, INSERT);
1218        if (*slot != NULL)
1219          return;
1220        *slot = CONST_CAST (void *, (const void *) type);
1221 
1222        if (!go_format_type (container, TREE_TYPE (decl), false, false, NULL,
1223 			    false))
1224 	 {
1225 	   fprintf (go_dump_file, "// ");
1226 	   slot = htab_find_slot (container->invalid_hash, type, INSERT);
1227 	   *slot = CONST_CAST (void *, (const void *) type);
1228 	 }
1229        fprintf (go_dump_file, "type _%s ",
1230 	       IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
1231        go_output_type (container);
1232 
1233        size = int_size_in_bytes (TREE_TYPE (decl));
1234        if (size > 0)
1235 	 fprintf (go_dump_file,
1236 		  "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1237 		  IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))),
1238 		  size);
1239     }
1240   else
1241     return;
1242 
1243   fprintf (go_dump_file, "\n");
1244 }
1245 
1246 /* Output a variable.  */
1247 
1248 static void
go_output_var(class godump_container * container,tree decl)1249 go_output_var (class godump_container *container, tree decl)
1250 {
1251   bool is_valid;
1252   tree type_name;
1253   tree id;
1254 
1255   if (container->decls_seen.contains (decl)
1256       || container->decls_seen.contains (DECL_NAME (decl)))
1257     return;
1258   container->decls_seen.add (decl);
1259   container->decls_seen.add (DECL_NAME (decl));
1260 
1261   type_name = TYPE_NAME (TREE_TYPE (decl));
1262   id = NULL_TREE;
1263   if (type_name != NULL_TREE && TREE_CODE (type_name) == IDENTIFIER_NODE)
1264     id = type_name;
1265   else if (type_name != NULL_TREE && TREE_CODE (type_name) == TYPE_DECL
1266 	   && DECL_SOURCE_LOCATION (type_name) != BUILTINS_LOCATION
1267 	   && DECL_NAME (type_name))
1268     id = DECL_NAME (type_name);
1269   if (id != NULL_TREE
1270       && (!htab_find_slot (container->type_hash, IDENTIFIER_POINTER (id),
1271 			   NO_INSERT)
1272 	  || htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (id),
1273 			     NO_INSERT)))
1274     id = NULL_TREE;
1275   if (id != NULL_TREE)
1276     {
1277       struct obstack *ob;
1278 
1279       ob = &container->type_obstack;
1280       obstack_1grow (ob, '_');
1281       go_append_string (ob, id);
1282       is_valid = htab_find_slot (container->type_hash, IDENTIFIER_POINTER (id),
1283 				 NO_INSERT) != NULL;
1284     }
1285   else
1286     is_valid = go_format_type (container, TREE_TYPE (decl), true, false, NULL,
1287 			       false);
1288   if (is_valid
1289       && htab_find_slot (container->type_hash,
1290 			 IDENTIFIER_POINTER (DECL_NAME (decl)),
1291 			 NO_INSERT) != NULL)
1292     {
1293       /* There is already a type with this name, probably from a
1294 	 struct tag.  Prefer the type to the variable.  */
1295       is_valid = false;
1296     }
1297   if (!is_valid)
1298     fprintf (go_dump_file, "// ");
1299 
1300   fprintf (go_dump_file, "var _%s ",
1301 	   IDENTIFIER_POINTER (DECL_NAME (decl)));
1302   go_output_type (container);
1303   fprintf (go_dump_file, "\n");
1304 
1305   /* Sometimes an extern variable is declared with an unknown struct
1306      type.  */
1307   if (type_name != NULL_TREE && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1308     {
1309       if (TREE_CODE (type_name) == IDENTIFIER_NODE)
1310 	container->pot_dummy_types.add (IDENTIFIER_POINTER (type_name));
1311       else if (TREE_CODE (type_name) == TYPE_DECL)
1312 	container->pot_dummy_types.add
1313 			    (IDENTIFIER_POINTER (DECL_NAME (type_name)));
1314     }
1315 }
1316 
1317 /* Output the final value of a preprocessor macro or enum constant.
1318    This is called via htab_traverse_noresize.  */
1319 
1320 static int
go_print_macro(void ** slot,void * arg ATTRIBUTE_UNUSED)1321 go_print_macro (void **slot, void *arg ATTRIBUTE_UNUSED)
1322 {
1323   struct macro_hash_value *mhval = (struct macro_hash_value *) *slot;
1324   fprintf (go_dump_file, "const _%s = %s\n", mhval->name, mhval->value);
1325   return 1;
1326 }
1327 
1328 /* Build a hash table with the Go keywords.  */
1329 
1330 static const char * const keywords[] = {
1331   "__asm__", "break", "case", "chan", "const", "continue", "default",
1332   "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
1333   "import", "interface", "map", "package", "range", "return", "select",
1334   "struct", "switch", "type", "var"
1335 };
1336 
1337 static void
keyword_hash_init(class godump_container * container)1338 keyword_hash_init (class godump_container *container)
1339 {
1340   size_t i;
1341   size_t count = sizeof (keywords) / sizeof (keywords[0]);
1342   void **slot;
1343 
1344   for (i = 0; i < count; i++)
1345     {
1346       slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1347       *slot = CONST_CAST (void *, (const void *) keywords[i]);
1348     }
1349 }
1350 
1351 /* Traversing the pot_dummy_types and seeing which types are present
1352    in the global types hash table and creating dummy definitions if
1353    not found.  This function is invoked by hash_set::traverse.  */
1354 
1355 bool
find_dummy_types(const char * const & ptr,godump_container * adata)1356 find_dummy_types (const char *const &ptr, godump_container *adata)
1357 {
1358   class godump_container *data = (class godump_container *) adata;
1359   const char *type = (const char *) ptr;
1360   void **slot;
1361   void **islot;
1362 
1363   slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1364   islot = htab_find_slot (data->invalid_hash, type, NO_INSERT);
1365   if (slot == NULL || islot != NULL)
1366     fprintf (go_dump_file, "type _%s struct {}\n", type);
1367   return true;
1368 }
1369 
1370 /* Output symbols.  */
1371 
1372 static void
go_finish(const char * filename)1373 go_finish (const char *filename)
1374 {
1375   class godump_container container;
1376   unsigned int ix;
1377   tree decl;
1378 
1379   real_debug_hooks->finish (filename);
1380 
1381   container.type_hash = htab_create (100, htab_hash_string,
1382                                      string_hash_eq, NULL);
1383   container.invalid_hash = htab_create (10, htab_hash_string,
1384 					string_hash_eq, NULL);
1385   container.keyword_hash = htab_create (50, htab_hash_string,
1386                                         string_hash_eq, NULL);
1387   obstack_init (&container.type_obstack);
1388 
1389   keyword_hash_init (&container);
1390 
1391   FOR_EACH_VEC_SAFE_ELT (queue, ix, decl)
1392     {
1393       switch (TREE_CODE (decl))
1394 	{
1395 	case FUNCTION_DECL:
1396 	  go_output_fndecl (&container, decl);
1397 	  break;
1398 
1399 	case TYPE_DECL:
1400 	  go_output_typedef (&container, decl);
1401 	  break;
1402 
1403 	case VAR_DECL:
1404 	  go_output_var (&container, decl);
1405 	  break;
1406 
1407 	default:
1408 	  gcc_unreachable ();
1409 	}
1410     }
1411 
1412   htab_traverse_noresize (macro_hash, go_print_macro, NULL);
1413 
1414   /* To emit dummy definitions.  */
1415   container.pot_dummy_types.traverse<godump_container *, find_dummy_types>
1416                         (&container);
1417 
1418   htab_delete (container.type_hash);
1419   htab_delete (container.invalid_hash);
1420   htab_delete (container.keyword_hash);
1421   obstack_free (&container.type_obstack, NULL);
1422 
1423   vec_free (queue);
1424 
1425   if (fclose (go_dump_file) != 0)
1426     error ("could not close Go dump file: %m");
1427   go_dump_file = NULL;
1428 }
1429 
1430 /* Set up our hooks.  */
1431 
1432 const struct gcc_debug_hooks *
dump_go_spec_init(const char * filename,const struct gcc_debug_hooks * hooks)1433 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1434 {
1435   go_dump_file = fopen (filename, "w");
1436   if (go_dump_file == NULL)
1437     {
1438       error ("could not open Go dump file %qs: %m", filename);
1439       return hooks;
1440     }
1441 
1442   go_debug_hooks = *hooks;
1443   real_debug_hooks = hooks;
1444 
1445   go_debug_hooks.finish = go_finish;
1446   go_debug_hooks.define = go_define;
1447   go_debug_hooks.undef = go_undef;
1448   go_debug_hooks.function_decl = go_function_decl;
1449   go_debug_hooks.early_global_decl = go_early_global_decl;
1450   go_debug_hooks.late_global_decl = go_late_global_decl;
1451   go_debug_hooks.type_decl = go_type_decl;
1452 
1453   macro_hash = htab_create (100, macro_hash_hashval, macro_hash_eq,
1454 			    macro_hash_del);
1455 
1456   return &go_debug_hooks;
1457 }
1458 
1459 #include "gt-godump.h"
1460