1 /* Output Go language descriptions of types.
2    Copyright (C) 2008-2018 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 struct godump_container
539 {
540   /* DECLs that we have already seen.  */
541   hash_set<tree> decls_seen;
542 
543   /* Types which may potentially have to be defined as dummy
544      types.  */
545   hash_set<const char *> pot_dummy_types;
546 
547   /* Go keywords.  */
548   htab_t keyword_hash;
549 
550   /* Global type definitions.  */
551   htab_t type_hash;
552 
553   /* Invalid types.  */
554   htab_t invalid_hash;
555 
556   /* Obstack used to write out a type definition.  */
557   struct obstack type_obstack;
558 };
559 
560 /* Append an IDENTIFIER_NODE to OB.  */
561 
562 static void
go_append_string(struct obstack * ob,tree id)563 go_append_string (struct obstack *ob, tree id)
564 {
565   obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
566 }
567 
568 /* Given an integer PRECISION in bits, returns a constant string that is the
569    matching go int or uint type (depending on the IS_UNSIGNED flag).  Returns a
570    NULL pointer if there is no matching go type.  */
571 
572 static const char *
go_get_uinttype_for_precision(unsigned int precision,bool is_unsigned)573 go_get_uinttype_for_precision (unsigned int precision, bool is_unsigned)
574 {
575   switch (precision)
576     {
577     case 8:
578       return is_unsigned ? "uint8" : "int8";
579     case 16:
580       return is_unsigned ? "uint16" : "int16";
581     case 32:
582       return is_unsigned ? "uint32" : "int32";
583     case 64:
584       return is_unsigned ? "uint64" : "int64";
585     default:
586       return NULL;
587     }
588 }
589 
590 /* Append an artificial variable name with the suffix _INDEX to OB.  Returns
591    INDEX + 1.  */
592 
593 static unsigned int
go_append_artificial_name(struct obstack * ob,unsigned int index)594 go_append_artificial_name (struct obstack *ob, unsigned int index)
595 {
596   char buf[100];
597 
598   /* FIXME: identifier may not be unique.  */
599   obstack_grow (ob, "Godump_", 7);
600   snprintf (buf, sizeof buf, "%u", index);
601   obstack_grow (ob, buf, strlen (buf));
602 
603   return index + 1;
604 }
605 
606 /* Append the variable name from DECL to OB.  If the name is in the
607    KEYWORD_HASH, prepend an '_'.  */
608 
609 static void
go_append_decl_name(struct obstack * ob,tree decl,htab_t keyword_hash)610 go_append_decl_name (struct obstack *ob, tree decl, htab_t keyword_hash)
611 {
612   const char *var_name;
613   void **slot;
614 
615   /* Start variable name with an underscore if a keyword.  */
616   var_name = IDENTIFIER_POINTER (DECL_NAME (decl));
617   slot = htab_find_slot (keyword_hash, var_name, NO_INSERT);
618   if (slot != NULL)
619     obstack_1grow (ob, '_');
620   go_append_string (ob, DECL_NAME (decl));
621 }
622 
623 /* Appends a byte array with the necessary number of elements and the name
624    "Godump_INDEX_pad" to pad from FROM_OFFSET to TO_OFFSET to OB assuming that
625    the next field is automatically aligned to ALIGN_UNITS.  Returns INDEX + 1,
626    or INDEX if no padding had to be appended.  The resulting offset where the
627    next field is allocated is returned through RET_OFFSET.  */
628 
629 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)630 go_append_padding (struct obstack *ob, unsigned int from_offset,
631 		   unsigned int to_offset, unsigned int align_units,
632 		   unsigned int index, unsigned int *ret_offset)
633 {
634   if (from_offset % align_units > 0)
635     from_offset += align_units - (from_offset % align_units);
636   gcc_assert (to_offset >= from_offset);
637   if (to_offset > from_offset)
638     {
639       char buf[100];
640 
641       index = go_append_artificial_name (ob, index);
642       snprintf (buf, sizeof buf, "_pad [%u]byte; ", to_offset - from_offset);
643       obstack_grow (ob, buf, strlen (buf));
644     }
645   *ret_offset = to_offset;
646 
647   return index;
648 }
649 
650 /* Appends an array of type TYPE_STRING with zero elements and the name
651    "Godump_INDEX_align" to OB.  If TYPE_STRING is a null pointer, ERROR_STRING
652    is appended instead of the type.  Returns INDEX + 1.  */
653 
654 static unsigned int
go_force_record_alignment(struct obstack * ob,const char * type_string,unsigned int index,const char * error_string)655 go_force_record_alignment (struct obstack *ob, const char *type_string,
656 			   unsigned int index, const char *error_string)
657 {
658   index = go_append_artificial_name (ob, index);
659   obstack_grow (ob, "_align ", 7);
660   if (type_string == NULL)
661     obstack_grow (ob, error_string, strlen (error_string));
662   else
663     {
664       obstack_grow (ob, "[0]", 3);
665       obstack_grow (ob, type_string, strlen (type_string));
666     }
667   obstack_grow (ob, "; ", 2);
668 
669   return index;
670 }
671 
672 /* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
673    USE_TYPE_NAME is true if we can simply use a type name here without
674    needing to define it.  IS_FUNC_OK is true if we can output a func
675    type here; the "func" keyword will already have been added.
676    Return true if the type can be represented in Go, false otherwise.
677    P_ART_I is used for indexing artificial elements in nested structures and
678    should always be a NULL pointer when called, except by certain recursive
679    calls from go_format_type() itself.  */
680 
681 static bool
go_format_type(struct godump_container * container,tree type,bool use_type_name,bool is_func_ok,unsigned int * p_art_i,bool is_anon_record_or_union)682 go_format_type (struct godump_container *container, tree type,
683 		bool use_type_name, bool is_func_ok, unsigned int *p_art_i,
684 		bool is_anon_record_or_union)
685 {
686   bool ret;
687   struct obstack *ob;
688   unsigned int art_i_dummy;
689   bool is_union = false;
690 
691   if (p_art_i == NULL)
692     {
693       art_i_dummy = 0;
694       p_art_i = &art_i_dummy;
695     }
696   ret = true;
697   ob = &container->type_obstack;
698 
699   if (TYPE_NAME (type) != NULL_TREE
700       && (container->decls_seen.contains (type)
701 	  || container->decls_seen.contains (TYPE_NAME (type)))
702       && (AGGREGATE_TYPE_P (type)
703 	  || POINTER_TYPE_P (type)
704 	  || TREE_CODE (type) == FUNCTION_TYPE))
705     {
706       tree name;
707       void **slot;
708 
709       name = TYPE_IDENTIFIER (type);
710 
711       slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
712 			     NO_INSERT);
713       if (slot != NULL)
714 	ret = false;
715 
716       obstack_1grow (ob, '_');
717       go_append_string (ob, name);
718       return ret;
719     }
720 
721   container->decls_seen.add (type);
722 
723   switch (TREE_CODE (type))
724     {
725     case TYPE_DECL:
726       {
727 	void **slot;
728 
729 	slot = htab_find_slot (container->invalid_hash,
730 			       IDENTIFIER_POINTER (DECL_NAME (type)),
731 			       NO_INSERT);
732 	if (slot != NULL)
733 	  ret = false;
734 
735 	obstack_1grow (ob, '_');
736 	go_append_string (ob, DECL_NAME (type));
737       }
738       break;
739 
740     case ENUMERAL_TYPE:
741     case INTEGER_TYPE:
742       {
743 	const char *s;
744 	char buf[100];
745 
746 	s = go_get_uinttype_for_precision (TYPE_PRECISION (type),
747 					   TYPE_UNSIGNED (type));
748 	if (s == NULL)
749 	  {
750 	    snprintf (buf, sizeof buf, "INVALID-int-%u%s",
751 		      TYPE_PRECISION (type),
752 		      TYPE_UNSIGNED (type) ? "u" : "");
753 	    s = buf;
754 	    ret = false;
755 	  }
756 	obstack_grow (ob, s, strlen (s));
757       }
758       break;
759 
760     case REAL_TYPE:
761       {
762 	const char *s;
763 	char buf[100];
764 
765 	switch (TYPE_PRECISION (type))
766 	  {
767 	  case 32:
768 	    s = "float32";
769 	    break;
770 	  case 64:
771 	    s = "float64";
772 	    break;
773 	  default:
774 	    snprintf (buf, sizeof buf, "INVALID-float-%u",
775 		      TYPE_PRECISION (type));
776 	    s = buf;
777 	    ret = false;
778 	    break;
779 	  }
780 	obstack_grow (ob, s, strlen (s));
781       }
782       break;
783 
784     case COMPLEX_TYPE:
785       {
786 	const char *s;
787 	char buf[100];
788 	tree real_type;
789 
790 	real_type = TREE_TYPE (type);
791 	if (TREE_CODE (real_type) == REAL_TYPE)
792 	  {
793 	    switch (TYPE_PRECISION (real_type))
794 	      {
795 	      case 32:
796 		s = "complex64";
797 		break;
798 	      case 64:
799 		s = "complex128";
800 		break;
801 	      default:
802 		snprintf (buf, sizeof buf, "INVALID-complex-%u",
803 			  2 * TYPE_PRECISION (real_type));
804 		s = buf;
805 		ret = false;
806 		break;
807 	      }
808 	  }
809 	else
810 	  {
811 	    s = "INVALID-complex-non-real";
812 	    ret = false;
813 	  }
814 	obstack_grow (ob, s, strlen (s));
815       }
816       break;
817 
818     case BOOLEAN_TYPE:
819       obstack_grow (ob, "bool", 4);
820       break;
821 
822     case POINTER_TYPE:
823       if (use_type_name
824           && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
825           && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
826 	      || (POINTER_TYPE_P (TREE_TYPE (type))
827                   && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
828 		      == FUNCTION_TYPE))))
829         {
830 	  tree name;
831 	  void **slot;
832 
833 	  name = TYPE_IDENTIFIER (TREE_TYPE (type));
834 
835 	  slot = htab_find_slot (container->invalid_hash,
836 				 IDENTIFIER_POINTER (name), NO_INSERT);
837 	  if (slot != NULL)
838 	    ret = false;
839 
840 	  obstack_grow (ob, "*_", 2);
841 	  go_append_string (ob, name);
842 
843 	  /* The pointer here can be used without the struct or union
844 	     definition.  So this struct or union is a potential dummy
845 	     type.  */
846 	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
847 	    container->pot_dummy_types.add (IDENTIFIER_POINTER (name));
848 
849 	  return ret;
850         }
851       if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
852 	obstack_grow (ob, "func", 4);
853       else
854 	obstack_1grow (ob, '*');
855       if (VOID_TYPE_P (TREE_TYPE (type)))
856 	obstack_grow (ob, "byte", 4);
857       else
858 	{
859 	  if (!go_format_type (container, TREE_TYPE (type), use_type_name,
860 			       true, NULL, false))
861 	    ret = false;
862 	}
863       break;
864 
865     case ARRAY_TYPE:
866       obstack_1grow (ob, '[');
867       if (TYPE_DOMAIN (type) != NULL_TREE
868 	  && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
869 	  && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
870 	  && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
871 	  && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
872 	  && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
873 	  && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
874 	  && tree_fits_shwi_p (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
875 	{
876 	  char buf[100];
877 
878 	  snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
879 		    tree_to_shwi (TYPE_MAX_VALUE (TYPE_DOMAIN (type))));
880 	  obstack_grow (ob, buf, strlen (buf));
881 	}
882       else
883 	obstack_1grow (ob, '0');
884       obstack_1grow (ob, ']');
885       if (!go_format_type (container, TREE_TYPE (type), use_type_name, false,
886 			   NULL, false))
887 	ret = false;
888       break;
889 
890     case UNION_TYPE:
891       is_union = true;
892       /* Fall through to RECORD_TYPE case.  */
893       gcc_fallthrough ();
894     case RECORD_TYPE:
895       {
896 	unsigned int prev_field_end;
897 	unsigned int known_alignment;
898 	tree field;
899 	bool emitted_a_field;
900 
901 	/* FIXME: Why is this necessary?  Without it we can get a core
902 	   dump on the s390x headers, or from a file containing simply
903 	   "typedef struct S T;".  */
904 	layout_type (type);
905 
906 	prev_field_end = 0;
907 	known_alignment = 1;
908 	/* Anonymous records and unions are flattened, i.e. they are not put
909 	   into "struct { ... }".  */
910 	if (!is_anon_record_or_union)
911 	  obstack_grow (ob, "struct { ", 9);
912 	for (field = TYPE_FIELDS (type), emitted_a_field = false;
913 	     field != NULL_TREE;
914 	     field = TREE_CHAIN (field))
915 	  {
916 	    if (TREE_CODE (field) != FIELD_DECL)
917 	      continue;
918 	    if (DECL_BIT_FIELD (field))
919 	      /* Bit fields are replaced by padding.  */
920 	      continue;
921 	    /* Only the first non-bitfield field is emitted for unions.  */
922 	    if (!is_union || !emitted_a_field)
923 	      {
924 		/* Emit the field.  */
925 		bool field_ok;
926 		bool is_anon_substructure;
927 		unsigned int decl_align_unit;
928 		unsigned int decl_offset;
929 
930 		field_ok = true;
931 		emitted_a_field = true;
932 		is_anon_substructure =
933 		  (DECL_NAME (field) == NULL
934 		   && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
935 		       || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE));
936 		/* Keep track of the alignment of named substructures, either
937 		   of the whole record, or the alignment of the emitted field
938 		   (for unions).  */
939 		decl_align_unit = DECL_ALIGN_UNIT (field);
940 		if (!is_anon_substructure && decl_align_unit > known_alignment)
941 		  known_alignment = decl_align_unit;
942 		/* Pad to start of field.  */
943 		decl_offset =
944 		  TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field))
945 		  + precision_to_units
946 		  (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)));
947 		{
948 		  unsigned int align_unit;
949 
950 		  /* For anonymous records and unions there is no automatic
951 		     structure alignment, so use 1 as the alignment.  */
952 		  align_unit = (is_anon_substructure) ? 1 : decl_align_unit;
953 		  *p_art_i = go_append_padding
954 		    (ob, prev_field_end, decl_offset, align_unit, *p_art_i,
955 		     &prev_field_end);
956 		}
957 		if (DECL_SIZE_UNIT (field))
958 		  prev_field_end +=
959 		    TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
960 		/* Emit the field name, but not for anonymous records and
961 		   unions.  */
962 		if (!is_anon_substructure)
963 		  {
964 		    if ((DECL_NAME (field) == NULL))
965 		      *p_art_i = go_append_artificial_name (ob, *p_art_i);
966 		    else
967 		      go_append_decl_name
968 			(ob, field, container->keyword_hash);
969 		    obstack_1grow (ob, ' ');
970 		  }
971 		/* Do not expand type if a record or union type or a function
972 		   pointer.  */
973 		if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
974 		    && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
975 			|| (POINTER_TYPE_P (TREE_TYPE (field))
976 			    && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
977 				== FUNCTION_TYPE))))
978 		  {
979 		    tree name;
980 		    void **slot;
981 
982 		    name = TYPE_IDENTIFIER (TREE_TYPE (field));
983 
984 		    slot = htab_find_slot (container->invalid_hash,
985 					   IDENTIFIER_POINTER (name),
986 					   NO_INSERT);
987 		    if (slot != NULL)
988 		      field_ok = false;
989 
990 		    obstack_1grow (ob, '_');
991 		    go_append_string (ob, name);
992 		  }
993 		else
994 		  {
995 		    if (!go_format_type (container, TREE_TYPE (field), true,
996 					 false, p_art_i, is_anon_substructure))
997 		      field_ok = false;
998 		  }
999 		if (!is_anon_substructure)
1000 		  obstack_grow (ob, "; ", 2);
1001 		if (!field_ok)
1002 		  ret = false;
1003 	      }
1004 	  }
1005 	/* Padding.  */
1006 	*p_art_i = go_append_padding (ob, prev_field_end,
1007 				      TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)),
1008 				      1, *p_art_i, &prev_field_end);
1009 	/* Alignment.  */
1010 	if (!is_anon_record_or_union
1011 	    && known_alignment < TYPE_ALIGN_UNIT (type))
1012 	  {
1013 	    const char *s;
1014 	    char buf[100];
1015 
1016 	    /* Enforce proper record alignment.  */
1017 	    s = go_get_uinttype_for_precision
1018 	      (TYPE_ALIGN (type), TYPE_UNSIGNED (type));
1019 	    if (s == NULL)
1020 	      {
1021 		snprintf (buf, sizeof buf, "INVALID-int-%u%s",
1022 			  TYPE_ALIGN (type), TYPE_UNSIGNED (type) ? "u" : "");
1023 		s = buf;
1024 		ret = false;
1025 	      }
1026 	    *p_art_i = go_force_record_alignment (ob, s, *p_art_i, buf);
1027 	  }
1028 	if (!is_anon_record_or_union)
1029 	  obstack_1grow (ob, '}');
1030       }
1031     break;
1032 
1033     case FUNCTION_TYPE:
1034       {
1035 	tree arg_type;
1036 	bool is_varargs;
1037 	tree result;
1038 	function_args_iterator iter;
1039 	bool seen_arg;
1040 
1041 	/* Go has no way to write a type which is a function but not a
1042 	   pointer to a function.  */
1043 	if (!is_func_ok)
1044 	  {
1045 	    obstack_grow (ob, "func*", 5);
1046 	    ret = false;
1047 	  }
1048 
1049 	obstack_1grow (ob, '(');
1050 	is_varargs = stdarg_p (type);
1051 	seen_arg = false;
1052 	FOREACH_FUNCTION_ARGS (type, arg_type, iter)
1053 	  {
1054 	    if (VOID_TYPE_P (arg_type))
1055 	      break;
1056 	    if (seen_arg)
1057 	      obstack_grow (ob, ", ", 2);
1058 	    if (!go_format_type (container, arg_type, true, false, NULL, false))
1059 	      ret = false;
1060 	    seen_arg = true;
1061 	  }
1062 	if (is_varargs)
1063 	  {
1064 	    if (prototype_p (type))
1065 	      obstack_grow (ob, ", ", 2);
1066 	    obstack_grow (ob, "...interface{}", 14);
1067 	  }
1068 	obstack_1grow (ob, ')');
1069 
1070 	result = TREE_TYPE (type);
1071 	if (!VOID_TYPE_P (result))
1072 	  {
1073 	    obstack_1grow (ob, ' ');
1074 	    if (!go_format_type (container, result, use_type_name, false, NULL,
1075 				 false))
1076 	      ret = false;
1077 	  }
1078       }
1079       break;
1080 
1081     default:
1082       obstack_grow (ob, "INVALID-type", 12);
1083       ret = false;
1084       break;
1085     }
1086 
1087   return ret;
1088 }
1089 
1090 /* Output the type which was built on the type obstack, and then free
1091    it.  */
1092 
1093 static void
go_output_type(struct godump_container * container)1094 go_output_type (struct godump_container *container)
1095 {
1096   struct obstack *ob;
1097 
1098   ob = &container->type_obstack;
1099   obstack_1grow (ob, '\0');
1100   fputs ((char *) obstack_base (ob), go_dump_file);
1101   obstack_free (ob, obstack_base (ob));
1102 }
1103 
1104 /* Output a function declaration.  */
1105 
1106 static void
go_output_fndecl(struct godump_container * container,tree decl)1107 go_output_fndecl (struct godump_container *container, tree decl)
1108 {
1109   if (!go_format_type (container, TREE_TYPE (decl), false, true, NULL, false))
1110     fprintf (go_dump_file, "// ");
1111   fprintf (go_dump_file, "func _%s ",
1112 	   IDENTIFIER_POINTER (DECL_NAME (decl)));
1113   go_output_type (container);
1114   fprintf (go_dump_file, " __asm__(\"%s\")\n",
1115 	   IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
1116 }
1117 
1118 /* Output a typedef or something like a struct definition.  */
1119 
1120 static void
go_output_typedef(struct godump_container * container,tree decl)1121 go_output_typedef (struct godump_container *container, tree decl)
1122 {
1123   /* If we have an enum type, output the enum constants
1124      separately.  */
1125   if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
1126       && TYPE_SIZE (TREE_TYPE (decl)) != 0
1127       && !container->decls_seen.contains (TREE_TYPE (decl))
1128       && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
1129 	  || !container->decls_seen.contains
1130 				    (TYPE_CANONICAL (TREE_TYPE (decl)))))
1131     {
1132       tree element;
1133 
1134       for (element = TYPE_VALUES (TREE_TYPE (decl));
1135 	   element != NULL_TREE;
1136 	   element = TREE_CHAIN (element))
1137 	{
1138 	  const char *name;
1139 	  struct macro_hash_value *mhval;
1140 	  void **slot;
1141 	  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
1142 
1143 	  name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
1144 
1145 	  /* Sometimes a name will be defined as both an enum constant
1146 	     and a macro.  Avoid duplicate definition errors by
1147 	     treating enum constants as macros.  */
1148 	  mhval = XNEW (struct macro_hash_value);
1149 	  mhval->name = xstrdup (name);
1150 	  mhval->value = NULL;
1151 	  slot = htab_find_slot (macro_hash, mhval, INSERT);
1152 	  if (*slot != NULL)
1153 	    macro_hash_del (*slot);
1154 
1155 	  if (tree_fits_shwi_p (TREE_VALUE (element)))
1156 	    snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC,
1157 		     tree_to_shwi (TREE_VALUE (element)));
1158 	  else if (tree_fits_uhwi_p (TREE_VALUE (element)))
1159 	    snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_UNSIGNED,
1160 		      tree_to_uhwi (TREE_VALUE (element)));
1161 	  else
1162 	    print_hex (wi::to_wide (element), buf);
1163 
1164 	  mhval->value = xstrdup (buf);
1165 	  *slot = mhval;
1166 	}
1167       container->decls_seen.add (TREE_TYPE (decl));
1168       if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
1169 	container->decls_seen.add (TYPE_CANONICAL (TREE_TYPE (decl)));
1170     }
1171 
1172   if (DECL_NAME (decl) != NULL_TREE)
1173     {
1174       void **slot;
1175       const char *type;
1176 
1177       type = IDENTIFIER_POINTER (DECL_NAME (decl));
1178       /* If type defined already, skip.  */
1179       slot = htab_find_slot (container->type_hash, type, INSERT);
1180       if (*slot != NULL)
1181 	return;
1182       *slot = CONST_CAST (void *, (const void *) type);
1183 
1184       if (!go_format_type (container, TREE_TYPE (decl), false, false, NULL,
1185 			   false))
1186 	{
1187 	  fprintf (go_dump_file, "// ");
1188 	  slot = htab_find_slot (container->invalid_hash, type, INSERT);
1189 	  *slot = CONST_CAST (void *, (const void *) type);
1190 	}
1191       fprintf (go_dump_file, "type _%s ",
1192 	       IDENTIFIER_POINTER (DECL_NAME (decl)));
1193       go_output_type (container);
1194 
1195       if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1196 	{
1197 	  HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
1198 
1199 	  if (size > 0)
1200 	    fprintf (go_dump_file,
1201 		     "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1202 		     IDENTIFIER_POINTER (DECL_NAME (decl)),
1203 		     size);
1204 	}
1205 
1206       container->decls_seen.add (decl);
1207     }
1208   else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1209     {
1210        void **slot;
1211        const char *type;
1212        HOST_WIDE_INT size;
1213 
1214        type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
1215        /* If type defined already, skip.  */
1216        slot = htab_find_slot (container->type_hash, type, INSERT);
1217        if (*slot != NULL)
1218          return;
1219        *slot = CONST_CAST (void *, (const void *) type);
1220 
1221        if (!go_format_type (container, TREE_TYPE (decl), false, false, NULL,
1222 			    false))
1223 	 {
1224 	   fprintf (go_dump_file, "// ");
1225 	   slot = htab_find_slot (container->invalid_hash, type, INSERT);
1226 	   *slot = CONST_CAST (void *, (const void *) type);
1227 	 }
1228        fprintf (go_dump_file, "type _%s ",
1229 	       IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
1230        go_output_type (container);
1231 
1232        size = int_size_in_bytes (TREE_TYPE (decl));
1233        if (size > 0)
1234 	 fprintf (go_dump_file,
1235 		  "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1236 		  IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))),
1237 		  size);
1238     }
1239   else
1240     return;
1241 
1242   fprintf (go_dump_file, "\n");
1243 }
1244 
1245 /* Output a variable.  */
1246 
1247 static void
go_output_var(struct godump_container * container,tree decl)1248 go_output_var (struct godump_container *container, tree decl)
1249 {
1250   bool is_valid;
1251   tree type_name;
1252   tree id;
1253 
1254   if (container->decls_seen.contains (decl)
1255       || container->decls_seen.contains (DECL_NAME (decl)))
1256     return;
1257   container->decls_seen.add (decl);
1258   container->decls_seen.add (DECL_NAME (decl));
1259 
1260   type_name = TYPE_NAME (TREE_TYPE (decl));
1261   id = NULL_TREE;
1262   if (type_name != NULL_TREE && TREE_CODE (type_name) == IDENTIFIER_NODE)
1263     id = type_name;
1264   else if (type_name != NULL_TREE && TREE_CODE (type_name) == TYPE_DECL
1265 	   && DECL_SOURCE_LOCATION (type_name) != BUILTINS_LOCATION
1266 	   && DECL_NAME (type_name))
1267     id = DECL_NAME (type_name);
1268   if (id != NULL_TREE
1269       && (!htab_find_slot (container->type_hash, IDENTIFIER_POINTER (id),
1270 			   NO_INSERT)
1271 	  || htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (id),
1272 			     NO_INSERT)))
1273     id = NULL_TREE;
1274   if (id != NULL_TREE)
1275     {
1276       struct obstack *ob;
1277 
1278       ob = &container->type_obstack;
1279       obstack_1grow (ob, '_');
1280       go_append_string (ob, id);
1281       is_valid = htab_find_slot (container->type_hash, IDENTIFIER_POINTER (id),
1282 				 NO_INSERT) != NULL;
1283     }
1284   else
1285     is_valid = go_format_type (container, TREE_TYPE (decl), true, false, NULL,
1286 			       false);
1287   if (is_valid
1288       && htab_find_slot (container->type_hash,
1289 			 IDENTIFIER_POINTER (DECL_NAME (decl)),
1290 			 NO_INSERT) != NULL)
1291     {
1292       /* There is already a type with this name, probably from a
1293 	 struct tag.  Prefer the type to the variable.  */
1294       is_valid = false;
1295     }
1296   if (!is_valid)
1297     fprintf (go_dump_file, "// ");
1298 
1299   fprintf (go_dump_file, "var _%s ",
1300 	   IDENTIFIER_POINTER (DECL_NAME (decl)));
1301   go_output_type (container);
1302   fprintf (go_dump_file, "\n");
1303 
1304   /* Sometimes an extern variable is declared with an unknown struct
1305      type.  */
1306   if (type_name != NULL_TREE && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1307     {
1308       if (TREE_CODE (type_name) == IDENTIFIER_NODE)
1309 	container->pot_dummy_types.add (IDENTIFIER_POINTER (type_name));
1310       else if (TREE_CODE (type_name) == TYPE_DECL)
1311 	container->pot_dummy_types.add
1312 			    (IDENTIFIER_POINTER (DECL_NAME (type_name)));
1313     }
1314 }
1315 
1316 /* Output the final value of a preprocessor macro or enum constant.
1317    This is called via htab_traverse_noresize.  */
1318 
1319 static int
go_print_macro(void ** slot,void * arg ATTRIBUTE_UNUSED)1320 go_print_macro (void **slot, void *arg ATTRIBUTE_UNUSED)
1321 {
1322   struct macro_hash_value *mhval = (struct macro_hash_value *) *slot;
1323   fprintf (go_dump_file, "const _%s = %s\n", mhval->name, mhval->value);
1324   return 1;
1325 }
1326 
1327 /* Build a hash table with the Go keywords.  */
1328 
1329 static const char * const keywords[] = {
1330   "__asm__", "break", "case", "chan", "const", "continue", "default",
1331   "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
1332   "import", "interface", "map", "package", "range", "return", "select",
1333   "struct", "switch", "type", "var"
1334 };
1335 
1336 static void
keyword_hash_init(struct godump_container * container)1337 keyword_hash_init (struct godump_container *container)
1338 {
1339   size_t i;
1340   size_t count = sizeof (keywords) / sizeof (keywords[0]);
1341   void **slot;
1342 
1343   for (i = 0; i < count; i++)
1344     {
1345       slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1346       *slot = CONST_CAST (void *, (const void *) keywords[i]);
1347     }
1348 }
1349 
1350 /* Traversing the pot_dummy_types and seeing which types are present
1351    in the global types hash table and creating dummy definitions if
1352    not found.  This function is invoked by hash_set::traverse.  */
1353 
1354 bool
find_dummy_types(const char * const & ptr,godump_container * adata)1355 find_dummy_types (const char *const &ptr, godump_container *adata)
1356 {
1357   struct godump_container *data = (struct godump_container *) adata;
1358   const char *type = (const char *) ptr;
1359   void **slot;
1360   void **islot;
1361 
1362   slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1363   islot = htab_find_slot (data->invalid_hash, type, NO_INSERT);
1364   if (slot == NULL || islot != NULL)
1365     fprintf (go_dump_file, "type _%s struct {}\n", type);
1366   return true;
1367 }
1368 
1369 /* Output symbols.  */
1370 
1371 static void
go_finish(const char * filename)1372 go_finish (const char *filename)
1373 {
1374   struct godump_container container;
1375   unsigned int ix;
1376   tree decl;
1377 
1378   real_debug_hooks->finish (filename);
1379 
1380   container.type_hash = htab_create (100, htab_hash_string,
1381                                      string_hash_eq, NULL);
1382   container.invalid_hash = htab_create (10, htab_hash_string,
1383 					string_hash_eq, NULL);
1384   container.keyword_hash = htab_create (50, htab_hash_string,
1385                                         string_hash_eq, NULL);
1386   obstack_init (&container.type_obstack);
1387 
1388   keyword_hash_init (&container);
1389 
1390   FOR_EACH_VEC_SAFE_ELT (queue, ix, decl)
1391     {
1392       switch (TREE_CODE (decl))
1393 	{
1394 	case FUNCTION_DECL:
1395 	  go_output_fndecl (&container, decl);
1396 	  break;
1397 
1398 	case TYPE_DECL:
1399 	  go_output_typedef (&container, decl);
1400 	  break;
1401 
1402 	case VAR_DECL:
1403 	  go_output_var (&container, decl);
1404 	  break;
1405 
1406 	default:
1407 	  gcc_unreachable ();
1408 	}
1409     }
1410 
1411   htab_traverse_noresize (macro_hash, go_print_macro, NULL);
1412 
1413   /* To emit dummy definitions.  */
1414   container.pot_dummy_types.traverse<godump_container *, find_dummy_types>
1415                         (&container);
1416 
1417   htab_delete (container.type_hash);
1418   htab_delete (container.invalid_hash);
1419   htab_delete (container.keyword_hash);
1420   obstack_free (&container.type_obstack, NULL);
1421 
1422   vec_free (queue);
1423 
1424   if (fclose (go_dump_file) != 0)
1425     error ("could not close Go dump file: %m");
1426   go_dump_file = NULL;
1427 }
1428 
1429 /* Set up our hooks.  */
1430 
1431 const struct gcc_debug_hooks *
dump_go_spec_init(const char * filename,const struct gcc_debug_hooks * hooks)1432 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1433 {
1434   go_dump_file = fopen (filename, "w");
1435   if (go_dump_file == NULL)
1436     {
1437       error ("could not open Go dump file %qs: %m", filename);
1438       return hooks;
1439     }
1440 
1441   go_debug_hooks = *hooks;
1442   real_debug_hooks = hooks;
1443 
1444   go_debug_hooks.finish = go_finish;
1445   go_debug_hooks.define = go_define;
1446   go_debug_hooks.undef = go_undef;
1447   go_debug_hooks.function_decl = go_function_decl;
1448   go_debug_hooks.early_global_decl = go_early_global_decl;
1449   go_debug_hooks.late_global_decl = go_late_global_decl;
1450   go_debug_hooks.type_decl = go_type_decl;
1451 
1452   macro_hash = htab_create (100, macro_hash_hashval, macro_hash_eq,
1453 			    macro_hash_del);
1454 
1455   return &go_debug_hooks;
1456 }
1457 
1458 #include "gt-godump.h"
1459