Re: [PATCH] [PR 25678] gdb crashes with "internal-error: sect_index_text not initialized" when .text

mlimber
2020-05-19T14:36:43Z

On Mon, May 18, 2020 at 5:44 PM Simon Marchi <simark@simark.ca> wrote:

> If you can upload it somewhere, it wouldn't hurt. I'm also trying to build
> icu from the same release.
>

Here are my ICU libs (built with gcc 4.9 for x64):

https://www.dropbox.com/sh/1esshbzshll0hzq/AACBgQgwuSEM_pYQ0HYG_ybXa

> Right now I'm trying to make some sense of the
> `symfile_find_segment_sections`
> function here:
>
>
> https://github.com/bminor/binutils-gdb/blob/966dc1a27c55ccb298cb8c7c41c9cc2985cc321a/gdb/symfile.c#L3701
>
> I suspect it's buggy, and "hides" the bug when using some shared libraries
> (including the one I build myself) which would explain why we see it with
> some
> libraries that are missing a .text section and not others.
>
> When called for a library that has no .text section, if that library has
> two
> segments (which is the case of the library I created), then that function
> will
> initialize objfile::sect_index_text to 0 (or some other value that
> insinuates
> that there is a .text section). That sounds wrong to me: if the library
> has no
> .text section, it would be better to leave sect_index_text to -1, and make
> sure
> the rest of the code can cope with that. If I remove
> `symfile_find_segment_sections`
> completely, sect_index_text stays -1 for my library and I hit the
> assertion. I then
> believe that the correct way forward would be to update the dwarf2/read.c
> code to
> deal with a .text section not present. Normally, if there's no .text
> section, there
> should be no debug info describing code stuff (only data stuff), so it
> shouldn't be
> necessary to use sect_index_text.
>
> The library attached to the bug (libtestcase.so) has the particularity of
> having
> 3 segments. So `symfile_find_segment_sections` is skipped,
> sect_index_text stays
> -1, and we see the assertion.
>

I have skimmed that code, but we're beyond my ken here. The things I
observe in that code are:

1. This only acts on files with 1 or 2 segments. (It gets skipped for
libtestcase.so as you say.)

2. If the segment info is 1 or 2, it sets two segment indices to refer to
this one segment. Perhaps that's legit (I'm a naif when it comes to ELF
details), but it struck me as odd.

3. Line 300, where this function is called, has this curious 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
accomodate that. First, check for a file with the standard
one or two segments. */

> So I'm curious, in your libicudata.so library, how many segments there
> are. That
> can be checked with:
>
> $ readelf -l libicudata.so.52 | grep LOAD
>

I have two load segments:

readelf -l libicudata.so

Elf file type is DYN (Shared object file)
Entry point 0x2b6
There are 6 program headers, starting at offset 64

Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x000000000166a940 0x000000000166a940 R 200000
LOAD 0x000000000166af30 0x000000000186af30 0x000000000186af30
0x00000000000000d0 0x00000000000000d0 RW 200000
DYNAMIC 0x000000000166af30 0x000000000186af30 0x000000000186af30
0x00000000000000d0 0x00000000000000d0 RW 8
NOTE 0x0000000000000190 0x0000000000000190 0x0000000000000190
0x0000000000000024 0x0000000000000024 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x000000000166af30 0x000000000186af30 0x000000000186af30
0x00000000000000d0 0x00000000000000d0 R 1

I note that there is an entry point specified on the second line of output,
which is curious to me since there is no code in this library.

Perhaps if we forced an extra load segment in this .so, it would produce
different results due to skipping the function cited above.

> If the libicudata.so.52 is really the problematic one, I'm a bit surprised
> that you
> don't always see the problem when debugging a program that uses it.
>

I'm also not sure why it sometimes happens and sometimes doesn't. Could it
be something with how or when it is loaded -- say, in a certain sequence or
via a manual dlopen() instead of via dynamic linking info?

M