[patch/rfc] Recognize non-DW_AT_location symbols

Jan Kratochvil
2009-03-16T20:20:58Z

Hi,

this patch is far from a perfect solution but it would be fine to check it in
if there is an approval as this patch is a regression-free GDB improvement:

for:
echo 'int main () { int x = 42; return x; }' | gcc -Wall -O2 -g -x c -

current GDB prints:
(gdb) p x
No symbol "x" in current context.
(gdb) ptype x
No symbol "x" in current context.

while patched GDB prints:
(gdb) p x
$1 = <value optimized out>
(gdb) ptype x
type = int

It can also happen for gcc-4.4 -O0 -g but that is more its bug (PR debug/39474).

With the current -O2 debugging situation I find the `No symbol ...' statements
even more confusing than pragmatic <value optimized out>.

Still this patch is just a fixup of the current incorrect GDB parsing code,
the proper solution should rewrite it from scratch. But it has no regressions
on x86_64-unknown-linux-gnu so it is at least an improvement.

Existing problems even with this patch:

* zero-length DW_AT_location should be the same as missing DW_AT_location.
https://fedorahosted.org/pipermail/elfutils-devel/2009-March/000180.html

GCC seems to use zero-length DW_AT_location for optimized-out variables and
no DW_AT_location if it fails to provide it for whatever reason. But not
always.

If GDB would always use zero-length DW_AT_location for optimized-out symbols
vs. no DW_AT_location for non-defining declarations this GDB patch would not
be needed as this is the current (DWARF-noncompliant) GDB expectation.

* Missing DWARF3 2.13.2 Declarations Completing Non-Defining Declarations:
Current ignorance of LOC_OPTIMIZED_OUT symbols was used for C++ symbols
completion. Fixing the LOC_OPTIMIZED_OUT symbols presents break C++ symbols
completion as the code then recognizes the first instance of the symbol (even
if it is LOC_OPTIMIZED_OUT) thus ignoring its later completion such as for:
<3><247>: Abbrev Number: 18 (DW_TAG_variable)
<248> DW_AT_name : cX
<24d> DW_AT_type : <0xca>
<251> DW_AT_declaration : 1
<1><5c5>: Abbrev Number: 37 (DW_TAG_variable)
<5c6> DW_AT_specification: <0x247>
<5ca> DW_AT_const_value : 6
The insert_symbol_hashed() part of the patch fixes up this specific case to
have no testsuite regressions on gcc. Still a more general fix should be made.

* For external variables it still prints
Address of symbol "foo" is unknown.
while it should print
<value optimized out>
because (read_var_value <LOC_UNRESOLVED> <msym == NULL>) should return
not_lval+set_value_optimized_out but providing such patch causes regression
on other GDB C++ support code.

* The updated testcase is probably incompatible with Alpha (larger than 32bit
file addresses), also it should test more types of symbol placements, `main'
range is not correct, CU range is not correct etc.

Updated patch fixes for current GDB its new testcases:
FAIL: gdb.dwarf2/dw2-noloc.exp: print noloc_local (file-scope optimized-out)
FAIL: gdb.dwarf2/dw2-noloc.exp: ptype noloc_local
FAIL: gdb.dwarf2/dw2-noloc.exp: print noloc_local2 (function-scope optimized-out)
FAIL: gdb.dwarf2/dw2-noloc.exp: ptype noloc_local2

Thanks,
Jan

gdb/
2009-03-16 Jan Kratochvil <jan.kratochvil@redhat.com>

Recognize missing DW_AT_location as <value optimized out>.
* dictionary.c (insert_symbol_hashed): New variables `iterp', `iter'.
Remove non-defining declaration completed by later declarations.
* dwarf2read.c
(new_symbol <DW_TAG_variable> <!DW_AT_location> <!DW_AT_external>):
Call add_symbol_to_list.

gdb/testsuite/
2009-03-16 Jan Kratochvil <jan.kratochvil@redhat.com>

