godump.c: New file.

gcc/:
	* godump.c: New file.
	* common.opt (fdump-go-spec=): New option.
	* tree.h: Add comments for TYPE_SYMTAB_ADDRESS and friends.
	(TYPE_SYMTAB_IS_ADDRESS, TYPE_SYMTAB_IS_POINTER): Define.
	(TYPE_SYMTAB_IS_DIE): Define.
	(struct tree_type): Change GTY for symtab field to use
	TYPE_SYMTAB_IS_ADDRESS and friends and to use a debug_hooks field
	to pick the union field.
	* debug.h (struct gcc_debug_hooks): Add tree_type_symtab_field.
	(dump_go_spec_init): Declare.
	* toplev.c (process_options): Handle flag_dump_go_spec.
	* debug.c: Include "tree.h".
	(do_nothing_debug_hooks): Set tree_type_symtab_field.
	* dwarf2out.c (dwarf2_debug_hooks): Likewise.
	* dbxout.c (dbx_debug_hooks): Likewise.
	(xcoff_debug_hooks): Likewise.
	* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
	* sdbout.c (sdb_debug_hooks): Likewise.  Do not define if
	SDB_DEBUGGING_INFO is not defined.
	* doc/invoke.texi (Option Summary): Mention -fdump-go-spec.
	(Overall Options): Document -fdump-go-spec.
	* Makefile.in (OBJS-common): Add godump.o.
	(debug.o): Add dependency on $(TREE_H).
	(godump.o): New target.
	(GTFILES): Add $(srcdir)/godump.c.
gcc/c-family/:
	* c-lex.c (init_c_lex): Set macro debug callbacks if
	flag_dump_go_spec is set.

From-SVN: r166770
This commit is contained in:
Ian Lance Taylor 2010-11-15 21:38:40 +00:00 committed by Ian Lance Taylor
parent 11746b92d8
commit c6a13190a1
15 changed files with 988 additions and 60 deletions

View File

@ -1,3 +1,31 @@
2010-11-15 Ian Lance Taylor <iant@google.com>
* godump.c: New file.
* common.opt (fdump-go-spec=): New option.
* tree.h: Add comments for TYPE_SYMTAB_ADDRESS and friends.
(TYPE_SYMTAB_IS_ADDRESS, TYPE_SYMTAB_IS_POINTER): Define.
(TYPE_SYMTAB_IS_DIE): Define.
(struct tree_type): Change GTY for symtab field to use
TYPE_SYMTAB_IS_ADDRESS and friends and to use a debug_hooks field
to pick the union field.
* debug.h (struct gcc_debug_hooks): Add tree_type_symtab_field.
(dump_go_spec_init): Declare.
* toplev.c (process_options): Handle flag_dump_go_spec.
* debug.c: Include "tree.h".
(do_nothing_debug_hooks): Set tree_type_symtab_field.
* dwarf2out.c (dwarf2_debug_hooks): Likewise.
* dbxout.c (dbx_debug_hooks): Likewise.
(xcoff_debug_hooks): Likewise.
* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
* sdbout.c (sdb_debug_hooks): Likewise. Do not define if
SDB_DEBUGGING_INFO is not defined.
* doc/invoke.texi (Option Summary): Mention -fdump-go-spec.
(Overall Options): Document -fdump-go-spec.
* Makefile.in (OBJS-common): Add godump.o.
(debug.o): Add dependency on $(TREE_H).
(godump.o): New target.
(GTFILES): Add $(srcdir)/godump.c.
2010-11-15 Jakub Jelinek <jakub@redhat.com>
PR debug/46095

View File

