[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