* gdb.dwarf2/dw2-noloc.exp: Compile main.c with nodebug.
(print noloc): Rename to ...
(print noloc_unresolvable): ... here.
(print hasloc_direct, print hasloc_resolvable, print noloc_local)
(print hasloc_direct2, print hasloc_resolvable2)
(print noloc_unresolvable2, print noloc_local2): New.
* gdb.dwarf2/dw2-noloc.S (main_end, hasloc_resolvable)
(hasloc_resolvable2): New.
(DW_AT_high_pc): Change it to `main_end'.
(noloc): Rename to ...
(noloc_unresolvable): ... here.
(hasloc_direct, hasloc_resolvable, noloc_local, hasloc_direct2)
(hasloc_resolvable2, noloc_unresolvable2, noloc_local2): New.

--- gdb/dictionary.c 3 Jan 2009 05:57:51 -0000 1.10
+++ gdb/dictionary.c 16 Mar 2009 18:18:49 -0000
@@ -670,10 +670,34 @@ insert_symbol_hashed (struct dictionary
struct symbol *sym)
{
unsigned int hash_index;
- struct symbol **buckets = DICT_HASHED_BUCKETS (dict);
+ struct symbol **buckets = DICT_HASHED_BUCKETS (dict), **iterp, *iter;

hash_index = (msymbol_hash_iw (SYMBOL_SEARCH_NAME (sym))
% DICT_HASHED_NBUCKETS (dict));
+
+ /* Remove non-defining declaration completed by later declarations
+ (DWARF3 2.13.2). As there may be multiple symbols of the same
+ SYMBOL_SEARCH_NAME but different SYMBOL_CLASS replace only those that have
+ lower validity (in the order of LOC* > LOC_UNRESOLVED > LOC_OPTIMIZED_OUT).
+
+ dict_create_linear should also contain such code but the C++ declarations
+ completing in practice exists only for file/global symbols which are being
+ indexed only using this function insert_symbol_hashed.
+
+ As this function is called in a reverse order than the placement of the
+ symbols in the inferior the RETURN statement will ensure the symbol gets
+ replaced. */
+
+ if (SYMBOL_CLASS (sym) == LOC_OPTIMIZED_OUT
+ || SYMBOL_CLASS (sym) == LOC_UNRESOLVED)
+ for (iterp = &buckets[hash_index]; (iter = *iterp) != NULL;
+ iterp = &iter->hash_next)
+ if (strcmp (SYMBOL_SEARCH_NAME (iter), SYMBOL_SEARCH_NAME (sym)) == 0
+ && (SYMBOL_CLASS (sym) == LOC_OPTIMIZED_OUT
+ || (SYMBOL_CLASS (sym) == LOC_UNRESOLVED
+ && SYMBOL_CLASS (iter) == LOC_OPTIMIZED_OUT)))
+ return;
+
sym->hash_next = buckets[hash_index];
buckets[hash_index] = sym;
}
--- gdb/dwarf2read.c 9 Mar 2009 18:53:48 -0000 1.296
+++ gdb/dwarf2read.c 16 Mar 2009 18:18:53 -0000
@@ -7658,6 +7658,11 @@ new_symbol (struct die_info *die, struct
SYMBOL_CLASS (sym) = LOC_UNRESOLVED;
add_symbol_to_list (sym, &global_symbols);
}
+ else
+ {
+ /* Use the default LOC_OPTIMIZED_OUT class. */
+ add_symbol_to_list (sym, cu->list_in_scope);
+ }
}
break;
case DW_TAG_formal_parameter:
--- gdb/testsuite/gdb.dwarf2/dw2-noloc.S 3 Jan 2009 05:58:04 -0000 1.4
+++ gdb/testsuite/gdb.dwarf2/dw2-noloc.S 16 Mar 2009 18:18:54 -0000
@@ -26,6 +26,15 @@ func_cu1:
.size func_cu1, .-func_cu1
.Lend_text1:

+ .equ main_end, main + 0x100 /* Just an estimate. */
+
+ .data
+ .globl hasloc_resolvable
+ .globl hasloc_resolvable2
+hasloc_resolvable:
+hasloc_resolvable2:
+ .4byte 1234567890
+
/* Debug information */

.section .debug_info
@@ -40,7 +49,7 @@ func_cu1:
/* CU die */
.uleb128 1 /* Abbrev: DW_TAG_compile_unit */
.4byte .Lline1_begin /* DW_AT_stmt_list */
- .4byte .Lend_text1 /* DW_AT_high_pc */
+ .4byte main_end /* DW_AT_high_pc */
.4byte .Lbegin_text1 /* DW_AT_low_pc */
.ascii "file1.txt\0" /* DW_AT_name */
.ascii "GNU C 3.3.3\0" /* DW_AT_producer */
@@ -64,11 +73,65 @@ func_cu1:
.byte 4 /* DW_AT_byte_size */
.byte 5 /* DW_AT_encoding */

- .uleb128 4 /* Abbrev: DW_TAG_variable */
- .ascii "noloc\0" /* DW_AT_name */
+ .uleb128 7 /* Abbrev: DW_TAG_variable (location) */
+ .ascii "hasloc_direct\0" /* DW_AT_name */
+ .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
+ .byte 2f - 1f /* DW_AT_location */
+1:
+ .byte 3 /* DW_OP_addr */
+ .4byte hasloc_resolvable /* <addr> */
+2:
+
+ .uleb128 4 /* Abbrev: DW_TAG_variable (extern) */
+ .ascii "hasloc_resolvable\0" /* DW_AT_name */
+ .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
+ .byte 1 /* DW_AT_external */
+
+ .uleb128 4 /* Abbrev: DW_TAG_variable (extern) */
+ .ascii "noloc_unresolvable\0" /* DW_AT_name */
+ .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
+ .byte 1 /* DW_AT_external */
+
+ .uleb128 5 /* Abbrev: DW_TAG_variable (local) */
+ .ascii "noloc_local\0" /* DW_AT_name */
+ .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
+
+ /* main */
+ .uleb128 6 /* Abbrev: DW_TAG_subprogram */
+ .byte 1 /* DW_AT_decl_file */
+ .byte 2 /* DW_AT_decl_line */
+ .ascii "main\0" /* DW_AT_name */
+ .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
+ .4byte main /* DW_AT_low_pc */
+ .4byte main_end /* DW_AT_high_pc */
+ .byte 1 /* DW_AT_frame_base: length */
+ .byte 0x55 /* DW_AT_frame_base: DW_OP_reg5 */
+
+ .uleb128 7 /* Abbrev: DW_TAG_variable (location) */
+ .ascii "hasloc_direct2\0" /* DW_AT_name */
+ .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
+ .byte 2f - 1f /* DW_AT_location */
+1:
+ .byte 3 /* DW_OP_addr */
+ .4byte hasloc_resolvable /* <addr> */
+2:
+
+ .uleb128 4 /* Abbrev: DW_TAG_variable (extern) */
+ .ascii "hasloc_resolvable2\0" /* DW_AT_name */
.4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
.byte 1 /* DW_AT_external */

+ .uleb128 4 /* Abbrev: DW_TAG_variable (extern) */
+ .ascii "noloc_unresolvable2\0" /* DW_AT_name */
+ .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
+ .byte 1 /* DW_AT_external */
+
+ .uleb128 5 /* Abbrev: DW_TAG_variable (local) */
+ .ascii "noloc_local2\0" /* DW_AT_name */
+ .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
+
+ .byte 0 /* End of children of main */
+
.byte 0 /* End of children of CU */

.Lcu1_end:
@@ -128,7 +191,7 @@ func_cu1:
.byte 0x0 /* Terminator */
.byte 0x0 /* Terminator */

- .uleb128 4 /* Abbrev code */
+ .uleb128 4 /* Abbrev code (extern) */
.uleb128 0x34 /* DW_TAG_variable */
.byte 0 /* has_children */
.uleb128 0x3 /* DW_AT_name */
@@ -140,6 +203,48 @@ func_cu1:
.byte 0x0 /* Terminator */
.byte 0x0 /* Terminator */

+ .uleb128 5 /* Abbrev code (local) */
+ .uleb128 0x34 /* DW_TAG_variable */
+ .byte 0 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 6 /* Abbrev code */
+ .uleb128 0x2e /* DW_TAG_subprogram */
+ .byte 1 /* has_children */
+ .uleb128 0x3a /* DW_AT_decl_file */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3b /* DW_AT_decl_line */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x40 /* DW_AT_frame_base */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 7 /* Abbrev code (location) */
+ .uleb128 0x34 /* DW_TAG_variable */
+ .byte 0 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x2 /* DW_AT_location */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
.byte 0x0 /* Terminator */
.byte 0x0 /* Terminator */

--- gdb/testsuite/gdb.dwarf2/dw2-noloc.exp 3 Jan 2009 05:58:04 -0000 1.4
+++ gdb/testsuite/gdb.dwarf2/dw2-noloc.exp 16 Mar 2009 18:18:54 -0000
@@ -28,7 +28,7 @@ set testfile "dw2-noloc"
set srcfile ${testfile}.S
set binfile ${objdir}/${subdir}/${testfile}.x

-if { [gdb_compile "${srcdir}/${subdir}/main.c" "main.o" object {debug}] != "" } {
+if { [gdb_compile "${srcdir}/${subdir}/main.c" "main.o" object {nodebug}] != "" } {
return -1
}

@@ -45,4 +45,30 @@ gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}

-gdb_test "print noloc" "Address of symbol \"noloc\" is unknown." "print noloc"
+gdb_test "print hasloc_direct" "= 1234567890"
+gdb_test "ptype hasloc_direct" "type = int"
+
+gdb_test "print hasloc_resolvable" "= 1234567890"
+gdb_test "ptype hasloc_resolvable" "type = int"
+
+gdb_test "print noloc_unresolvable" "Address of symbol \"noloc_unresolvable\" is unknown\\."
+gdb_test "ptype noloc_unresolvable" "type = int"
+
+gdb_test "print noloc_local" "= <value optimized out>"
+gdb_test "ptype noloc_local" "type = int"
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_test "print hasloc_direct2" "= 1234567890"
+gdb_test "ptype hasloc_direct2" "type = int"
+
+gdb_test "print hasloc_resolvable2" "= 1234567890"
+gdb_test "ptype hasloc_resolvable2" "type = int"
+
+gdb_test "print noloc_unresolvable2" "Address of symbol \"noloc_unresolvable2\" is unknown\\."
+gdb_test "ptype noloc_unresolvable2" "type = int"
+
+gdb_test "print noloc_local2" "= <value optimized out>"
+gdb_test "ptype noloc_local2" "type = int"