]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commit
gdb: don't use .text as default entry point section
authorAndrew Burgess <aburgess@redhat.com>
Wed, 15 Apr 2026 09:43:31 +0000 (10:43 +0100)
committerAndrew Burgess <aburgess@redhat.com>
Fri, 17 Apr 2026 20:40:36 +0000 (21:40 +0100)
commitcd289df068e39683576f95907b5dd06ae3e4e254
tree395732bcafc5ff22a0e58c198525e345078efc73
parenteb0801fe571a581ce2dbd8492ad7b1166d7ffcaa
gdb: don't use .text as default entry point section

We got a Fedora GDB bug report that a user tried to debug an Appimage,
and GDB would reliably crash like this:

  (gdb) run
  Starting program: /tmp/build/gdb/testsuite/outputs/gdb.base/solib-bad-entry-addr/solib-bad-entry-addr
  ../../src/gdb/symfile.c:843: internal-error: sect_index_text not initialized
  A problem internal to GDB has been detected,
  further debugging may prove unreliable.
  ----- Backtrace -----
  ... etc ...

The specific AppImage being debugged can be found here, I've modified
the URL with a warning marker.  I make no claims about whether it is
safe to download the image, and running it is definitely at your own
risk.  If you wish to, delete the warning marker to download:

  https://github.com/Murmele/Gittyup/<RUN AT YOUR OWN RISK>/releases/download/gittyup_v1.4.0/Gittyup-1.4.0-x86_64.AppImage

At the point of the above crash GDB's stack is:

  #9  0x000000000190c6ed in internal_error_loc (file=0x1e4a94e "../../src/gdb/symfile.c", line=838, fmt=0x1e4aa50 "sect_index_text not initialized") at ../../src/gdbsupport/errors.cc:57
  #10 0x0000000000f5f5ac in init_entry_point_info (objfile=0x5a98e80) at ../../src/gdb/symfile.c:838
  #11 0x0000000000f5f943 in syms_from_objfile (objfile=0x5a98e80, addrs=0x7ffd78728490, add_flags=...) at ../../src/gdb/symfile.c:962
  #12 0x0000000000f5fe6d in symbol_file_add_with_addrs (abfd=..., name=0x3e76e50 "/tmp/.mount_GittyujmIBkD/usr/bin/../../home/runner/work/Gittyup/Qt/5.15.2/gcc_64/lib/./libicudata.so.56", add_flags=..., addrs=0x7ffd78728490, flags=..., parent=0x0) at ../../src/gdb/symfile.c:1071
  #13 0x0000000000f601aa in symbol_file_add_from_bfd (abfd=..., name=0x3e76e50 "/tmp/.mount_GittyujmIBkD/usr/bin/../../home/runner/work/Gittyup/Qt/5.15.2/gcc_64/lib/./libicudata.so.56", add_flags=..., addrs=0x7ffd78728490, flags=..., parent=0x0) at ../../src/gdb/symfile.c:1145
  #14 0x0000000000f0f2ad in solib_read_symbols (so=..., flags=...) at ../../src/gdb/solib.c:627
  #15 0x0000000000f10263 in solib_add (pattern=0x0, from_tty=0, readsyms=1) at ../../src/gdb/solib.c:960

From this we can see GDB is trying to add the shared library:

  /tmp/.mount_GittyujmIBkD/usr/bin/../../home/runner/work/Gittyup/Qt/5.15.2/gcc_64/lib/./libicudata.so.56

The internal error is triggered from these lines in
init_entry_point_info:

  if (!found)
    ei->the_bfd_section_index = SECT_OFF_TEXT (objfile);

Where SECT_OFF_TEXT is:

  #define SECT_OFF_TEXT(objfile) \
     ((objfile->sect_index_text == -1) \
      ? (internal_error (_("sect_index_text not initialized")), -1) \
      : objfile->sect_index_text)

So we can see that objfile::sect_index_text is -1, which leads to the
internal error.

