Bug 26772 - [readnow] FAIL: gdb.dwarf2/dw2-align.exp: set lang c++
Summary: [readnow] FAIL: gdb.dwarf2/dw2-align.exp: set lang c++
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: symtab (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: 11.1
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 25858 25980 (view as bug list)
Depends on:
Blocks:
 
Reported: 2020-10-22 06:26 UTC by Tom de Vries
Modified: 2020-10-28 20:15 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tom de Vries 2020-10-22 06:26:28 UTC
With target board readnow and test-case gdb.dwarf2/dw2-align.exp, I have:
...
(gdb) run ^M
Starting program: dw2-align ^M
^M
Breakpoint 1, 0x00000000004004ab in main ()^M
(gdb) set lang c++^M
Warning: the current language does not match this frame.^M
(gdb) FAIL: gdb.dwarf2/dw2-align.exp: set lang c++
...
Comment 1 Tom de Vries 2020-10-22 06:35:09 UTC
Adding a "show lang" gives us more info:
...
+gdb_test "show lang"                                                                              
 gdb_test_no_output "set lang c++"                                                                 ...

With readnow:
...
(gdb) run ^M
Starting program: dw2-align ^M
^M
Breakpoint 1, 0x00000000004004ab in main ()^M
(gdb) show lang^M
The current source language is "auto; currently asm".^M
(gdb) PASS: gdb.dwarf2/dw2-align.exp: show lang
set lang c++^M
Warning: the current language does not match this frame.^M
(gdb) FAIL: gdb.dwarf2/dw2-align.exp: set lang c++
...

Normal run:
...
(gdb) run ^M
Starting program: dw2-align ^M
^M
Breakpoint 1, 0x00000000004004ab in main ()^M
(gdb) show lang^M
The current source language is "auto; currently c".^M
(gdb) PASS: gdb.dwarf2/dw2-align.exp: show lang
set lang c++^M
(gdb) PASS: gdb.dwarf2/dw2-align.exp: set lang c++
...

So, the question seems to be, why is the language asm in the readnow case.

In other words:
...
$ gdb -batch ./outputs/gdb.dwarf2/dw2-align/dw2-align -ex start -ex "show language"
Temporary breakpoint 1 at 0x4004ab

Temporary breakpoint 1, 0x00000000004004ab in main ()
The current source language is "auto; currently c".
...
vs:
...
$ gdb -batch ./outputs/gdb.dwarf2/dw2-align/dw2-align -ex start -ex "show language" -readnow
Temporary breakpoint 1 at 0x4004ab

Temporary breakpoint 1, 0x00000000004004ab in main ()
The current source language is "auto; currently asm".
...
Comment 2 Tom de Vries 2020-10-22 06:46:19 UTC
The problem happens when select_frame is called, which calls find_pc_compunit_symtab (pc) with a pc of 0x4004ab, which corresponds to main_label:
...
00000000004004a7 <main>:
  4004a7:       55                      push   %rbp
  4004a8:       48 89 e5                mov    %rsp,%rbp

00000000004004ab <main_label>:
  4004ab:       b8 00 00 00 00          mov    $0x0,%eax
  4004b0:       5d                      pop    %rbp
  4004b1:       c3                      retq
  4004b2:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  4004b9:       00 00 00
  4004bc:       0f 1f 40 00             nopl   0x0(%rax)
...

In the normal case, find_pc_compunit_symtab (pc) == NULL.

In the readnow case, we have:
...
(gdb) p *cust
$2 = {next = 0x2089ba0, objfile = 0x1fe9ce0, name = 0x2088290 "crtn.S", 
  filetabs = 0x20882a0, last_filetab = 0x20882a0, debugformat = 0xe16d98 "DWARF 2", 
  producer = 0x1ff6cd5 "GNU AS 2.32.0", 
  dirname = 0x20884d0 "/home/abuild/rpmbuild/BUILD/glibc-2.26/csu", blockvector = 0x20883c0, 
  block_line_section = 11, locations_valid = 0, epilogue_unwind_valid = 0, 
  call_site_htab = 0x0, macro_table = 0x0, includes = 0x0, user = 0x0}
...
Comment 3 Tom de Vries 2020-10-22 07:28:48 UTC
In find_pc_sect_compunit_symtab, we iterate to find the best match:
...
  for (objfile *obj_file : current_program_space->objfiles ())
    {
      for (compunit_symtab *cust : obj_file->compunits ())
        {
...

And the global block for crtn.S matches, because the address 0x4004ab fits in the range:
...
(gdb) p /x b.startaddr
$6 = 0x4003c2
(gdb) p /x b.endaddr
$7 = 0x40053d
...

The crtn.S CU has a DW_AT_ranges attribute:
...
 <0><2e7>: Abbrev Number: 1 (DW_TAG_compile_unit)
    <2e8>   DW_AT_stmt_list   : 0x1a3
    <2ec>   DW_AT_ranges      : 0x40
    <2f0>   DW_AT_name        : ../sysdeps/x86_64/crtn.S
...
which corresponds to:
...
    00000040 ffffffffffffffff 0000000000000000 (base address)
    00000040 00000000004003c2 00000000004003c7
    00000040 0000000000400538 000000000040053d
    00000040 <End of list>
...

So, the global block correctly describes the outer limits of the address range of the crtn.S CU, but 0x4004ab is not part of the address range.

The idea behind the algorithm is that a CU should be found with a narrower match  for 0x4004ab, which will then be classified as the better match.

The problem is that the algorithm doesn't take into account the case that a narrower match is not present, and the best match is still inaccurate.

To get an accurate match, we can use f.i. the address map found in the block vector:
...
(gdb) p addrmap_find (bv.map, pc)
$26 = (void *) 0x0
...

Alternatively, also the static block seems to have accurate info:
....
(gdb) p /x bv.block[1].ranges.range[0]
$37 = {startaddr = 0x4003c2, endaddr = 0x4003c7}
(gdb) p /x bv.block[1].ranges.range[1]
$38 = {startaddr = 0x400538, endaddr = 0x40053d}
...
Comment 4 Tom de Vries 2020-10-22 07:31:47 UTC
This patch uses the addrmap:
...
diff --git a/gdb/symtab.c b/gdb/symtab.c
index a4f8239a8a..1148527f68 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -2920,10 +2920,20 @@ find_pc_sect_compunit_symtab (CORE_ADDR pc, struct obj_section *sec
tion)
          bv = COMPUNIT_BLOCKVECTOR (cust);
          b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
 
-         if (BLOCK_START (b) <= pc
-             && BLOCK_END (b) > pc
-             && (distance == 0
-                 || BLOCK_END (b) - BLOCK_START (b) < distance))
+         bool in_range_p = BLOCK_START (b) <= pc && pc < BLOCK_END (b);
+         if (!in_range_p)
+           continue;
+
+         if (BLOCKVECTOR_MAP (bv))
+           {
+             if (addrmap_find (BLOCKVECTOR_MAP (bv), pc) == nullptr)
+               continue;
+
+             return cust;
+           }
+
+         if (distance == 0
+             || BLOCK_END (b) - BLOCK_START (b) < distance)
            {
              /* For an objfile that has its functions reordered,
                 find_pc_psymtab will find the proper partial symbol table
...
such that we have:
...
$ gdb -batch ./outputs/gdb.dwarf2/dw2-align/dw2-align -ex start -ex "show language" -readnow
Temporary breakpoint 1 at 0x4004ab

Temporary breakpoint 1, 0x00000000004004ab in main ()
The current source language is "auto; currently c".
...
Comment 5 Tom de Vries 2020-10-22 07:52:51 UTC
Btw, this is on openSUSE Leap 15.2.

This doesn't reproduce on f.i. ubuntu 18.04.5, since there there's no debug info for crtn.S.
Comment 6 Tom de Vries 2020-10-22 09:22:46 UTC
Patch submitted at https://sourceware.org/pipermail/gdb-patches/2020-October/172733.html
Comment 7 Tom de Vries 2020-10-22 11:03:10 UTC
*** Bug 25858 has been marked as a duplicate of this bug. ***
Comment 8 Sourceware Commits 2020-10-28 20:04:18 UTC
The master branch has been updated by Tom de Vries <vries@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=1b00ef063f8230a1f110cc5aeef04d3dc1338358

commit 1b00ef063f8230a1f110cc5aeef04d3dc1338358
Author: Tom de Vries <tdevries@suse.de>
Date:   Wed Oct 28 21:04:12 2020 +0100

    [gdb/symtab] Fix language of frame without debug info
    
    On openSUSE Leap 15.2, I run into this FAIL with target board readnow and
    test-case gdb.dwarf2/dw2-align.exp:
    ...
    (gdb) set lang c++^M
    Warning: the current language does not match this frame.^M
    (gdb) FAIL: gdb.dwarf2/dw2-align.exp: set lang c++
    ...
    
    Adding some extra debugging shows that the current language differs without
    and with readnow:
    ...
     Breakpoint 1, 0x00000000004004ab in main ()^M
     (gdb) show lang^M
    -The current source language is "auto; currently c".^M
    +The current source language is "auto; currently asm".^M
    ...
    
    This is explained by find_pc_compunit_symtab (0x4004ab) called from
    select_frame, which:
    - without readnow: returns NULL, and
    - with readnow: returns the symtab for the CU crtn.S, wich has language
      "MIPS assembler".
    
    In the former case, the symtab for crtn.S is not expanded, and
    find_pc_compunit_symtab hits the default NULL return.  In the latter case, the
    symtab for crtn.S is expanded, and the "best match" loop in
    find_pc_compunit_symtab returns that symtab as its best match.
    
    The GLOBAL_BLOCK for crtn.S has these outer limits of the address range:
    ...
    (gdb) p /x b.startaddr
    $6 = 0x4003c2
    (gdb) p /x b.endaddr
    $7 = 0x40053d
    ...
    and 0x4004ab indeed fits in that range, which explains why the CU is
    considered a match.
    
    However, the actual address ranges for the CU are:
    ...
        00000040 ffffffffffffffff 0000000000000000 (base address)
        00000040 00000000004003c2 00000000004003c7
        00000040 0000000000400538 000000000040053d
        00000040 <End of list>
    ...
    which confirms that the CU should not be considered a match.
    
    The problem is that the "best match" loop is based on the assumption that a
    symtab with a better match will be found, but in this case we don't find a
    better match because there's no debug info describing main.
    
    Fix this by preferring to use the addres map in the "best match" loop, which
    will accurately tell us that addrmap_find (bv.map, 0x4004ab) == NULL.
    
    Tested on x86_64-linux (that is, openSUSE Leap 15.2), with and without
    readnow.  In the case of a readnow run, brings down the number of unexpected
    failures from 66 to 38.
    
    The FAIL does not reproduce on f.i. Ubuntu 18.04.5, because there the exec
    does not contain debug info for crtn.S.  The dwarf assembly test-case mimics
    the scenario described above, and reproduces the FAIL with and without
    -readnow, for both mentioned OS configurations.
    
    Also fixes PR25980 - "Overlapping Dwarf Compile Units with non-overlapping
    subranges gives incorrect line information".
    
    gdb/ChangeLog:
    
    2020-10-28  Tom de Vries  <tdevries@suse.de>
    
            PR symtab/26772
            * symtab.c (find_pc_sect_compunit_symtab): In case there's an address
            map, check it in the "best match" loop.
    
    gdb/testsuite/ChangeLog:
    
    2020-10-28  Tom de Vries  <tdevries@suse.de>
    
            PR symtab/26772
            * gdb.dwarf2/dw2-ranges-overlap.c: New test.
            * gdb.dwarf2/dw2-ranges-overlap.exp: New file.
Comment 9 Tom de Vries 2020-10-28 20:09:58 UTC
Patch with test-case committed, marking resolved-fixed.
Comment 10 Tom de Vries 2020-10-28 20:15:19 UTC
*** Bug 25980 has been marked as a duplicate of this bug. ***