Bug 18218 - bad handling of .debug_str_offsets section
Summary: bad handling of .debug_str_offsets section
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: binutils (show other bugs)
Version: 2.26
: P2 normal
Target Milestone: 2.26
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-04-08 20:10 UTC by dje
Modified: 2015-04-13 19:53 UTC (History)
1 user (show)

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


Attachments
testcase (1.15 KB, text/plain)
2015-04-08 20:16 UTC, dje
Details
testcase #2, .c file (225 bytes, text/x-csrc)
2015-04-08 21:46 UTC, dje
Details
testcase #2, .s file (1.44 KB, text/plain)
2015-04-08 21:46 UTC, dje
Details
testcase #2, .dwo file (752 bytes, application/x-object)
2015-04-08 21:47 UTC, dje
Details
A patch (270 bytes, patch)
2015-04-08 23:55 UTC, H.J. Lu
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description dje 2015-04-08 20:10:50 UTC
Problem:

readelf -w readelf-str-offsets.dwo
->
    <c>   DW_AT_producer    : (indexed string: 0x5): <no .debug_str_offsets.dwo section>

However, this works:

readelf -wi readelf-str-offsets.dwo
->
    <c>   DW_AT_producer    : (indexed string: 0x5): GNU C ...

The appended testcase, readelf-str-offsets-bug.s, was created by compiling
this file:

---snip---
/* We need enough entries in .debug_str_offsets so that                                                                                                          
   gas/write.c:compress_debug will compress it.                                                                                                                  
   Threshold is 32 bytes.  */

int var1;
int var2;
int var3;
int var4;

int
main ()
{
  return 0;
}
---snip---

thusly:

gcc -m64 -gdwarf-4 -gsplit-dwarf -c readelf-str-offsets-bug.c -save-temps -Wa,--compress-debug-sections

and then manually editing the .s file so that .debug_str_offsets appears before .debug_info, and then recompiling thusly:

gcc -m64 -gdwarf-4 -gsplit-dwarf -c readelf-str-offsets-bug.s -Wa,--compress-debug-sections

[The system where I tripped over this bug just happened to put .debug_str_offsets ahead of .debug_info.]

The bug occurs because .debug_str_offsets is loaded and decompressed twice:
1) to display .zdebug_str_offsets itself
2) to display .zdebug_info

The first time through we hit this code in readelf.c:load_specific_debug_section

  if (section->start == NULL)
    section->size = 0;
  else
    {
      section->size = sec->sh_size;
      if (uncompress_section_contents (&section->start, &section->size))
        sec->sh_size = section->size;   <<<<<<<<<<<<<
    }

Note that we've set sec->sh_size to the new, uncompressed value.

Then we free the section here in display_debug_section:

            if (secondary || (i != info && i != abbrev))
              free_debug_section ((enum dwarf_section_display_enum) i);

Then we'll go to display .debug_info.
But because we no longer have .debug_str_offsets we reload it.
However, it's sh_size field is now bad - it no longer contains the compressed size.  So we reload the section with the newer larger size thinking all of that is compressed data, the read fails, and the section is left as marked as unloaded.

We then get here in fetch_indexed_string:

  if (index_section->start == NULL)
    return (dwo ? _("<no .debug_str_offsets.dwo section>")
                : _("<no .debug_str_offsets section>"));

---

N.B. The above written prior to commit 77115a4a.

2015-04-05  H.J. Lu  <hongjiu.lu@intel.com>

        * readelf.c (get_elf_section_flags): Support SHF_COMPRESSED.
        (get_compression_header): New.
        (process_section_headers): Dump compression header if needed.
        (uncompress_section_contents): Don't free compressed_buffer here.
        (load_specific_debug_section): Free the compressed buffer, update
        the section buffer and the section size if uncompress is
        successful.

There is still a bug though.
Now I'm getting:

readelf: Warning: DW_FORM_GNU_str_index indirect offset too big: 76207962
and
    <c>   DW_AT_producer    : (indexed string: 0x5): <indirect index offset is too big>

It seems that when fetch_indexed_string is called, the contents are compressed.

(gdb) p *index_section
$46 = {
  uncompressed_name = 0x47ffab ".debug_str_offsets.dwo",
  compressed_name = 0x47ffc2 ".zdebug_str_offsets.dwo",
  name = 0x47ffc2 ".zdebug_str_offsets.dwo",
  start = 0x68f430 "ZLIB", <<<<<<<<<<<<<<<<<
  address = 0,
  size = 32,
  abbrev_sec = abbrev,
  user_data = 0x0
}
Comment 1 dje 2015-04-08 20:16:49 UTC
Created attachment 8230 [details]
testcase
Comment 2 H.J. Lu 2015-04-08 20:45:30 UTC
Please provide readelf-str-offsets.dwo.
Comment 3 dje 2015-04-08 21:45:19 UTC
Bleah.  I needed to make .debug_str_offsets.dwo larger so that it actually would get compressed.

gcc -m64 -gdwarf-4 -gsplit-dwarf -c readelf-str-offsets-bug.c -Wa,--compress-debug-sections --save-temps

<
edit readelf-str-offsets-bug.s and move .debug_str_offsets.dwo ahead of .debug_info.
This might no longer be necessary, but it's useful to exercise the original bug.
>

gcc -m64 -gdwarf-4 -gsplit-dwarf -c readelf-str-offsets-bug.s -Wa,--compress-debug-sections
readelf -w readelf-str-offsets-bug.dwo
Comment 4 dje 2015-04-08 21:46:16 UTC
Created attachment 8231 [details]
testcase #2, .c file
Comment 5 dje 2015-04-08 21:46:51 UTC
Created attachment 8232 [details]
testcase #2, .s file
Comment 6 dje 2015-04-08 21:47:34 UTC
Created attachment 8233 [details]
testcase #2, .dwo file
Comment 7 dje 2015-04-08 21:47:56 UTC
testcase uploaded
Comment 8 H.J. Lu 2015-04-08 23:55:00 UTC
Created attachment 8234 [details]
A patch

This works on the testcase.  But it may not be correct.
Comment 9 H.J. Lu 2015-04-09 14:03:16 UTC
A patch is posted at

https://sourceware.org/ml/binutils/2015-04/msg00155.html
Comment 10 cvs-commit@gcc.gnu.org 2015-04-13 19:52:44 UTC
The master branch has been updated by Doug Evans <devans@sourceware.org>:

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

commit 0d2a7a932244fab27d6c4ce211ea8f7708a1a9cc
Author: Doug Evans <dje@google.com>
Date:   Mon Apr 13 12:50:17 2015 -0700

    Fix reading of .debug_str_offsets{,.dwo} twice.
    
    	PR binutils/18218
    	* readelf.c (printable_section_name): Constify sec argument.
    	(apply_relocations): Ditto.  New arg "size".  All callers updated.
    	(load_specific_debug_section): Constify sec argument.
    	Remove side-effect of modifying sec->sh_size.
Comment 11 dje 2015-04-13 19:53:25 UTC
Fix committed.