Bug 78063 - libbacktrace fails to handle cross CU DW_AT_abstract_origin
Summary: libbacktrace fails to handle cross CU DW_AT_abstract_origin
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libbacktrace (show other bugs)
Version: 7.0
: P3 normal
Target Milestone: 9.0
Assignee: Tom de Vries
URL:
Keywords:
Depends on: 81081
Blocks:
  Show dependency treegraph
 
Reported: 2016-10-21 09:42 UTC by Richard Biener
Modified: 2019-02-08 10:12 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2018-05-08 00:00:00


Attachments
Tentative patch "[libbacktrace] Handle DW_FORM_ref_addr" (969 bytes, patch)
2019-02-06 21:33 UTC, Tom de Vries
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Richard Biener 2016-10-21 09:42:40 UTC
Currently libbacktrace doesn't handle the pending early LTO debug way of separating early debug and late debug.  We have

  Compilation Unit @ offset 0xfcc:
   Length:        0x111 (32-bit)
   Version:       4
   Abbrev Offset: 0x362
   Pointer Size:  8
 <0><fd7>: Abbrev Number: 1 (DW_TAG_compile_unit)
    <fd8>   DW_AT_producer    : (indirect string, offset: 0x1574): GNU C11 7.0.0
 20161020 (experimental) -mtune=generic -march=x86-64 -g -O2 -O2 -fsanitize=addr
ess -flto -fno-use-linker-plugin -flto-partition=none
    <fdc>   DW_AT_language    : 12      (ANSI C99)
    <fdd>   DW_AT_name        : (indirect string, offset: 0x1523): /space/rguent
her/src/svn/trunk/gcc/testsuite/c-c++-common/asan/misalign-1.c
...
 <1><10cb>: Abbrev Number: 14 (DW_TAG_subprogram)
    <10cc>   DW_AT_external    : 1
    <10cc>   DW_AT_name        : foo
    <10d0>   DW_AT_decl_file   : 1
    <10d1>   DW_AT_decl_line   : 9
    <10d2>   DW_AT_prototyped  : 1
    <10d2>   DW_AT_type        : <0xff6>

and

  Compilation Unit @ offset 0xe37:
   Length:        0x191 (32-bit)
   Version:       4
   Abbrev Offset: 0x296
   Pointer Size:  8
 <0><e42>: Abbrev Number: 1 (DW_TAG_compile_unit)
    <e43>   DW_AT_producer    : (indirect string, offset: 0x13c4): GNU GIMPLE 7.
0.0 20161020 (experimental) -mtune=generic -march=x86-64 -mtune=generic -march=x
86-64 -g -O2 -O2 -O2 -O2 -fmath-errno -fsigned-zeros -ftrapping-math -fno-trapv 
-fno-strict-overflow -fno-openmp -fno-openacc -fsanitize=address -fno-use-linker
-plugin -flto-partition=none
    <e47>   DW_AT_language    : 12      (ANSI C99)
    <e48>   DW_AT_name        : (indirect string, offset: 0x14de): <artificial>
    <e4c>   DW_AT_comp_dir    : (indirect string, offset: 0x14eb): /abuild/rguen
ther/obj/gcc
    <e50>   DW_AT_ranges      : 0x40
    <e54>   DW_AT_low_pc      : 0x0
    <e5c>   DW_AT_stmt_list   : 0x290
 <1><e60>: Abbrev Number: 2 (DW_TAG_imported_unit)
    <e61>   DW_AT_import      : <0xfd7> [Abbrev Number: 1]
...
 <1><e65>: Abbrev Number: 3 (DW_TAG_subprogram)
    <e66>   DW_AT_abstract_origin: <0x10cb>
    <e6a>   DW_AT_low_pc      : 0x400ac0
    <e72>   DW_AT_high_pc     : 0x59
    <e7a>   DW_AT_frame_base  : 1 byte block: 9c        (DW_OP_call_frame_cfa)
    <e7c>   DW_AT_GNU_all_call_sites: 1
    <e7c>   DW_AT_sibling     : <0xe9d>

so we run into

