[committed][PATCH][gdb/breakpoint, PIE] Handle setting breakpoint on label without address

Tom de Vries
2020-09-03T10:34:52Z

On 8/28/20 3:20 PM, Tom de Vries wrote:
> [ was: Re: [PATCH][gdb/breakpoint] Handle setting breakpoint on label
> without address ]
>
> On 8/28/20 12:31 PM, Tom de Vries wrote:
>> On 8/27/20 3:49 PM, Tom de Vries wrote:
>>> On 8/27/20 2:41 PM, Pedro Alves wrote:
>>>> On 8/27/20 12:52 PM, Tom de Vries wrote:
>>>>> Hi,
>>>>>
>>>>> Consider test-case test.c:
>>>>> ...
>>>>> $ cat test.c
>>>>> int main (void) {
>>>>> return 0;
>>>>> L1:
>>>>> (void)0;
>>>>> }
>>>>> ...
>>>>>
>>>>> Compiled with debug info:
>>>>> ...
>>>>> $ gcc test.c -g
>>>>> ...
>>>>>
>>>>> When attempting to set a breakpoint at L1, which is a label without address:
>>>>> ...
>>>>> <1><f4>: Abbrev Number: 2 (DW_TAG_subprogram)
>>>>> <f5> DW_AT_name : main
>>>>> <2><115>: Abbrev Number: 3 (DW_TAG_label)
>>>>> <116> DW_AT_name : L1
>>>>> <119> DW_AT_decl_file : 1
>>>>> <11a> DW_AT_decl_line : 5
>>>>> <2><11b>: Abbrev Number: 0
>>>> Is this a debug info bug,
>>> Strictly speaking, this is a debug info bug. The standard says that:
>>> ...
>>> The label entry has a DW_AT_low_pc attribute whose value is the address
>>> of the first executable instruction for the location identified by the
>>> label in the source program.
>>> ...
>>>
>>> But I interpret the missing DW_AT_low_pc attribute as: there is a label
>>> in the source, but the corresponding code has been optimized out.
>>>
>>>> or is the debug info telling us that the
>>>> address of the label is the same as the line number's address?
>>>>
>>>> How about looking up the line number address instead of throwing
>>>> an error?
>>>>
>>> Well, in this particular case, that wouldn't help.
>>>
>>> With L1 at line 3:
>>> ...
>>> $ cat -n test.c
>>> 1 int main (void) {
>>> 2 return 0;
>>> 3 L1:
>>> 4 (void)0;
>>> 5 }
>>> 6
>>> ...
>>> there's no corresponding address:
>>> ...
>>> $ readelf -wL a.out
>>> CU: test.c:
>>> File name Line number Starting address
>>> View Stmt
>>> test.c 1 0x400497
>>> x
>>> test.c 2 0x40049b
>>> x
>>> test.c 5 0x4004a0
>>> x
>>> test.c - 0x4004a2
>>> ...
>>>
>>> My suspicion is that this won't be useful in general.
>>>
>> I've pushed this as attached below, with the test-case updated to work
>> around PR26546 - "[pie] Setting breakpoint on missing label sets
>> breakpoint at offset 0 in NULL section" (
>> https://sourceware.org/bugzilla/show_bug.cgi?id=26546 ).
> Which is fixed by the patch below.
>
> Any comments?
>

I've committed this.

Thanks,
- Tom
>
> 0001-gdb-breakpoint-PIE-Handle-setting-breakpoint-on-label-without-address.patch
>
> [gdb/breakpoint, PIE] Handle setting breakpoint on label without address
>
> When adding:
> ...
> if ![runto_main] then {
> fail "can't run to main"
> return 0
> }
> ...
> to test-case gdb.base/label-without-address.exp and running it with target
> board unix/-fPIE/-pie, we run into:
> ...
> (gdb) break main:L1^M
> Breakpoint 2 at 0x555555554000: file label-without-address.c, line 22.^M
> ...
> That is, for a label with optimized-out address, we set a breakpoint at the
> relocation base.
>
> The root cause is that the dwarf reader, despite finding that attribute
> DW_AT_low_pc is missing, still tags the L1 symbol as having LOC_LABEL, which
> means it has a valid address, which defaults to 0.
>
> Fix this by instead tagging the L1 symbol with LOC_OPTIMIZED_OUT.
>
> Tested on x86_64-linux.
>
> gdb/ChangeLog:
>
> 2020-08-28 Tom de Vries <tdevries@suse.de>
>
> PR breakpoint/26546
> * dwarf2/read.c (new_symbol): Tag label symbol without DW_AT_low_pc as
> LOC_OPTIMIZED_OUT instead of LOC_LABEL.
>
> gdb/testsuite/ChangeLog:
>
> 2020-08-28 Tom de Vries <tdevries@suse.de>
>
> PR breakpoint/26546
> * gdb.base/label-without-address.exp: Runto main first.
>
> ---
> gdb/dwarf2/read.c | 4 +++-
> gdb/testsuite/gdb.base/label-without-address.exp | 5 +++++
> 2 files changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
> index 0ac8533263..b37f7e7a2f 100644
> --- a/gdb/dwarf2/read.c
> +++ b/gdb/dwarf2/read.c
> @@ -21447,10 +21447,12 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
> addr = attr->value_as_address ();
> addr = gdbarch_adjust_dwarf2_addr (gdbarch, addr + baseaddr);
> SET_SYMBOL_VALUE_ADDRESS (sym, addr);
> + SYMBOL_ACLASS_INDEX (sym) = LOC_LABEL;
> }
> + else
> + SYMBOL_ACLASS_INDEX (sym) = LOC_OPTIMIZED_OUT;
> SYMBOL_TYPE (sym) = objfile_type (objfile)->builtin_core_addr;
> SYMBOL_DOMAIN (sym) = LABEL_DOMAIN;
> - SYMBOL_ACLASS_INDEX (sym) = LOC_LABEL;
> add_symbol_to_list (sym, cu->list_in_scope);
> break;
> case DW_TAG_subprogram:
> diff --git a/gdb/testsuite/gdb.base/label-without-address.exp b/gdb/testsuite/gdb.base/label-without-address.exp
> index 0fcb1fd19a..c688149cf3 100644
> --- a/gdb/testsuite/gdb.base/label-without-address.exp
> +++ b/gdb/testsuite/gdb.base/label-without-address.exp
> @@ -19,6 +19,11 @@ if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} {
> return -1
> }
>
> +if ![runto_main] then {
> + fail "can't run to main"
> + return 0
> +}
> +
> set supported 0
> gdb_test_multiple "l main:L1" "" {
> -wrap -re "No label \"L1\" defined in function \"main\"\." {
>