readelf: Add -z decompression support
Compatible with GNU readelf, -z decompresses sections displayed by -x or -p. ELF Tool Chain ticket #555 https://sourceforge.net/p/elftoolchain/tickets/555/ Submitted by: Tiger Gao <tig@FreeBSDFoundation.org> Reviewed by: markj MFC after: 1 month Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D26909
This commit is contained in:
parent
8e8c5da47f
commit
e128bd0ff9
@ -24,7 +24,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $Id: readelf.1 3753 2019-06-28 01:13:13Z emaste $
|
.\" $Id: readelf.1 3753 2019-06-28 01:13:13Z emaste $
|
||||||
.\"
|
.\"
|
||||||
.Dd June 27, 2019
|
.Dd October 31, 2020
|
||||||
.Dt READELF 1
|
.Dt READELF 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -49,6 +49,7 @@
|
|||||||
.Fl -debug-dump Ns Op Ns = Ns Ar long-option-name , Ns ...
|
.Fl -debug-dump Ns Op Ns = Ns Ar long-option-name , Ns ...
|
||||||
.Oc
|
.Oc
|
||||||
.Op Fl x Ar section | Fl -hex-dump Ns = Ns Ar section
|
.Op Fl x Ar section | Fl -hex-dump Ns = Ns Ar section
|
||||||
|
.Op Fl z | Fl -decompress
|
||||||
.Op Fl A | Fl -arch-specific
|
.Op Fl A | Fl -arch-specific
|
||||||
.Op Fl D | Fl -use-dynamic
|
.Op Fl D | Fl -use-dynamic
|
||||||
.Op Fl H | Fl -help
|
.Op Fl H | Fl -help
|
||||||
@ -157,6 +158,13 @@ Display the contents of the specified section in hexadecimal.
|
|||||||
The argument
|
The argument
|
||||||
.Ar section
|
.Ar section
|
||||||
should be the name of a section or a numeric section index.
|
should be the name of a section or a numeric section index.
|
||||||
|
.It Fl z | Fl -decompress
|
||||||
|
Decompress contents of sections specified by
|
||||||
|
.Fl x
|
||||||
|
or
|
||||||
|
.Fl p
|
||||||
|
before displaying.
|
||||||
|
If the specified section is not compressed, it is displayed as is.
|
||||||
.It Fl A | Fl -arch-specific
|
.It Fl A | Fl -arch-specific
|
||||||
This option is accepted but is currently unimplemented.
|
This option is accepted but is currently unimplemented.
|
||||||
.It Fl D | Fl -use-dynamic
|
.It Fl D | Fl -use-dynamic
|
||||||
|
@ -40,12 +40,14 @@
|
|||||||
#include <libelftc.h>
|
#include <libelftc.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
#include <libcasper.h>
|
#include <libcasper.h>
|
||||||
#include <casper/cap_fileargs.h>
|
#include <casper/cap_fileargs.h>
|
||||||
@ -87,6 +89,7 @@ ELFTC_VCSID("$Id: readelf.c 3769 2019-06-29 15:15:02Z emaste $");
|
|||||||
#define RE_WW 0x00040000
|
#define RE_WW 0x00040000
|
||||||
#define RE_W 0x00080000
|
#define RE_W 0x00080000
|
||||||
#define RE_X 0x00100000
|
#define RE_X 0x00100000
|
||||||
|
#define RE_Z 0x00200000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dwarf dump options.
|
* dwarf dump options.
|
||||||
@ -189,6 +192,7 @@ static struct option longopts[] = {
|
|||||||
{"arch-specific", no_argument, NULL, 'A'},
|
{"arch-specific", no_argument, NULL, 'A'},
|
||||||
{"archive-index", no_argument, NULL, 'c'},
|
{"archive-index", no_argument, NULL, 'c'},
|
||||||
{"debug-dump", optional_argument, NULL, OPTION_DEBUG_DUMP},
|
{"debug-dump", optional_argument, NULL, OPTION_DEBUG_DUMP},
|
||||||
|
{"decompress", no_argument, 0, 'z'},
|
||||||
{"dynamic", no_argument, NULL, 'd'},
|
{"dynamic", no_argument, NULL, 'd'},
|
||||||
{"file-header", no_argument, NULL, 'h'},
|
{"file-header", no_argument, NULL, 'h'},
|
||||||
{"full-section-name", no_argument, NULL, 'N'},
|
{"full-section-name", no_argument, NULL, 'N'},
|
||||||
@ -6900,17 +6904,96 @@ get_symbol_value(struct readelf *re, int symtab, int i)
|
|||||||
return (sym.st_value);
|
return (sym.st_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decompress a data section if needed (using ZLIB).
|
||||||
|
* Returns true if sucessful, false otherwise.
|
||||||
|
*/
|
||||||
|
static bool decompress_section(struct section *s,
|
||||||
|
unsigned char *compressed_data_buffer, uint64_t compressed_size,
|
||||||
|
unsigned char **ret_buf, uint64_t *ret_sz)
|
||||||
|
{
|
||||||
|
GElf_Shdr sh;
|
||||||
|
|
||||||
|
if (gelf_getshdr(s->scn, &sh) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1));
|
||||||
|
|
||||||
|
if (sh.sh_flags & SHF_COMPRESSED) {
|
||||||
|
int ret;
|
||||||
|
GElf_Chdr chdr;
|
||||||
|
Elf64_Xword inflated_size;
|
||||||
|
unsigned char *uncompressed_data_buffer = NULL;
|
||||||
|
Elf64_Xword uncompressed_size;
|
||||||
|
z_stream strm;
|
||||||
|
|
||||||
|
if (gelf_getchdr(s->scn, &chdr) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "gelf_getchdr() failed: %s", elf_errmsg(-1));
|
||||||
|
if (chdr.ch_type != ELFCOMPRESS_ZLIB) {
|
||||||
|
warnx("unknown compression type: %d", chdr.ch_type);
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
inflated_size = 0;
|
||||||
|
uncompressed_size = chdr.ch_size;
|
||||||
|
uncompressed_data_buffer = malloc(uncompressed_size);
|
||||||
|
compressed_data_buffer += sizeof(chdr);
|
||||||
|
compressed_size -= sizeof(chdr);
|
||||||
|
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
strm.avail_in = compressed_size;
|
||||||
|
strm.avail_out = uncompressed_size;
|
||||||
|
ret = inflateInit(&strm);
|
||||||
|
|
||||||
|
if (ret != Z_OK)
|
||||||
|
goto fail;
|
||||||
|
/*
|
||||||
|
* The section can contain several compressed buffers,
|
||||||
|
* so decompress in a loop until all data is inflated.
|
||||||
|
*/
|
||||||
|
while (inflated_size < compressed_size) {
|
||||||
|
strm.next_in = compressed_data_buffer + inflated_size;
|
||||||
|
strm.next_out = uncompressed_data_buffer + inflated_size;
|
||||||
|
ret = inflate(&strm, Z_FINISH);
|
||||||
|
if (ret != Z_STREAM_END)
|
||||||
|
goto fail;
|
||||||
|
inflated_size = uncompressed_size - strm.avail_out;
|
||||||
|
ret = inflateReset(&strm);
|
||||||
|
if (ret != Z_OK)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (strm.avail_out != 0)
|
||||||
|
warnx("Warning: wrong info in compression header.");
|
||||||
|
ret = inflateEnd(&strm);
|
||||||
|
if (ret != Z_OK)
|
||||||
|
goto fail;
|
||||||
|
*ret_buf = uncompressed_data_buffer;
|
||||||
|
*ret_sz = uncompressed_size;
|
||||||
|
return (true);
|
||||||
|
fail:
|
||||||
|
inflateEnd(&strm);
|
||||||
|
if (strm.msg)
|
||||||
|
warnx("%s", strm.msg);
|
||||||
|
else
|
||||||
|
warnx("ZLIB error: %d", ret);
|
||||||
|
free(uncompressed_data_buffer);
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
hex_dump(struct readelf *re)
|
hex_dump(struct readelf *re)
|
||||||
{
|
{
|
||||||
struct section *s;
|
struct section *s;
|
||||||
Elf_Data *d;
|
Elf_Data *d;
|
||||||
uint8_t *buf;
|
uint8_t *buf, *new_buf;
|
||||||
size_t sz, nbytes;
|
size_t sz, nbytes;
|
||||||
uint64_t addr;
|
uint64_t addr;
|
||||||
int elferr, i, j;
|
int elferr, i, j;
|
||||||
|
|
||||||
for (i = 1; (size_t) i < re->shnum; i++) {
|
for (i = 1; (size_t) i < re->shnum; i++) {
|
||||||
|
new_buf = NULL;
|
||||||
s = &re->sl[i];
|
s = &re->sl[i];
|
||||||
if (find_dumpop(re, (size_t) i, s->name, HEX_DUMP, -1) == NULL)
|
if (find_dumpop(re, (size_t) i, s->name, HEX_DUMP, -1) == NULL)
|
||||||
continue;
|
continue;
|
||||||
@ -6932,6 +7015,11 @@ hex_dump(struct readelf *re)
|
|||||||
buf = d->d_buf;
|
buf = d->d_buf;
|
||||||
sz = d->d_size;
|
sz = d->d_size;
|
||||||
addr = s->addr;
|
addr = s->addr;
|
||||||
|
if (re->options & RE_Z) {
|
||||||
|
if (decompress_section(s, d->d_buf, d->d_size,
|
||||||
|
&new_buf, &sz))
|
||||||
|
buf = new_buf;
|
||||||
|
}
|
||||||
printf("\nHex dump of section '%s':\n", s->name);
|
printf("\nHex dump of section '%s':\n", s->name);
|
||||||
while (sz > 0) {
|
while (sz > 0) {
|
||||||
printf(" 0x%8.8jx ", (uintmax_t)addr);
|
printf(" 0x%8.8jx ", (uintmax_t)addr);
|
||||||
@ -6955,6 +7043,7 @@ hex_dump(struct readelf *re)
|
|||||||
addr += nbytes;
|
addr += nbytes;
|
||||||
sz -= nbytes;
|
sz -= nbytes;
|
||||||
}
|
}
|
||||||
|
free(new_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6963,11 +7052,13 @@ str_dump(struct readelf *re)
|
|||||||
{
|
{
|
||||||
struct section *s;
|
struct section *s;
|
||||||
Elf_Data *d;
|
Elf_Data *d;
|
||||||
unsigned char *start, *end, *buf_end;
|
unsigned char *start, *end, *buf_end, *new_buf;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
size_t sz;
|
||||||
int i, j, elferr, found;
|
int i, j, elferr, found;
|
||||||
|
|
||||||
for (i = 1; (size_t) i < re->shnum; i++) {
|
for (i = 1; (size_t) i < re->shnum; i++) {
|
||||||
|
new_buf = NULL;
|
||||||
s = &re->sl[i];
|
s = &re->sl[i];
|
||||||
if (find_dumpop(re, (size_t) i, s->name, STR_DUMP, -1) == NULL)
|
if (find_dumpop(re, (size_t) i, s->name, STR_DUMP, -1) == NULL)
|
||||||
continue;
|
continue;
|
||||||
@ -6986,9 +7077,15 @@ str_dump(struct readelf *re)
|
|||||||
s->name);
|
s->name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
buf_end = (unsigned char *) d->d_buf + d->d_size;
|
|
||||||
start = (unsigned char *) d->d_buf;
|
|
||||||
found = 0;
|
found = 0;
|
||||||
|
start = d->d_buf;
|
||||||
|
sz = d->d_size;
|
||||||
|
if (re->options & RE_Z) {
|
||||||
|
if (decompress_section(s, d->d_buf, d->d_size,
|
||||||
|
&new_buf, &sz))
|
||||||
|
start = new_buf;
|
||||||
|
}
|
||||||
|
buf_end = start + sz;
|
||||||
printf("\nString dump of section '%s':\n", s->name);
|
printf("\nString dump of section '%s':\n", s->name);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
while (start < buf_end && !isprint(*start))
|
while (start < buf_end && !isprint(*start))
|
||||||
@ -7009,6 +7106,7 @@ str_dump(struct readelf *re)
|
|||||||
break;
|
break;
|
||||||
start = end + 1;
|
start = end + 1;
|
||||||
}
|
}
|
||||||
|
free(new_buf);
|
||||||
if (!found)
|
if (!found)
|
||||||
printf(" No strings found in this section.");
|
printf(" No strings found in this section.");
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
@ -7634,6 +7732,7 @@ Usage: %s [options] file...\n\
|
|||||||
Display DWARF information.\n\
|
Display DWARF information.\n\
|
||||||
-x INDEX | --hex-dump=INDEX\n\
|
-x INDEX | --hex-dump=INDEX\n\
|
||||||
Display contents of a section as hexadecimal.\n\
|
Display contents of a section as hexadecimal.\n\
|
||||||
|
-z | --decompress Decompress the contents of a section before displaying it.\n\
|
||||||
-A | --arch-specific (accepted, but ignored)\n\
|
-A | --arch-specific (accepted, but ignored)\n\
|
||||||
-D | --use-dynamic Print the symbol table specified by the DT_SYMTAB\n\
|
-D | --use-dynamic Print the symbol table specified by the DT_SYMTAB\n\
|
||||||
entry in the \".dynamic\" section.\n\
|
entry in the \".dynamic\" section.\n\
|
||||||
@ -7668,7 +7767,7 @@ main(int argc, char **argv)
|
|||||||
memset(re, 0, sizeof(*re));
|
memset(re, 0, sizeof(*re));
|
||||||
STAILQ_INIT(&re->v_dumpop);
|
STAILQ_INIT(&re->v_dumpop);
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv, "AacDdegHhIi:lNnp:rSstuVvWw::x:",
|
while ((opt = getopt_long(argc, argv, "AacDdegHhIi:lNnp:rSstuVvWw::x:z",
|
||||||
longopts, NULL)) != -1) {
|
longopts, NULL)) != -1) {
|
||||||
switch(opt) {
|
switch(opt) {
|
||||||
case '?':
|
case '?':
|
||||||
@ -7765,6 +7864,9 @@ main(int argc, char **argv)
|
|||||||
add_dumpop(re, 0, optarg, HEX_DUMP,
|
add_dumpop(re, 0, optarg, HEX_DUMP,
|
||||||
DUMP_BY_NAME);
|
DUMP_BY_NAME);
|
||||||
break;
|
break;
|
||||||
|
case 'z':
|
||||||
|
re->options |= RE_Z;
|
||||||
|
break;
|
||||||
case OPTION_DEBUG_DUMP:
|
case OPTION_DEBUG_DUMP:
|
||||||
re->options |= RE_W;
|
re->options |= RE_W;
|
||||||
parse_dwarf_op_long(re, optarg);
|
parse_dwarf_op_long(re, optarg);
|
||||||
|
@ -10,7 +10,7 @@ READELFDIR= ${ELFTCDIR}/readelf
|
|||||||
PROG= readelf
|
PROG= readelf
|
||||||
SRCS= readelf.c
|
SRCS= readelf.c
|
||||||
|
|
||||||
LIBADD= dwarf elftc elf
|
LIBADD= dwarf elftc elf z
|
||||||
|
|
||||||
.if ${MK_CASPER} != "no"
|
.if ${MK_CASPER} != "no"
|
||||||
LIBADD+= casper
|
LIBADD+= casper
|
||||||
|
Loading…
Reference in New Issue
Block a user