@ -1234,6 +1234,7 @@ OBJS-common = \
gimple-low.o \
gimple-pretty-print.o \
gimplify.o \
godump.o \
graph.o \
graphds.o \
graphite.o \
@ -2945,7 +2946,7 @@ dbxout.o : dbxout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(RTL_H) $(FLAGS_H) $(REGS_H) debug.h $(TM_P_H) $(TARGET_H) $(FUNCTION_H) \
langhooks.h insn-config.h reload.h $(GSTAB_H) xcoffout.h output.h dbxout.h \
$(TOPLEV_H) $(DIAGNOSTIC_CORE_H) $(GGC_H) $(OBSTACK_H) $(EXPR_H) gt-dbxout.h
debug.o : debug.c debug.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H)
debug.o : debug.c debug.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
sdbout.o : sdbout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) debug.h \
$(TREE_H) $(GGC_H) $(RTL_H) $(REGS_H) $(FLAGS_H) insn-config.h \
output.h $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) $(TM_P_H) gsyms.h langhooks.h $(TARGET_H) sdbout.h \
@ -2965,6 +2966,8 @@ vmsdbgout.o : vmsdbgout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
xcoffout.o : xcoffout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) $(RTL_H) xcoffout.h $(FLAGS_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) output.h dbxout.h \
$(GGC_H) $(TARGET_H) debug.h $(GSTAB_H) xcoff.h
godump.o : godump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(DIAGNOSTIC_CORE_H) \
$(TREE_H) $(GGC_H) pointer-set.h $(OBSTACK_H) debug.h
emit-rtl.o : emit-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(TREE_H) $(FLAGS_H) $(FUNCTION_H) $(REGS_H) insn-config.h $(RECOG_H) \
$(GGC_H) $(EXPR_H) hard-reg-set.h $(BITMAP_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) $(BASIC_BLOCK_H) \
@ -3739,7 +3742,8 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/emit-rtl.c $(srcdir)/except.h $(srcdir)/explow.c $(srcdir)/expr.c \
$(srcdir)/expr.h \
$(srcdir)/function.c $(srcdir)/except.c \
$(srcdir)/gcse.c $(srcdir)/integrate.c $(srcdir)/lists.c $(srcdir)/optabs.c \
$(srcdir)/gcse.c $(srcdir)/godump.c \
$(srcdir)/integrate.c $(srcdir)/lists.c $(srcdir)/optabs.c \
$(srcdir)/profile.c $(srcdir)/mcf.c \
$(srcdir)/reg-stack.c $(srcdir)/cfglayout.c $(srcdir)/cfglayout.h \
$(srcdir)/sdbout.c $(srcdir)/stor-layout.c \

View File

@ -1,3 +1,8 @@
2010-11-15 Ian Lance Taylor <iant@google.com>
* c-lex.c (init_c_lex): Set macro debug callbacks if
flag_dump_go_spec is set.
2010-11-15 Nicola Pero <nicola.pero@meta-innovation.com>
* c-common.h (objc_build_incr_expr_for_property_ref): New.

View File

@ -87,9 +87,10 @@ init_c_lex (void)
cb->read_pch = c_common_read_pch;
/* Set the debug callbacks if we can use them. */
if (debug_info_level == DINFO_LEVEL_VERBOSE
&& (write_symbols == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG))
if ((debug_info_level == DINFO_LEVEL_VERBOSE
&& (write_symbols == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG))
|| flag_dump_go_spec != NULL)
{
cb->define = cb_define;
cb->undef = cb_undef;

View File

@ -825,6 +825,10 @@ fdump-final-insns=
Common RejectNegative Joined Var(flag_dump_final_insns)
-fdump-final-insns=filename Dump to filename the insns at the end of translation
fdump-go-spec=
Common RejectNegative Joined Var(flag_dump_go_spec)
-fdump-go-spec=filename Write all declarations to file as Go code
fdump-noaddr
Common Report Var(flag_dump_noaddr)
Suppress output of addresses in debugging dumps

View File

@ -384,7 +384,8 @@ const struct gcc_debug_hooks dbx_debug_hooks =
debug_nothing_rtx_rtx, /* copy_call_info */
debug_nothing_uid, /* virtual_call */
debug_nothing_tree_tree, /* set_name */
0 /* start_end_main_source_file */
0, /* start_end_main_source_file */
TYPE_SYMTAB_IS_ADDRESS /* tree_type_symtab_field */
};
#endif /* DBX_DEBUGGING_INFO */
@ -423,7 +424,8 @@ const struct gcc_debug_hooks xcoff_debug_hooks =
debug_nothing_rtx_rtx, /* copy_call_info */
debug_nothing_uid, /* virtual_call */
debug_nothing_tree_tree, /* set_name */
0 /* start_end_main_source_file */
0, /* start_end_main_source_file */
TYPE_SYMTAB_IS_ADDRESS /* tree_type_symtab_field */
};
#endif /* XCOFF_DEBUGGING_INFO */

View File

@ -20,6 +20,7 @@
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "debug.h"
/* The do-nothing debug hooks. */
@ -57,7 +58,8 @@ const struct gcc_debug_hooks do_nothing_debug_hooks =
debug_nothing_rtx_rtx, /* copy_call_info */
debug_nothing_uid, /* virtual_call */
debug_nothing_tree_tree, /* set_name */
0 /* start_end_main_source_file */
0, /* start_end_main_source_file */
TYPE_SYMTAB_IS_ADDRESS /* tree_type_symtab_field */
};
/* This file contains implementations of each debug hook that do

View File

@ -165,6 +165,10 @@ struct gcc_debug_hooks
/* This is 1 if the debug writer wants to see start and end commands for the
main source files, and 0 otherwise. */
int start_end_main_source_file;
/* The type of symtab field used by these debug hooks. This is one
of the TYPE_SYMTAB_IS_xxx values defined in tree.h. */
int tree_type_symtab_field;
};
extern const struct gcc_debug_hooks *debug_hooks;
@ -217,4 +221,9 @@ extern int symbol_queue_index;
const char *remap_debug_filename (const char *);
void add_debug_prefix_map (const char *);
/* For -fdump-go-spec. */
extern const struct gcc_debug_hooks *
dump_go_spec_init (const char *, const struct gcc_debug_hooks *);
#endif /* !GCC_DEBUG_H */

