Add SHF_COMPRESSED support to readelf

This patch updates readelf to dump compression header with

readelf -S -W:

  [ 4] .debug_info PROGBITS  00000000 000038 00007d 00   C 0   0  1

readelf -t -W:

  [ 4] .debug_info
       PROGBITS        00000000 000038 00007d 00   0   0  1
       [00000800]: COMPRESSED
       ZLIB, 0000009d, 1

It also checks the compression header when decompressing the compressed
section.

	* 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.
This commit is contained in:
H.J. Lu
2015-04-05 09:20:02 -07:00
parent 317974f683
commit 77115a4a15
2 changed files with 82 additions and 6 deletions

View File

@ -1,3 +1,13 @@
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.
2015-04-02 H.J. Lu <hongjiu.lu@intel.com>
* configure: Regenerated.

View File

@ -5155,7 +5155,8 @@ get_elf_section_flags (bfd_vma sh_flags)
/* Generic. */
/* 18 */ { STRING_COMMA_LEN ("EXCLUDE") },
/* SPARC specific. */
/* 19 */ { STRING_COMMA_LEN ("ORDERED") }
/* 19 */ { STRING_COMMA_LEN ("ORDERED") },
/* 20 */ { STRING_COMMA_LEN ("COMPRESSED") }
};
if (do_section_details)
@ -5187,6 +5188,7 @@ get_elf_section_flags (bfd_vma sh_flags)
case SHF_GROUP: sindex = 8; break;
case SHF_TLS: sindex = 9; break;
case SHF_EXCLUDE: sindex = 18; break;
case SHF_COMPRESSED: sindex = 20; break;
default:
sindex = -1;
@ -5268,6 +5270,7 @@ get_elf_section_flags (bfd_vma sh_flags)
case SHF_GROUP: *p = 'G'; break;
case SHF_TLS: *p = 'T'; break;
case SHF_EXCLUDE: *p = 'E'; break;
case SHF_COMPRESSED: *p = 'C'; break;
default:
if ((elf_header.e_machine == EM_X86_64
@ -5355,6 +5358,27 @@ get_elf_section_flags (bfd_vma sh_flags)
return buff;
}
static unsigned int
get_compression_header (Elf_Internal_Chdr *chdr, unsigned char *buf)
{
if (is_32bit_elf)
{
Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) buf;
chdr->ch_type = BYTE_GET (echdr->ch_type);
chdr->ch_size = BYTE_GET (echdr->ch_size);
chdr->ch_addralign = BYTE_GET (echdr->ch_addralign);
return sizeof (*echdr);
}
else
{
Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) buf;
chdr->ch_type = BYTE_GET (echdr->ch_type);
chdr->ch_size = BYTE_GET (echdr->ch_size);
chdr->ch_addralign = BYTE_GET (echdr->ch_addralign);
return sizeof (*echdr);
}
}
static int
process_section_headers (FILE * file)
{
@ -5799,7 +5823,29 @@ process_section_headers (FILE * file)
}
if (do_section_details)
printf (" %s\n", get_elf_section_flags (section->sh_flags));
{
printf (" %s\n", get_elf_section_flags (section->sh_flags));
if ((section->sh_flags & SHF_COMPRESSED) != 0)
{
/* Minimum section size is 12 bytes for 32-bit compression
header + 12 bytes for compressed data header. */
unsigned char buf[24];
assert (sizeof (buf) >= sizeof (Elf64_External_Chdr));
if (get_data (&buf, (FILE *) file, section->sh_offset, 1,
sizeof (buf), _("compression header")))
{
Elf_Internal_Chdr chdr;
get_compression_header (&chdr, buf);
if (chdr.ch_type == ELFCOMPRESS_ZLIB)
printf (" ZLIB, ");
else
printf (_(" [<unknown>: 0x%x], "),
chdr.ch_type);
print_vma (chdr.ch_size, LONG_HEX);
printf (", %lu\n", (unsigned long) chdr.ch_addralign);
}
}
}
}
if (!do_section_details)
@ -12007,7 +12053,6 @@ uncompress_section_contents (unsigned char **buffer,
|| strm.avail_out != 0)
goto fail;
free (compressed_buffer);
*buffer = uncompressed_buffer;
*size = uncompressed_size;
return 1;
@ -12040,9 +12085,30 @@ load_specific_debug_section (enum dwarf_section_display_enum debug,
section->size = 0;
else
{
section->size = sec->sh_size;
if (uncompress_section_contents (&section->start, &section->size))
sec->sh_size = section->size;
unsigned char *start = section->start;
dwarf_size_type size = sec->sh_size;
if ((sec->sh_flags & SHF_COMPRESSED) != 0)
{
Elf_Internal_Chdr chdr;
unsigned int compression_header_size
= get_compression_header (&chdr, start);
if (chdr.ch_type != ELFCOMPRESS_ZLIB
|| chdr.ch_addralign != sec->sh_addralign)
return 0;
start += compression_header_size;
size -= compression_header_size;
}
if (uncompress_section_contents (&start, &size))
{
/* Free the compressed buffer, update the section buffer
and the section size if uncompress is successful. */
free (section->start);
section->start = start;
sec->sh_size = size;
}
section->size = size;
}
if (section->start == NULL)