Looking at the 'readelf -Wa ...' output for the shared library in
question we see this:

  ELF Header:
    Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
    Class:                             ELF64
    Data:                              2's complement, little endian
    Version:                           1 (current)
    OS/ABI:                            UNIX - System V
    ABI Version:                       0
    Type:                              DYN (Shared object file)
    Machine:                           Advanced Micro Devices X86-64
    Version:                           0x1
    Entry point address:               0x2d7
    Start of program headers:          25051136 (bytes into file)
    Start of section headers:          25047552 (bytes into file)
    Flags:                             0x0
    Size of this header:               64 (bytes)
    Size of program headers:           56 (bytes)
    Number of program headers:         7
    Size of section headers:           64 (bytes)
    Number of section headers:         11
    Section header string table index: 7

  Section Headers:
    [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
    [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
    [ 1] .note.gnu.build-id NOTE            0000000000000190 000190 000024 00   A  0   0  4
    [ 2] .gnu.hash         GNU_HASH        00000000000001b8 0001b8 000034 00   A  3   0  8
    [ 3] .dynsym           DYNSYM          00000000000001f0 0001f0 000090 18   A 10   2  8
    [ 4] .rodata           PROGBITS        00000000000002e0 0002e0 17e27d0 00   A  0   0 16
    [ 5] .eh_frame         PROGBITS        00000000017e2ab0 17e2ab0 000000 00   A  0   0  8
    [ 6] .dynamic          DYNAMIC         00000000019e2f10 17e2f10 0000f0 10  WA 10   0  8
    [ 7] .shstrtab         STRTAB          0000000000000000 17e3000 000063 00      0   0  1
    [ 8] .symtab           SYMTAB          0000000000000000 17e3068 000150 18      9  10  8
    [ 9] .strtab           STRTAB          0000000000000000 17e31b8 000044 00      0   0  1
    [10] .dynstr           STRTAB          00000000019e3188 17e4188 000420 00   A  0   0  8
  Key to Flags:
    W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
    L (link order), O (extra OS processing required), G (group), T (TLS),
    C (compressed), x (unknown), o (OS specific), E (exclude),
    D (mbind), l (large), p (processor specific)

  There are no section groups in this file.

  Program Headers:
    Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
    LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x17e2ab0 0x17e2ab0 R   0x200000
    GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
    NOTE           0x000190 0x0000000000000190 0x0000000000000190 0x000024 0x000024 R   0x4
    LOAD           0x17e2f10 0x00000000019e2f10 0x00000000019e2f10 0x0000f0 0x0000f0 RW  0x200000
    DYNAMIC        0x17e2f10 0x00000000019e2f10 0x00000000019e2f10 0x0000f0 0x0000f0 RW  0x8
    GNU_RELRO      0x17e2f10 0x00000000019e2f10 0x00000000019e2f10 0x0000f0 0x0000f0 R   0x1
    LOAD           0x17e4000 0x00000000019e3000 0x00000000019e3000 0x0005a8 0x0005a8 RW  0x1000

Things to note here are:

  1. There really is no .text section, or any executable sections,

  2. there are 3 LOAD segments.  This will be important later, and

  3. the "Entry point address" is outside all sections, and is
     non-zero.

Next we can investigate where objfile::sect_index_text is set to
something other than -1.  Starting in init_objfile_sect_indices, if
the objfile has a ".text" section then sect_index_text can be set.
This case clearly doesn't apply.

Next symfile_find_segment_sections is called.  This tries to match a
common case where we have either 1 or 2 LOAD segments, and assumes a
default distribution of sections to segments.  However, we have 3 LOAD
segments, so these lines:

  if (data->segments.size () != 1 && data->segments.size () != 2)
    return;

result in an early return from symfile_find_segment_sections without
sect_index_text being set.

Back in init_objfile_sect_indices, if no sections have an offset then
we set any currently unset sect_index_* values, including
sect_index_text, to point at section 0.  However, in our case the
objfile is a relocatable shared library, so the sections will have an
offset, and so this final fallback case doesn't apply.

The result is that init_objfile_sect_indices never sets
sect_index_text.  This worries me a little as
init_objfile_sect_indices contains this comment:

  /* This is where things get really weird...  We MUST have valid
     indices for the various sect_index_* members or gdb will abort.
     So if for example, there is no ".text" section, we have to
     accommodate that.  First, check for a file with the standard
     one or two segments.  */

Notice the emphasis on MUST in that comment, and indeed, we exit this
function without setting sect_index_text, and GDB does indeed abort.
The comment seems to imply that the following code is going to try to
figure out a suitable stand-in sect_index_text for when there is no
".text" section, but clearly I've run into a case that isn't covered.

All of this code relating to setting sect_index_text was introduced in
commit:

  commit 31d99776c73d6fca13163da59c852b0fa99f89b8
  Date:   Mon Jun 18 15:46:38 2007 +0000

Which unfortunately is from a time where we didn't write useful commit
messages, so to understand the commit you need to go read the mailing
list archive, but they don't offer much more insight:

  https://sourceware.org/pipermail/gdb-patches/2007-May/050527.html

Clearly the comment in init_objfile_sect_indices would suggest that
the fix here is to figure out some "fake" value for sect_index_text,
and that would certainly avoid the problem here.  But, at least for
this problem, I think there's maybe a better solution.

The original internal error is triggered by a use of SECT_OFF_TEXT in
init_entry_point_info.  We have an entry point address, we try to find
the section index for the section containing the entry point, and
failing that, we assume the entry point is in the text section.  This
fall-back assumption means that, if the text section has an offset
applied, then the entry point will also have that same offset
applied.  But it's not clear to me why picking the text section is
going to be any more valid than any other section, especially in a
case like this where we don't even have a text section, so the
sect_index_text might itself point to some other arbitrary section.

Earlier in init_entry_point_info we already have a fall-back case
where we set entry_info::entry_point_p to false to indicate that the
objfile has no entry point, so this is always a possibility.  So I
wondered about writing something like:

  if (!found)
    {
      if (objfile->sect_index_text != -1)
ei->the_bfd_section_index = SECT_OFF_TEXT (objfile);
      else
        ei->entry_point_p = false;
    }

If we have no text section index then we just claim the objfile has no
entry point.  But I didn't like this for two reasons, first, the
comment back in init_objfile_sect_indices saying that the index should
be set, this seems to indicate that we should not be making decisions
later within GDB based on whether the index is set or not.

And second, using the text section as a fall back, when the entry
address is outside every section, just seems off.  So I wondered, why
not just reject the entry point completely in this case?  Which is how
I ended up with:

  if (!found)
    ei->entry_point_p = false;

With this patch in place I was able to start debugging the AppImage
linked above.

I created a simple test case which reproduces this issue.  It's a
little contrived because it has to hit all the points required to
trigger this bug:

  1. No .text section,

  2. more than 2 LOAD segments, and

  3. entry address outside every section.

I have no idea what caused the original shared library to take on
these characteristics, it might even be a tool issue building the
original shared library.  I haven't investigated this, as I don't
think it really matters, GDB shouldn't be crashing just because the
incoming objects are a little weird.

I've attached a link to the Fedora bug in the 'Bug:' tag, but it's a
little confusing.  An automated system has merged together two bug
reports.  As such the overall bug report linked too is for a
completely different issue, only comments 21, 22, 23, and 24 relate to
the bug being fixed here.

Bug: https://bugzilla.redhat.com/show_bug.cgi?id=2366461#c21

Approved-By: Tom Tromey <tom@tromey.com>
gdb/symfile.c
gdb/testsuite/gdb.base/solib-bad-entry-addr-lib.s [new file with mode: 0644]
gdb/testsuite/gdb.base/solib-bad-entry-addr.c [new file with mode: 0644]
gdb/testsuite/gdb.base/solib-bad-entry-addr.exp [new file with mode: 0644]