View File

@ -165,7 +165,7 @@ in the following sections.
-pipe -pass-exit-codes @gol
-x @var{language} -v -### --help@r{[}=@var{class}@r{[},@dots{}@r{]]} --target-help @gol
--version -wrapper @@@var{file} -fplugin=@var{file} -fplugin-arg-@var{name}=@var{arg} @gol
-fdump-ada-spec@r{[}-slim@r{]}}
-fdump-ada-spec@r{[}-slim@r{]}} -fdump-go-spec=@var{file}
@item C Language Options
@xref{C Dialect Options,,Options Controlling C Dialect}.
@ -1385,6 +1385,13 @@ For C and C++ source and include files, generate corresponding Ada
specs. @xref{Generating Ada Bindings for C and C++ headers,,, gnat_ugn,
GNAT User's Guide}, which provides detailed documentation on this feature.
@item -fdump-go-spec=@var{file}
For input files in any language, generate corresponding Go
declarations in @var{file}. This generates Go @code{const},
@code{type}, @code{var}, and @code{func} declarations which may be a
useful way to start writing a Go interface to code written in some
other language.
@include @value{srcdir}/../libiberty/at-file.texi
@end table

View File

@ -5648,7 +5648,8 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
dwarf2out_copy_call_info,
dwarf2out_virtual_call,
dwarf2out_set_name,
1 /* start_end_main_source_file */
1, /* start_end_main_source_file */
TYPE_SYMTAB_IS_DIE /* tree_type_symtab_field */
};
/* NOTE: In the comments in this file, many references are made to

874
gcc/godump.c Normal file
View File

@ -0,0 +1,874 @@
/* Output Go language descriptions of types.
Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
Written by Ian Lance Taylor <iant@google.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* This file is used during the build process to emit Go language
descriptions of declarations from C header files. It uses the
debug info hooks to emit the descriptions. The Go language
descriptions then become part of the Go runtime support
library.
All global names are output with a leading underscore, so that they
are all hidden in Go. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "diagnostic-core.h"
#include "tree.h"
#include "ggc.h"
#include "pointer-set.h"
#include "obstack.h"
#include "debug.h"
/* We dump this information from the debug hooks. This gives us a
stable and maintainable API to hook into. In order to work
correctly when -g is used, we build our own hooks structure which
wraps the hooks we need to change. */
/* Our debug hooks. This is initialized by dump_go_spec_init. */
static struct gcc_debug_hooks go_debug_hooks;
/* The real debug hooks. */
static const struct gcc_debug_hooks *real_debug_hooks;
/* The file where we should write information. */
static FILE *go_dump_file;
/* A queue of decls to output. */
static GTY(()) VEC(tree,gc) *queue;
/* A hash table of macros we have seen. */
static htab_t macro_hash;
/* For the hash tables. */
static int
string_hash_eq (const void *y1, const void *y2)
{
return strcmp ((const char *) y1, (const char *) y2) == 0;
}
/* A macro definition. */
static void
go_define (unsigned int lineno, const char *buffer)
{
const char *p;
const char *name_end;
char *out_buffer;
char *q;
char *copy;
hashval_t hashval;
void **slot;
real_debug_hooks->define (lineno, buffer);
/* Skip macro functions. */
for (p = buffer; *p != '\0' && *p != ' '; ++p)
if (*p == '(')
return;
if (*p == '\0')
return;
name_end = p;
++p;
if (*p == '\0')
return;
copy = XNEWVEC (char, name_end - buffer + 1);
memcpy (copy, buffer, name_end - buffer);
copy[name_end - buffer] = '\0';
hashval = htab_hash_string (copy);
slot = htab_find_slot_with_hash (macro_hash, copy, hashval, NO_INSERT);
if (slot != NULL)
{
XDELETEVEC (copy);
return;
}
/* For simplicity, we force all names to be hidden by adding an
initial underscore, and let the user undo this as needed. */
out_buffer = XNEWVEC (char, strlen (p) * 2 + 1);
q = out_buffer;
while (*p != '\0')
{
if (ISALPHA (*p) || *p == '_')
{
const char *start;
char *n;
start = p;
while (ISALNUM (*p) || *p == '_')
++p;
n = XALLOCAVEC (char, p - start + 1);
memcpy (n, start, p - start);
n[p - start] = '\0';
slot = htab_find_slot (macro_hash, n, NO_INSERT);
if (slot == NULL || *slot == NULL)
{
/* This is a reference to a name which was not defined
as a macro. */
fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
return;
}
*q++ = '_';
memcpy (q, start, p - start);
q += p - start;
}
else if (ISDIGIT (*p)
|| (*p == '.' && ISDIGIT (p[1])))
{
const char *start;
bool is_hex;
start = p;
is_hex = false;
if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
{
p += 2;
is_hex = true;
}
while (ISDIGIT (*p) || *p == '.' || *p == 'e' || *p == 'E'
|| (is_hex
&& ((*p >= 'a' && *p <= 'f')
|| (*p >= 'A' && *p <= 'F'))))
++p;
memcpy (q, start, p - start);
q += p - start;
while (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L'
|| *p == 'f' || *p == 'F'
|| *p == 'd' || *p == 'D')
{
/* Go doesn't use any of these trailing type
modifiers. */
++p;
}
}
else if (ISSPACE (*p)
|| *p == '+' || *p == '-'
|| *p == '*' || *p == '/' || *p == '%'
|| *p == '|' || *p == '&'
|| *p == '>' || *p == '<'
|| *p == '!'
|| *p == '(' || *p == ')'
|| *p == '"' || *p == '\'')
*q++ = *p++;
else
{
/* Something we don't recognize. */
fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
return;
}
}
*q = '\0';
slot = htab_find_slot_with_hash (macro_hash, copy, hashval, INSERT);
*slot = copy;
fprintf (go_dump_file, "const _%s = %s\n", copy, out_buffer);
XDELETEVEC (out_buffer);
}
/* A macro undef. */
static void
go_undef (unsigned int lineno, const char *buffer)
{
void **slot;
real_debug_hooks->undef (lineno, buffer);
slot = htab_find_slot (macro_hash, buffer, NO_INSERT);
if (slot == NULL)
return;
fprintf (go_dump_file, "// undef _%s\n", buffer);
/* We don't delete the slot from the hash table because that will
cause a duplicate const definition. */
}
/* A function or variable decl. */
static void
go_decl (tree decl)
{
if (!TREE_PUBLIC (decl)
|| DECL_IS_BUILTIN (decl)
|| DECL_NAME (decl) == NULL_TREE)
return;
VEC_safe_push (tree, gc, queue, decl);
}
/* A function decl. */
static void
go_function_decl (tree decl)
{
real_debug_hooks->function_decl (decl);
go_decl (decl);
}
/* A global variable decl. */
static void
go_global_decl (tree decl)
{
real_debug_hooks->global_decl (decl);
go_decl (decl);
}
/* A type declaration. */
static void
go_type_decl (tree decl, int local)
{
real_debug_hooks->type_decl (decl, local);
if (local || DECL_IS_BUILTIN (decl))
return;
if (DECL_NAME (decl) == NULL_TREE
&& (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE
|| TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE)
&& TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
return;
VEC_safe_push (tree, gc, queue, decl);
}
/* A container for the data we pass around when generating information
at the end of the compilation. */
struct godump_container
{
/* DECLs that we have already seen. */
struct pointer_set_t *decls_seen;
/* Types which may potentially have to be defined as dummy
types. */
struct pointer_set_t *pot_dummy_types;
/* Go keywords. */
htab_t keyword_hash;
/* Global type definitions. */
htab_t type_hash;
/* Obstack used to write out a type definition. */
struct obstack type_obstack;
};
/* Append an IDENTIFIER_NODE to OB. */
static void
go_append_string (struct obstack *ob, tree id)
{
obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
}
/* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
USE_TYPE_NAME is true if we can simply use a type name here without
needing to define it. IS_FUNC_OK is true if we can output a func
type here; the "func" keyword will already have been added. Return
true if the type can be represented in Go, false otherwise. */
static bool
go_format_type (struct godump_container *container, tree type,
bool use_type_name, bool is_func_ok)
{
bool ret;
struct obstack *ob;
ret = true;
ob = &container->type_obstack;
if (TYPE_NAME (type) != NULL_TREE
&& (pointer_set_contains (container->decls_seen, type)
|| pointer_set_contains (container->decls_seen, TYPE_NAME (type)))
&& (AGGREGATE_TYPE_P (type)
|| POINTER_TYPE_P (type)
|| TREE_CODE (type) == FUNCTION_TYPE))
{
tree name;
name = TYPE_NAME (type);
if (TREE_CODE (name) == IDENTIFIER_NODE)
{
obstack_1grow (ob, '_');
go_append_string (ob, name);
return ret;
}
else if (TREE_CODE (name) == TYPE_DECL)
{
obstack_1grow (ob, '_');
go_append_string (ob, DECL_NAME (name));
return ret;
}
}
pointer_set_insert (container->decls_seen, type);
switch (TREE_CODE (type))
{
case ENUMERAL_TYPE:
obstack_grow (ob, "int", 3);
break;
case TYPE_DECL:
obstack_1grow (ob, '_');
go_append_string (ob, DECL_NAME (type));
break;
case INTEGER_TYPE:
{
const char *s;
char buf[100];
switch (TYPE_PRECISION (type))
{
case 8:
s = TYPE_UNSIGNED (type) ? "uint8" : "int8";
break;
case 16:
s = TYPE_UNSIGNED (type) ? "uint16" : "int16";
break;
case 32:
s = TYPE_UNSIGNED (type) ? "uint32" : "int32";
break;
case 64:
s = TYPE_UNSIGNED (type) ? "uint64" : "int64";
break;
default:
snprintf (buf, sizeof buf, "INVALID-int-%u%s",
TYPE_PRECISION (type),
TYPE_UNSIGNED (type) ? "u" : "");
s = buf;
ret = false;
break;
}
obstack_grow (ob, s, strlen (s));
}
break;
case REAL_TYPE:
{
const char *s;
char buf[100];
switch (TYPE_PRECISION (type))
{
case 32:
s = "float32";
break;
case 64:
s = "float64";
break;
case 80:
s = "float80";
break;
default:
snprintf (buf, sizeof buf, "INVALID-float-%u",
TYPE_PRECISION (type));
s = buf;
ret = false;
break;
}
obstack_grow (ob, s, strlen (s));
}
break;
case BOOLEAN_TYPE:
obstack_grow (ob, "bool", 4);
break;
case POINTER_TYPE:
if (use_type_name
&& TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
&& (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
|| (POINTER_TYPE_P (TREE_TYPE (type))
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
== FUNCTION_TYPE))))
{
tree name;
name = TYPE_NAME (TREE_TYPE (type));
if (TREE_CODE (name) == IDENTIFIER_NODE)
{
obstack_grow (ob, "*_", 2);
go_append_string (ob, name);
/* The pointer here can be used without the struct or
union definition. So this struct or union is a a
potential dummy type. */
if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
pointer_set_insert (container->pot_dummy_types,
IDENTIFIER_POINTER (name));
return ret;
}
else if (TREE_CODE (name) == TYPE_DECL)
{
obstack_grow (ob, "*_", 2);
go_append_string (ob, DECL_NAME (name));
if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
pointer_set_insert (container->pot_dummy_types,
IDENTIFIER_POINTER (DECL_NAME (name)));
return ret;
}
}
if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
obstack_grow (ob, "func", 4);
else
obstack_1grow (ob, '*');
if (VOID_TYPE_P (TREE_TYPE (type)))
obstack_grow (ob, "byte", 4);
else
{
if (!go_format_type (container, TREE_TYPE (type), use_type_name,
true))
ret = false;
}
break;
case ARRAY_TYPE:
obstack_1grow (ob, '[');
if (TYPE_DOMAIN (type) != NULL_TREE
&& TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
&& TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
&& TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
&& tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
&& TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
&& TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
&& host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0))
{
char buf[100];
snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0));
obstack_grow (ob, buf, strlen (buf));
}
obstack_1grow (ob, ']');
if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
ret = false;
break;
case UNION_TYPE:
case RECORD_TYPE:
{
tree field;
int i;
obstack_grow (ob, "struct { ", 9);
i = 0;
for (field = TYPE_FIELDS (type);
field != NULL_TREE;
field = TREE_CHAIN (field))
{
if (DECL_NAME (field) == NULL)
{
char buf[100];
obstack_grow (ob, "_f", 2);
snprintf (buf, sizeof buf, "%d", i);
obstack_grow (ob, buf, strlen (buf));
i++;
}
else
{
const char *var_name;
void **slot;
/* Start variable name with an underscore if a keyword. */
var_name = IDENTIFIER_POINTER (DECL_NAME (field));
slot = htab_find_slot (container->keyword_hash, var_name,
NO_INSERT);
if (slot != NULL)
obstack_1grow (ob, '_');
go_append_string (ob, DECL_NAME (field));
}
obstack_1grow (ob, ' ');
if (DECL_BIT_FIELD (field))
{
obstack_grow (ob, "INVALID-bit-field", 17);
ret = false;
}
else
{
/* Do not expand type if a record or union type or a
function pointer. */
if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
&& (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
|| (POINTER_TYPE_P (TREE_TYPE (field))
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
== FUNCTION_TYPE))))
{
tree name = TYPE_NAME (TREE_TYPE (field));
if (TREE_CODE (name) == IDENTIFIER_NODE)
{
obstack_1grow (ob, '_');
go_append_string (ob, name);
}
else if (TREE_CODE (name) == TYPE_DECL)
{
obstack_1grow (ob, '_');
go_append_string (ob, DECL_NAME (name));
}
}
else
{
if (!go_format_type (container, TREE_TYPE (field), true,
false))
ret = false;
}
}
obstack_grow (ob, "; ", 2);
/* Only output the first field of a union, and hope for
the best. */
if (TREE_CODE (type) == UNION_TYPE)
break;
}
obstack_1grow (ob, '}');
}
break;
case FUNCTION_TYPE:
{
tree args;
bool is_varargs;
tree result;
/* Go has no way to write a type which is a function but not a
pointer to a function. */
if (!is_func_ok)
{
obstack_grow (ob, "func*", 5);
ret = false;
}
obstack_1grow (ob, '(');
is_varargs = true;
for (args = TYPE_ARG_TYPES (type);
args != NULL_TREE;
args = TREE_CHAIN (args))
{
if (VOID_TYPE_P (TREE_VALUE (args)))
{
gcc_assert (TREE_CHAIN (args) == NULL);
is_varargs = false;
break;
}
if (args != TYPE_ARG_TYPES (type))
obstack_grow (ob, ", ", 2);
if (!go_format_type (container, TREE_VALUE (args), true, false))
ret = false;
}
if (is_varargs)
{
if (TYPE_ARG_TYPES (type) != NULL_TREE)
obstack_grow (ob, ", ", 2);
obstack_grow (ob, "...interface{}", 14);
}
obstack_1grow (ob, ')');
result = TREE_TYPE (type);
if (!VOID_TYPE_P (result))
{
obstack_1grow (ob, ' ');
if (!go_format_type (container, result, use_type_name, false))
ret = false;
}
}
break;
default:
obstack_grow (ob, "INVALID-type", 12);
ret = false;
break;
}
return ret;
}
/* Output the type which was built on the type obstack, and then free
it. */
static void
go_output_type (struct godump_container *container)
{
struct obstack *ob;
ob = &container->type_obstack;
obstack_1grow (ob, '\0');
fputs (obstack_base (ob), go_dump_file);
obstack_free (ob, obstack_base (ob));
}
/* Output a function declaration. */
static void
go_output_fndecl (struct godump_container *container, tree decl)
{
if (!go_format_type (container, TREE_TYPE (decl), false, true))
fprintf (go_dump_file, "// ");
fprintf (go_dump_file, "func _%s ",
IDENTIFIER_POINTER (DECL_NAME (decl)));
go_output_type (container);
fprintf (go_dump_file, " __asm__(\"%s\")\n",
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
}
/* Output a typedef or something like a struct definition. */
static void
go_output_typedef (struct godump_container *container, tree decl)
{
/* If we have an enum type, output the enum constants
separately. */
if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
&& TYPE_SIZE (TREE_TYPE (decl)) != 0
&& !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
&& (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
|| !pointer_set_contains (container->decls_seen,
TYPE_CANONICAL (TREE_TYPE (decl)))))
{
tree element;
for (element = TYPE_VALUES (TREE_TYPE (decl));
element != NULL_TREE;
element = TREE_CHAIN (element))
fprintf (go_dump_file, "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
IDENTIFIER_POINTER (TREE_PURPOSE (element)),
tree_low_cst (TREE_VALUE (element), 0));
pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
pointer_set_insert (container->decls_seen,
TYPE_CANONICAL (TREE_TYPE (decl)));
}
if (DECL_NAME (decl) != NULL_TREE)
{
void **slot;
const char *type;
type = IDENTIFIER_POINTER (DECL_NAME (decl));
/* If type defined already, skip. */
slot = htab_find_slot (container->type_hash, type, INSERT);
if (*slot != NULL)
return;
*slot = CONST_CAST (void *, (const void *) type);
if (!go_format_type (container, TREE_TYPE (decl), false, false))
fprintf (go_dump_file, "// ");
fprintf (go_dump_file, "type _%s ",
IDENTIFIER_POINTER (DECL_NAME (decl)));
go_output_type (container);
pointer_set_insert (container->decls_seen, decl);
}
else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
{
void **slot;
const char *type;
type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
/* If type defined already, skip. */
slot = htab_find_slot (container->type_hash, type, INSERT);
if (*slot != NULL)
return;
*slot = CONST_CAST (void *, (const void *) type);
if (!go_format_type (container, TREE_TYPE (decl), false, false))
fprintf (go_dump_file, "// ");
fprintf (go_dump_file, "type _%s ",
IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
go_output_type (container);
}
else
return;
fprintf (go_dump_file, "\n");
}
/* Output a variable. */
static void
go_output_var (struct godump_container *container, tree decl)
{
if (pointer_set_contains (container->decls_seen, decl)
|| pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
return;
pointer_set_insert (container->decls_seen, decl);
pointer_set_insert (container->decls_seen, DECL_NAME (decl));
if (!go_format_type (container, TREE_TYPE (decl), true, false))
fprintf (go_dump_file, "// ");
fprintf (go_dump_file, "var _%s ",
IDENTIFIER_POINTER (DECL_NAME (decl)));
go_output_type (container);
fprintf (go_dump_file, "\n");
/* Sometimes an extern variable is declared with an unknown struct
type. */
if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
&& RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
{
tree type_name = TYPE_NAME (TREE_TYPE (decl));
if (TREE_CODE (type_name) == IDENTIFIER_NODE)
pointer_set_insert (container->pot_dummy_types,
IDENTIFIER_POINTER (type_name));
else if (TREE_CODE (type_name) == TYPE_DECL)
pointer_set_insert (container->pot_dummy_types,
IDENTIFIER_POINTER (DECL_NAME (type_name)));
}
}
/* Build a hash table with the Go keywords. */
static const char * const keywords[] = {
"__asm__", "break", "case", "chan", "const", "continue", "default",
"defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
"import", "interface", "map", "package", "range", "return", "select",
"struct", "switch", "type", "var"
};
static void
keyword_hash_init (struct godump_container *container)
{
size_t i;
size_t count = sizeof (keywords) / sizeof (keywords[0]);
void **slot;
for (i = 0; i < count; i++)
{
slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
*slot = CONST_CAST (void *, (const void *) keywords[i]);
}
}
/* Traversing the pot_dummy_types and seeing which types are present
in the global types hash table and creating dummy definitions if
not found. This function is invoked by pointer_set_traverse. */
static bool
find_dummy_types (const void *ptr, void *adata)
{
struct godump_container *data = (struct godump_container *) adata;
const char *type = (const char *) ptr;
void **slot;
slot = htab_find_slot (data->type_hash, type, NO_INSERT);
if (slot == NULL)
fprintf (go_dump_file, "type _%s struct {}\n", type);
return true;
}
/* Output symbols. */
static void
go_finish (const char *filename)
{
struct godump_container container;
unsigned int ix;
tree decl;
real_debug_hooks->finish (filename);
container.decls_seen = pointer_set_create ();
container.pot_dummy_types = pointer_set_create ();
container.type_hash = htab_create (100, htab_hash_string,
string_hash_eq, NULL);
container.keyword_hash = htab_create (50, htab_hash_string,
string_hash_eq, NULL);
obstack_init (&container.type_obstack);
keyword_hash_init (&container);
FOR_EACH_VEC_ELT (tree, queue, ix, decl)
{
switch (TREE_CODE (decl))
{
case FUNCTION_DECL:
go_output_fndecl (&container, decl);
break;
case TYPE_DECL:
go_output_typedef (&container, decl);
break;
case VAR_DECL:
go_output_var (&container, decl);
break;
default:
gcc_unreachable();
}
}
/* To emit dummy definitions. */
pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
(void *) &container);
pointer_set_destroy (container.decls_seen);
pointer_set_destroy (container.pot_dummy_types);
htab_delete (container.type_hash);
htab_delete (container.keyword_hash);
obstack_free (&container.type_obstack, NULL);
queue = NULL;
if (fclose (go_dump_file) != 0)
error ("could not close Go dump file: %m");
go_dump_file = NULL;
}
/* Set up our hooks. */
const struct gcc_debug_hooks *
dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
{
go_dump_file = fopen (filename, "w");
if (go_dump_file == NULL)
{
error ("could not open Go dump file %qs: %m", filename);
return hooks;
}
go_debug_hooks = *hooks;
real_debug_hooks = hooks;
go_debug_hooks.finish = go_finish;
go_debug_hooks.define = go_define;
go_debug_hooks.undef = go_undef;
go_debug_hooks.function_decl = go_function_decl;
go_debug_hooks.global_decl = go_global_decl;
go_debug_hooks.type_decl = go_type_decl;
macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
return &go_debug_hooks;
}
#include "gt-godump.h"

View File

@ -345,7 +345,8 @@ const struct gcc_debug_hooks sdb_debug_hooks =
debug_nothing_rtx_rtx, /* copy_call_info */
debug_nothing_uid, /* virtual_call */
debug_nothing_tree_tree, /* set_name */
0 /* start_end_main_source_file */
0, /* start_end_main_source_file */
TYPE_SYMTAB_IS_POINTER /* tree_type_symtab_field */
};
/* Return a unique string to name an anonymous type. */
@ -1704,47 +1705,6 @@ sdbout_init (const char *input_file_name ATTRIBUTE_UNUSED)
preinit_symbols = 0;
}
#else /* SDB_DEBUGGING_INFO */
/* This should never be used, but its address is needed for comparisons. */
const struct gcc_debug_hooks sdb_debug_hooks =
{
0, /* init */
0, /* finish */
0, /* assembly_start */
0, /* define */
0, /* undef */
0, /* start_source_file */
0, /* end_source_file */
0, /* begin_block */
0, /* end_block */
0, /* ignore_block */
0, /* source_line */
0, /* begin_prologue */
0, /* end_prologue */
0, /* begin_epilogue */
0, /* end_epilogue */
0, /* begin_function */
0, /* end_function */
0, /* function_decl */
0, /* global_decl */
0, /* type_decl */
0, /* imported_module_or_decl */
0, /* deferred_inline_function */
0, /* outlining_inline_function */
0, /* label */
0, /* handle_pch */
0, /* var_location */
0, /* switch_text_section */
0, /* direct_call */
0, /* virtual_call_token */
0, /* copy_call_info */
0, /* virtual_call */
0, /* set_name */
0 /* start_end_main_source_file */
};
#endif /* SDB_DEBUGGING_INFO */
#include "gt-sdbout.h"

