[Bug symtab/34389] New: Source code lookup fails for code at or near 0 when linking with garbage collection

aburgess at redhat dot com via Gdb-prs <[email protected]>
Newsgroups gmane.comp.gdb.bugs.discuss
Message-ID <[email protected]/bugzilla/>
https://sourceware.org/bugzilla/show_bug.cgi?id=34389

            Bug ID: 34389
           Summary: Source code lookup fails for code at or near 0 when
                    linking with garbage collection
           Product: gdb
           Version: HEAD
            Status: NEW
          Severity: normal
          Priority: P2
         Component: symtab
          Assignee: unassigned at sourceware dot org
          Reporter: aburgess at redhat dot com
  Target Milestone: ---

Created attachment 16836
  --> https://sourceware.org/bugzilla/attachment.cgi?id=16836&action=edit
Reproducer for this bug.

This issue was reported here:

 
https://inbox.sourceware.org/gdb/CAGnW-qix0m4Y1zJG8OE640OkJZXwbsHX-Jk5JH6sfFy1aOvuNw@mail.gmail.com

  I had an LLM create a simpler reproducer, but this is still risc-v
  only, so you'll need to setup a risc-v tool chain.  However, the bug
  can be revealed using GDB's built-in risc-v simulator.

  Download the attached `addr-zero.tar.xz` file then:

  ```
  tar -xf addr-zero.tar.xz
  cd addr-zero/
  make
  ```

  You should now have a `repro.elf` file.

  Here's a session where I avoid triggering the bug, notice that when
  I disassemble `target_func` I can see both the assembly instructions
  and the source code:

  ```
  (gdb) file repro.elf
  (gdb) target sim
  (gdb) load
  (gdb) disassemble /s target_func
  Dump of assembler code for function target_func:
  file_a.c:
  7     {
     0x00000000000000a4 <+0>:   addi    sp,sp,-48
     0x00000000000000a8 <+4>:   sd      ra,40(sp)
     0x00000000000000ac <+8>:   sd      s0,32(sp)
     0x00000000000000b0 <+12>:  addi    s0,sp,48
     0x00000000000000b4 <+16>:  mv      a5,a0
     0x00000000000000b8 <+20>:  sw      a5,-36(s0)

  8             int a = x + 1;
     0x00000000000000bc <+24>:  lw      a5,-36(s0)
     0x00000000000000c0 <+28>:  addiw   a5,a5,1
     0x00000000000000c4 <+32>:  sw      a5,-20(s0)

  9             int b = a + 2;
     0x00000000000000c8 <+36>:  lw      a5,-20(s0)
     0x00000000000000cc <+40>:  addiw   a5,a5,2
     0x00000000000000d0 <+44>:  sw      a5,-24(s0)

  10            int c = b + 3;
     0x00000000000000d4 <+48>:  lw      a5,-24(s0)
     0x00000000000000d8 <+52>:  addiw   a5,a5,3
     0x00000000000000dc <+56>:  sw      a5,-28(s0)

  11            sink = c;
     0x00000000000000e0 <+60>:  lw      a4,-28(s0)
     0x00000000000000e4 <+64>:  sw      a4,260(zero) # 0x104 <sink>

  12            return c;
     0x00000000000000e8 <+68>:  lw      a5,-28(s0)

  13    }
     0x00000000000000ec <+72>:  mv      a0,a5
     0x00000000000000f0 <+76>:  ld      ra,40(sp)
     0x00000000000000f4 <+80>:  ld      s0,32(sp)
     0x00000000000000f8 <+84>:  addi    sp,sp,48
     0x00000000000000fc <+88>:  ret
  End of assembler dump.
  (gdb)
  ```

  And here's a session where I trigger the bug by first disassembling
  the `target` function, now when I disassemble `target_func` I no
  longer see the source code:

  ```
  (gdb) file repro.elf
  (gdb) target sim
  (gdb) load
  (gdb) disassemble /s helper
  Dump of assembler code for function helper:
  file_b.c:
  12    {
     0x0000000000000014 <+0>:   addi    sp,sp,-32
     0x0000000000000018 <+4>:   sd      ra,24(sp)
     0x000000000000001c <+8>:   sd      s0,16(sp)
     0x0000000000000020 <+12>:  addi    s0,sp,32
     0x0000000000000024 <+16>:  mv      a5,a0
     0x0000000000000028 <+20>:  sw      a5,-20(s0)

  13            bsink = x * 2;
     0x000000000000002c <+24>:  lw      a5,-20(s0)
     0x0000000000000030 <+28>:  slliw   a5,a5,0x1
     0x0000000000000034 <+32>:  sext.w  a4,a5
     0x0000000000000038 <+36>:  sw      a4,256(zero) # 0x100 <bsink>

  14            return bsink;
     0x000000000000003c <+40>:  lw      a5,256(zero) # 0x100 <bsink>
     0x0000000000000040 <+44>:  sext.w  a5,a5

  15    }
     0x0000000000000044 <+48>:  mv      a0,a5
     0x0000000000000048 <+52>:  ld      ra,24(sp)
     0x000000000000004c <+56>:  ld      s0,16(sp)
     0x0000000000000050 <+60>:  addi    sp,sp,32
     0x0000000000000054 <+64>:  ret
  End of assembler dump.
  (gdb) disassemble /s target_func
  Dump of assembler code for function target_func:
     0x00000000000000a4 <+0>:   addi    sp,sp,-48
     0x00000000000000a8 <+4>:   sd      ra,40(sp)
     0x00000000000000ac <+8>:   sd      s0,32(sp)
     0x00000000000000b0 <+12>:  addi    s0,sp,48
     0x00000000000000b4 <+16>:  mv      a5,a0
     0x00000000000000b8 <+20>:  sw      a5,-36(s0)
     0x00000000000000bc <+24>:  lw      a5,-36(s0)
     0x00000000000000c0 <+28>:  addiw   a5,a5,1
     0x00000000000000c4 <+32>:  sw      a5,-20(s0)
     0x00000000000000c8 <+36>:  lw      a5,-20(s0)
     0x00000000000000cc <+40>:  addiw   a5,a5,2
     0x00000000000000d0 <+44>:  sw      a5,-24(s0)
     0x00000000000000d4 <+48>:  lw      a5,-24(s0)
     0x00000000000000d8 <+52>:  addiw   a5,a5,3
     0x00000000000000dc <+56>:  sw      a5,-28(s0)
     0x00000000000000e0 <+60>:  lw      a4,-28(s0)
     0x00000000000000e4 <+64>:  sw      a4,260(zero) # 0x104 <sink>
     0x00000000000000e8 <+68>:  lw      a5,-28(s0)
     0x00000000000000ec <+72>:  mv      a0,a5
     0x00000000000000f0 <+76>:  ld      ra,40(sp)
     0x00000000000000f4 <+80>:  ld      s0,32(sp)
     0x00000000000000f8 <+84>:  addi    sp,sp,48
     0x00000000000000fc <+88>:  ret
  End of assembler dump.
  (gdb)
  ```

  The problem is that `repro.elf` is linked with garbage collection.
  When function sections are garbage collected references to these
  sections are left as 0 in the `.debug_rnglists` section, here's part
  of the table from `repro.elf`:

  ```
  Contents of the .debug_rnglists section:


   Table at Offset: 0:
    Length:          0x1e
    DWARF version:   5
    Address size:    8
    Segment size:    0
    Offset entries:  0
      Offset   Begin    End
      0000000c 0000000000000014 0000000000000058
      00000016 0000000000000000 0000000000000990
      00000021 <End of list>
  ```

  Notice the entry at offset 0x1c starts at address 0, this is a
  garbage collected entry.

  Here's the rest of the `.debug_rnglists` table:

  ```
   Table at Offset: 0x22:
    Length:          0x13
    DWARF version:   5
    Address size:    8
    Segment size:    0
    Offset entries:  0
      Offset   Begin    End
      0000002e 0000000000000058 00000000000000a4
      00000038 <End of list>
   Table at Offset: 0x39:
    Length:          0x13
    DWARF version:   5
    Address size:    8
    Segment size:    0
    Offset entries:  0
      Offset   Begin    End
      00000045 00000000000000a4 0000000000000100
      0000004f <End of list>
  ```

  Notice that both of these ranges, the one at 0x2e and the one at
  0x45 both appear to sit within the garbage collected range at 0x16
  which runs from 0x0 to 0x990.

  The bug can be triggered by controlling the order in which GDB
  searches the `compunit_symtab` objects.  If we first disassemble
  something from the `compunit_symtab` containing the garbage
  collected function then this will be the first `compunit_symtab`
  that GDB searches for later look ups, and, as its range covers the
  addresses of other functions, that `compunit_symtab` will "claim"
  those addresses, even though that `compunit_symtab` doesn't actually
  have any line table entries for those addresses.

  If we avoid searching the problematic `compunit_symtab` first, and
  instead search the other `compunit_symtab` objects, then GDB will be
  able to find those in later searches as they will continue to be
  checked first.

  This is only really a problem for targets that allow code to be
  placed at, or near, address 0.  Garbage collection effectively moves
  the ranges of the deleted function(s) to start at 0.  On targets
  where address 0, and some space after that, is non-accessible, then
  usually the range of the garbage collected functions falls within
  this non-accessible range, as a consequence, this bug is a
  non-issue, there will never be overlap between legitimate, mapped
  code and the garbage collected ranges.

  But for targets where code can be mapped at, or near, address 0,
  there is the possibility of aliasing between deleted function ranges
  real functions.  If these two things come from different
  `compunit_symtab` objects them GDB will run into issues finding the
  correct `compunit_symtab`.

  An ideal solution for this would be to have the linker be smarter
  and fully discard ranges that correspond to sections that have been
  discarded, but I don't know how easy that would be to implement.
  Maybe we need to investigate strategies for dealing with this in
  GDB.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.