[PATCH] stabs format for symbols in .comm
George Helffrich
george@geology.bristol.ac.uk
Mon Oct 29 15:31:00 GMT 2007
This patch was approved in August 2004 but never committed, sadly.
This is an updated version against the 4.3-20070810 snapshot (reason:
builds gfortran). Original approval reference (and linked discussion)
at:
http://gcc.gnu.org/ml/gcc-patches/2004-08/msg02475.html
Briefly, on some systems (e.g. Darwin), symbolic expressions in .stabs
assembler pseudo-ops do not get relocated on load. Thus V-lettered
.stabs symbols cannot be located by the debugger. This patch changes
the way that .comm symbols are presented, using an alternate syntax
that gdb understands, which avoids the need for .stabs relocations.
The problem arises when dealing with Fortran COMMON symbols; there is
no effect on C .stabs referencing .comm.
Tested on i386-apple-darwin8.10.1, powerpc-apple-darwin8.8.0 (see also
linked discussion)
2007-10-27 George Helffrich <ghfbsd@gly.bris.ac.uk>
* dbxout.c (dbxout_symbol_location, dbxout_syms): Output stabs
for
symbols in .comm to use the gdb-supported N_BCOMM/N_ECOMM
mechanism.
Some systems (e.g. Darwin) will not relocate SYMBOL+offset
expressions
in stabs, making the traditional N_LCSYM mechanism unusable.
* dbxout.c (dbxout_common_name, dbxout_common_check): New
routines.
--- dbxout.c.orig 2007-08-08 23:29:12.000000000 +0100
+++ dbxout.c 2007-10-29 14:22:09.000000000 +0000
@@ -326,6 +326,8 @@
static void dbxout_class_name_qualifiers (tree);
static int dbxout_symbol_location (tree, tree, const char *, rtx);
static void dbxout_symbol_name (tree, const char *, int);
+static void dbxout_common_name (tree, const char *, STAB_CODE_TYPE);
+static const char *dbxout_common_check (tree, int *);
static void dbxout_block (tree, int, tree);
static void dbxout_global_decl (tree);
static void dbxout_type_decl (tree, int);
@@ -2806,6 +2808,7 @@
rtx addr = 0;
int number = 0;
int regno = -1;
+ int offs;
/* Don't mention a variable at all
if it was completely optimized into nothingness.
@@ -2852,6 +2855,12 @@
{
letter = 'G';
code = N_GSYM;
+ if (NULL != dbxout_common_check (decl, &offs))
+ {
+ letter = 'V';
+ addr = 0;
+ number = offs;
+ }
}
else
{
@@ -2897,7 +2906,16 @@
if (DECL_INITIAL (decl) == 0
|| (!strcmp (lang_hooks.name, "GNU C++")
&& DECL_INITIAL (decl) == error_mark_node))
- code = N_LCSYM;
+ {
+ code = N_LCSYM;
+ if (NULL != dbxout_common_check (decl, &offs))
+ {
+ addr = 0;
+ number = offs;
+ letter = 'V';
+ code = N_GSYM;
+ }
+ }
else if (DECL_IN_TEXT_SECTION (decl))
/* This is not quite right, but it's the closest
of all the codes that Unix defines. */
@@ -2988,7 +3006,14 @@
this variable was itself `static'. */
code = N_LCSYM;
letter = 'V';
- addr = XEXP (XEXP (home, 0), 0);
+ if (NULL == dbxout_common_check (decl, &offs))
+ addr = XEXP (XEXP (home, 0), 0);
+ else
+ {
+ addr = 0;
+ number = offs;
+ code = N_GSYM;
+ }
}
else if (GET_CODE (home) == CONCAT)
{
@@ -3073,18 +3098,148 @@
stabstr_C (letter);
}
-/* Output definitions of all the decls in a chain. Return nonzero if
- anything was output */
+/* Symbols in global common (.comm) get wrapped with an
N_BCOMM/N_ECOMM pair
+ around each group of symbols in the same .comm area. The N_GSYM
stabs
+ that are emitted only contain the offset in the common area. This
routine
+ emits the N_BCOMM and N_ECOMM stabs. */
+
+static void
+dbxout_common_name (tree decl, const char *name, STAB_CODE_TYPE op)
+{
+ dbxout_begin_complex_stabs ();
+ stabstr_S (name);
+ dbxout_finish_complex_stabs (decl, op, NULL_RTX, NULL, 0);
+}
+
+/* Check decl to determine whether it is a VAR_DECL destined for
storage in a
+ common area. If it is, the return value will be a non-null string
giving
+ the name of the common storage block it will go into. If non-null,
the
+ value is the offset into the common block for that symbol's
storage. */
+
+static const char *
+dbxout_common_check(tree decl, int *value)
+{
+ rtx home;
+ rtx sym_addr;
+ const char *name = NULL;
+
+ /* If the decl isn't a VAR_DECL, or if it isn't public or static, or
if
+ it does not have a value (the offset into the common area), or if
it
+ is thread local (as opposed to global) then it isn't common, and
shouldn't
+ be handled as such. */
+ if (TREE_CODE (decl) != VAR_DECL
+ || !TREE_PUBLIC(decl)
+ || !TREE_STATIC(decl)
+ || !DECL_HAS_VALUE_EXPR_P(decl)
+ || DECL_THREAD_LOCAL_P (decl))
+ return NULL;
+
+ home = DECL_RTL (decl);
+ if (home == NULL_RTX || GET_CODE (home) != MEM)
+ return NULL;
+
+ sym_addr = dbxout_expand_expr (DECL_VALUE_EXPR (decl));
+ if (sym_addr == NULL_RTX || GET_CODE (sym_addr) != MEM)
+ return NULL;
+
+ sym_addr = XEXP (sym_addr, 0);
+ if (GET_CODE (sym_addr) == CONST)
+ sym_addr = XEXP (sym_addr, 0);
+ if ((GET_CODE (sym_addr) == SYMBOL_REF || GET_CODE (sym_addr) ==
PLUS)
+ && (DECL_INITIAL (decl) == 0
+ || (!strcmp (lang_hooks.name, "GNU C++")
+ && DECL_INITIAL (decl) == error_mark_node)))
+ {
+
+ /* We have sym that will go into a common area, meaning that it
+ will get storage reserved with a .comm/.lcomm assembler
pseudo-op.
+
+ Determine name of common area this symbol will be an offset
into,
+ and offset into that area. Also retrieve the decl for the
area
+ that the symbol is offset into. */
+ tree cdecl = NULL;
+
+ switch (GET_CODE (sym_addr))
+ {
+ case PLUS:
+ if (GET_CODE (XEXP (sym_addr, 0)) == CONST_INT)
+ {
+ name =
+ targetm.strip_name_encoding(XSTR (XEXP (sym_addr,
1), 0));
+ *value = INTVAL (XEXP (sym_addr, 0));
+ cdecl = SYMBOL_REF_DECL (XEXP (sym_addr, 1));
+ }
+ else
+ {
+ name =
+ targetm.strip_name_encoding(XSTR (XEXP (sym_addr,
0), 0));
+ *value = INTVAL (XEXP (sym_addr, 1));
+ cdecl = SYMBOL_REF_DECL (XEXP (sym_addr, 0));
+ }
+ break;
+
+ case SYMBOL_REF:
+ name = targetm.strip_name_encoding(XSTR (sym_addr, 0));
+ *value = 0;
+ cdecl = SYMBOL_REF_DECL (sym_addr);
+ break;
+
+ default:
+ error ("common symbol debug info is not structured as "
+ "symbol+offset");
+ }
+
+ /* Check area common symbol is offset into. If this is not
public, then
+ it is not a symbol in a common block. It must be a .lcomm
symbol, not
+ a .comm symbol. */
+ if (cdecl == NULL || !TREE_PUBLIC(cdecl))
+ name = NULL;
+ }
+ else
+ name = NULL;
+
+ return name;
+}
+
+/* Output definitions of all the decls in a chain. Bracket each group
of
+ common symbols with N_BCOMM/N_ECOMM bracketing stabs. Return
nonzero if
+ anything was output. */
int
dbxout_syms (tree syms)
{
int result = 0;
+ const char *comm_prev = NULL;
+ tree syms_prev = NULL;
while (syms)
{
+ int temp, copen, cclos;
+ const char *comm_new;
+
+ /* Check for common symbol, and then progression into a
new/different
+ block of common symbols. Emit closing/opening common bracket
if
+ necessary. */
+ comm_new = dbxout_common_check (syms, &temp);
+ copen = comm_new != NULL
+ && (comm_prev == NULL || strcmp (comm_new, comm_prev));
+ cclos = comm_prev != NULL
+ && (comm_new == NULL || strcmp (comm_new, comm_prev));
+ if (cclos)
+ dbxout_common_name (syms, comm_prev, N_ECOMM);
+ if (copen)
+ {
+ dbxout_common_name (syms, comm_new, N_BCOMM);
+ syms_prev = syms;
+ }
+ comm_prev = comm_new;
+
result += dbxout_symbol (syms, 1);
syms = TREE_CHAIN (syms);
}
+
+ if (comm_prev != NULL)
+ dbxout_common_name (syms_prev, comm_prev, N_ECOMM);
+
return result;
}
More information about the Fortran
mailing list