View File

@ -1916,6 +1916,12 @@ process_options (void)
flag_var_tracking_uninit = 0;
}
/* The debug hooks are used to implement -fdump-go-spec because it
gives a simple and stable API for all the information we need to
dump. */
if (flag_dump_go_spec != NULL)
debug_hooks = dump_go_spec_init (flag_dump_go_spec, debug_hooks);
/* If the user specifically requested variable tracking with tagging
uninitialized variables, we need to turn on variable tracking.
(We already determined above that variable tracking is feasible.) */

View File

@ -2076,9 +2076,6 @@ struct GTY(()) tree_block {
#define TYPE_MIN_VALUE(NODE) (NUMERICAL_TYPE_CHECK (NODE)->type.minval)
#define TYPE_MAX_VALUE(NODE) (NUMERICAL_TYPE_CHECK (NODE)->type.maxval)
#define TYPE_PRECISION(NODE) (TYPE_CHECK (NODE)->type.precision)
#define TYPE_SYMTAB_ADDRESS(NODE) (TYPE_CHECK (NODE)->type.symtab.address)
#define TYPE_SYMTAB_POINTER(NODE) (TYPE_CHECK (NODE)->type.symtab.pointer)
#define TYPE_SYMTAB_DIE(NODE) (TYPE_CHECK (NODE)->type.symtab.die)
#define TYPE_NAME(NODE) (TYPE_CHECK (NODE)->type.name)
#define TYPE_NEXT_VARIANT(NODE) (TYPE_CHECK (NODE)->type.next_variant)
#define TYPE_MAIN_VARIANT(NODE) (TYPE_CHECK (NODE)->type.main_variant)
@ -2300,6 +2297,33 @@ extern enum machine_mode vector_type_mode (const_tree);
#define TYPE_CONTAINS_PLACEHOLDER_INTERNAL(NODE) \
(TYPE_CHECK (NODE)->type.contains_placeholder_bits)
/* The debug output functions use the symtab union field to store
information specific to the debugging format. The different debug
output hooks store different types in the union field. These three
macros are used to access different fields in the union. The debug
hooks are responsible for consistently using only a specific
macro. */
/* Symtab field as an integer. Used by stabs generator in dbxout.c to
hold the type's number in the generated stabs. */
#define TYPE_SYMTAB_ADDRESS(NODE) (TYPE_CHECK (NODE)->type.symtab.address)
/* Symtab field as a string. Used by COFF generator in sdbout.c to
hold struct/union type tag names. */
#define TYPE_SYMTAB_POINTER(NODE) (TYPE_CHECK (NODE)->type.symtab.pointer)
/* Symtab field as a pointer to a DWARF DIE. Used by DWARF generator
in dwarf2out.c to point to the DIE generated for the type. */
#define TYPE_SYMTAB_DIE(NODE) (TYPE_CHECK (NODE)->type.symtab.die)
/* The garbage collector needs to know the interpretation of the
symtab field. These constants represent the different types in the
union. */
#define TYPE_SYMTAB_IS_ADDRESS (0)
#define TYPE_SYMTAB_IS_POINTER (1)
#define TYPE_SYMTAB_IS_DIE (2)
struct die_struct;
struct GTY(()) tree_type {
@ -2333,10 +2357,10 @@ struct GTY(()) tree_type {
tree pointer_to;
tree reference_to;
union tree_type_symtab {
int GTY ((tag ("0"))) address;
const char * GTY ((tag ("1"))) pointer;
struct die_struct * GTY ((tag ("2"))) die;
} GTY ((desc ("debug_hooks == &sdb_debug_hooks ? 1 : debug_hooks == &dwarf2_debug_hooks ? 2 : 0"))) symtab;
int GTY ((tag ("TYPE_SYMTAB_IS_ADDRESS"))) address;
const char * GTY ((tag ("TYPE_SYMTAB_IS_POINTER"))) pointer;
struct die_struct * GTY ((tag ("TYPE_SYMTAB_IS_DIE"))) die;
} GTY ((desc ("debug_hooks->tree_type_symtab_field"))) symtab;
tree name;
tree minval;
tree maxval;

View File

@ -210,7 +210,8 @@ const struct gcc_debug_hooks vmsdbg_debug_hooks
debug_nothing_rtx_rtx, /* copy_call_info */
debug_nothing_uid, /* virtual_call */
debug_nothing_tree_tree, /* set_name */
0 /* start_end_main_source_file */
0, /* start_end_main_source_file */
TYPE_SYMTAB_IS_ADDRESS /* tree_type_symtab_field */
};
/* Definitions of defaults for assembler-dependent names of various