static int
read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
                     struct unit *u, uint64_t base, struct dwarf_buf *unit_buf,
                     const struct line_header *lhdr,
                     backtrace_error_callback error_callback, void *data,
                     struct function_vector *vec_function,
                     struct function_vector *vec_inlined)
{
...
                case DW_AT_abstract_origin:
                case DW_AT_specification:
                  if (abbrev->attrs[i].form == DW_FORM_ref_addr
                      || abbrev->attrs[i].form == DW_FORM_ref_sig8)
                    {
                      /* This refers to an abstract origin defined in
                         some other compilation unit.  We can handle
                         this case if we must, but it's harder.  */
                      break;
                    }
                  if (val.encoding == ATTR_VAL_UINT
                      || val.encoding == ATTR_VAL_REF_UNIT)
                    {
                      const char *name;

                      name = read_referenced_name (ddata, u, val.u.uint,
                                                   error_callback, data);
                      if (name != NULL)
                        function->name = name;
                    }

which causes us to fail to specify the function name to the dwarf_lookup_pc
callback.  This causes libsanitizer to not print file/line info but fall
back to symbolic backtrace completely (it could at least preserve the
partial info I guess).  Which in turn causes most asan and tsan tests
in the testsuite to FAIL with -flto because they scan for a proper
backtrace but we get

READ of size 4 at 0x7fff24ce1c8f thread T0
    #0 0x400b18 in foo (/home/abuild/rguenther/obj/gcc/misalign-1.exe+0x400b18)
    #1 0x40092c in main (/home/abuild/rguenther/obj/gcc/misalign-1.exe+0x40092c)

instead of the desired

READ of size 4 at 0x7fff2193ea1f thread T0
    #0 0x400b98 in foo /space/rguenther/src/svn/trunk2/gcc/testsuite/c-c++-common/asan/misalign-1.c:11
    #1 0x4009af in main /space/rguenther/src/svn/trunk2/gcc/testsuite/c-c++-common/asan/misalign-1.c:35

as said, libbacktrace computes file and line correctly but fails to lookup
the function DW_AT_name as that is only available in the abstract origin.
Comment 1 Richard Biener 2017-11-10 13:46:04 UTC
Now manifests itself for LTO bootstrapped compilers.
Comment 2 Romain Geissler 2018-05-04 00:22:33 UTC
Hi,

As written in previous comments, this now breaks both libbacktrace tests + all sanitizer tests using backtrace when using gcc >= 8 and an LTO bootstrapped compiler.

Shall we XFAIL temporarily these tests in case of LTO bootstrap (if that is even possible) ?

Here is a list of tests which are failing for me:

test1: [0]: missing file name or function name
FAIL: backtrace_full alloc stress
FAIL: edtest
test1: [0]: missing file name or function name
test1: [0]: missing file name or function name
test1: [0]: missing file name or function name
test1: [0]: missing file name or function name
test1: [0]: missing file name or function name
test1: [0]: missing file name or function name
test1: [0]: missing file name or function name
test1: [0]: missing file name or function name
test1: [0]: missing file name or function name
test1: [0]: missing file name or function name
FAIL: threaded backtrace_full noinline
FAIL: ttest

Cheers,
Romain
Comment 3 Richard Biener 2018-05-08 07:08:35 UTC
(In reply to Romain Geissler from comment #2)
> Hi,
> 
> As written in previous comments, this now breaks both libbacktrace tests +
> all sanitizer tests using backtrace when using gcc >= 8 and an LTO
> bootstrapped compiler.

The sanitizer tests should behave OK (but I didn't recently double-check).
I've adjusted their expected patterns to cope with the new DWARF.

> Shall we XFAIL temporarily these tests in case of LTO bootstrap (if that is
> even possible) ?
> 
> Here is a list of tests which are failing for me:
> 
> test1: [0]: missing file name or function name
> FAIL: backtrace_full alloc stress
> FAIL: edtest
> test1: [0]: missing file name or function name
> test1: [0]: missing file name or function name
> test1: [0]: missing file name or function name
> test1: [0]: missing file name or function name
> test1: [0]: missing file name or function name
> test1: [0]: missing file name or function name
> test1: [0]: missing file name or function name
> test1: [0]: missing file name or function name
> test1: [0]: missing file name or function name
> test1: [0]: missing file name or function name
> FAIL: threaded backtrace_full noinline
> FAIL: ttest

I think the easiest fix would be to add -fno-lto to the test CFLAGS.
We already build some of the host libraries with -fno-lto for various
reasons.  Ah, only libdecnumber it seems.

Of course the best thing would be to fix this bug rather than working
around it...

> Cheers,
> Romain
Comment 4 Tom de Vries 2019-02-06 21:33:35 UTC
Created attachment 45622 [details]
Tentative patch "[libbacktrace] Handle DW_FORM_ref_addr"

Patch passes regular bootstrap and reg-test.
Comment 5 Ian Lance Taylor 2019-02-07 00:29:05 UTC
Patch looks basically OK to me.
Comment 6 Martin Liška 2019-02-07 12:31:50 UTC
I can confirm LTO bootstrapped GCC can properly report backtraces for an ICE.
Moreover, asan.exp tests work fine (compiled with -flto).
Comment 7 Tom de Vries 2019-02-08 05:56:16 UTC
Author: vries
Date: Fri Feb  8 05:55:44 2019
New Revision: 268663

URL: https://gcc.gnu.org/viewcvs?rev=268663&root=gcc&view=rev
Log:
[libbacktrace] Handle DW_FORM_ref_addr

Add handling of the DW_FORM_ref_addr encoding to libbacktrace.

2019-02-08  Tom de Vries  <tdevries@suse.de>

	PR libbacktrace/78063
	* dwarf.c (build_address_map): Keep all parsed units.
	(read_referenced_name_from_attr): Handle DW_FORM_ref_addr.

Modified:
    trunk/libbacktrace/ChangeLog
    trunk/libbacktrace/dwarf.c
Comment 8 Tom de Vries 2019-02-08 10:12:12 UTC
Patch committed.

Test-case patch submitted ( https://gcc.gnu.org/ml/gcc-patches/2019-02/msg00432.html ).

Marking resolved-fixed.