[RFA] Nullified garbage-collected global variables

Jerome Guitton
2010-07-12T15:22:02Z

The unused data/code elimination done by LD leaves some null partial
symbols; unfortunately, LD is not smart enough to drop this unused
dwarf debug info. So it's up to GDB to discard them.

For example, consider p.c:

/******************************/

int my_global_symbol = 42;

static int my_static_symbol;

int
main ()
{
return 1;
}

/******************************/

...and q.c:

/******************************/

static int my_static_symbol;

void
r ()
{
my_static_symbol = my_global_symbol;
my_global_symbol = my_static_symbol + my_global_symbol;
}

/******************************/

...built with -fdata-sections/-ffunction-sections and linked with -gc-sections:

gcc -c -g -ffunction-sections -fdata-sections p.c
gcc -Wl,-gc-sections -Wl,-e,main p.o -o p

gcc -c -g -ffunction-sections -fdata-sections r.c
gcc -Wl,-gc-sections -Wl,-e,r r.o -o r

In the final executable p, my_global_symbol will be removed, as it is
not used. But the linker cannot remove the corresponding debug info;
it will just nullify my_global_symbol's address in its location
expression.

If we load both p and r in GDB (e.g. using add-symbol-file) the value
of my_global_symbol's address will depend on load order:
* p before r => &my_global_symbol == 0
* r before p => &my_global_symbol not null

The second scenario is the correct one; my_global_symbol is taken from
r. You would expect the same behavior in the case of the first
scenario...

This example may seem a bit artificial, but if you consider two
modules that are linked against the same library, then stripped using
-gc-sections, then both loaded on the same target, you will understand
that the user may have some troubles debugging the variables in his
library, depending on what has been dragged into which module and
what has been dropped, and depending on the load order.

OK to apply? If so, I'll provide a new testcase.

gdb/ChangeLog:
* dwarf2read.c (add_partial_symbol): Do not add a global variable if
its adress is null. Add comment to explain why.
---
gdb/dwarf2read.c | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index e4ab034..da85aa2 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -2447,7 +2447,10 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
Don't enter into the minimal symbol tables as there is
a minimal symbol table entry from the ELF symbols already.
Enter into partial symbol table if it has a location
- descriptor or a type.
+ descriptor or a type. A global variable may also have been
+ stripped out by the linker if unused, in which case its
+ address will be nullified; do not add such variables into
+ partial symbol table then.
If the location descriptor is missing, new_symbol will create
a LOC_UNRESOLVED symbol, the address of the variable will then
be determined from the minimal symbol table whenever the variable
@@ -2458,7 +2461,7 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)

if (pdi->locdesc)
addr = decode_locdesc (pdi->locdesc, cu);
- if (pdi->locdesc || pdi->has_type)
+ if ((pdi->locdesc && addr) || (!pdi->locdesc && pdi->has_type))
psym = add_psymbol_to_list (actual_name, strlen (actual_name),
built_actual_name,
VAR_DOMAIN, LOC_STATIC,
--
1.6.5.rc2