xref: /dragonfly/contrib/gcc-8.0/gcc/godump.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
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