From 77115a4a156052eb1542d16041115cc347da4a07 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sun, 5 Apr 2015 09:20:02 -0700 Subject: 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. --- binutils/ChangeLog | 10 +++++++ binutils/readelf.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 82 insertions(+), 6 deletions(-) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 023bd98..230a58d 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,13 @@ +2015-04-05 H.J. Lu + + * 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 * configure: Regenerated. diff --git a/binutils/readelf.c b/binutils/readelf.c index 17d4fd4..fea372f 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -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 (_(" [: 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 (§ion->start, §ion->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) -- cgit v1.1