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