Changeset View
Standalone View
contrib/elftoolchain/readelf/readelf.c
Show First 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
#define RE_SS 0x00002000 | #define RE_SS 0x00002000 | ||||
#define RE_S 0x00004000 | #define RE_S 0x00004000 | ||||
#define RE_T 0x00008000 | #define RE_T 0x00008000 | ||||
#define RE_U 0x00010000 | #define RE_U 0x00010000 | ||||
#define RE_VV 0x00020000 | #define RE_VV 0x00020000 | ||||
#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. | ||||
*/ | */ | ||||
#define DW_A 0x00000001 | #define DW_A 0x00000001 | ||||
#define DW_FF 0x00000002 | #define DW_FF 0x00000002 | ||||
#define DW_F 0x00000004 | #define DW_F 0x00000004 | ||||
#define DW_I 0x00000008 | #define DW_I 0x00000008 | ||||
▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | static struct option longopts[] = { | ||||
{"string-dump", required_argument, NULL, 'p'}, | {"string-dump", required_argument, NULL, 'p'}, | ||||
{"symbols", no_argument, NULL, 's'}, | {"symbols", no_argument, NULL, 's'}, | ||||
{"syms", no_argument, NULL, 's'}, | {"syms", no_argument, NULL, 's'}, | ||||
{"unwind", no_argument, NULL, 'u'}, | {"unwind", no_argument, NULL, 'u'}, | ||||
{"use-dynamic", no_argument, NULL, 'D'}, | {"use-dynamic", no_argument, NULL, 'D'}, | ||||
{"version-info", no_argument, 0, 'V'}, | {"version-info", no_argument, 0, 'V'}, | ||||
{"version", no_argument, 0, 'v'}, | {"version", no_argument, 0, 'v'}, | ||||
{"wide", no_argument, 0, 'W'}, | {"wide", no_argument, 0, 'W'}, | ||||
{"decompress", no_argument, 0, 'z'}, | |||||
emaste: in contrast to the comment above these were already sorted by long option name, so this one… | |||||
{NULL, 0, NULL, 0} | {NULL, 0, NULL, 0} | ||||
}; | }; | ||||
struct eflags_desc { | struct eflags_desc { | ||||
uint64_t flag; | uint64_t flag; | ||||
const char *desc; | const char *desc; | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 2,339 Lines • ▼ Show 20 Lines | #define BUF_SZ 256 | ||||
return (buf); | return (buf); | ||||
} | } | ||||
static void | static void | ||||
dump_shdr(struct readelf *re) | dump_shdr(struct readelf *re) | ||||
{ | { | ||||
struct section *s; | struct section *s; | ||||
GElf_Chdr chdr; | |||||
int i; | int i; | ||||
#define S_HDR "[Nr] Name", "Type", "Addr", "Off", "Size", "ES", \ | #define S_HDR "[Nr] Name", "Type", "Addr", "Off", "Size", "ES", \ | ||||
"Flg", "Lk", "Inf", "Al" | "Flg", "Lk", "Inf", "Al" | ||||
#define S_HDRL "[Nr] Name", "Type", "Address", "Offset", "Size", \ | #define S_HDRL "[Nr] Name", "Type", "Address", "Offset", "Size", \ | ||||
"EntSize", "Flags", "Link", "Info", "Align" | "EntSize", "Flags", "Link", "Info", "Align" | ||||
#define ST_HDR "[Nr] Name", "Type", "Addr", "Off", "Size", "ES", \ | #define ST_HDR "[Nr] Name", "Type", "Addr", "Off", "Size", "ES", \ | ||||
"Lk", "Inf", "Al", "Flags" | "Lk", "Inf", "Al", "Flags" | ||||
#define ST_HDRL "[Nr] Name", "Type", "Address", "Offset", "Link", \ | #define ST_HDRL "[Nr] Name", "Type", "Address", "Offset", "Link", \ | ||||
"Size", "EntSize", "Info", "Align", "Flags" | "Size", "EntSize", "Info", "Align", "Flags" | ||||
#define S_CT i, s->name, section_type(re->ehdr.e_machine, s->type), \ | #define S_CT i, s->name, section_type(re->ehdr.e_machine, s->type), \ | ||||
(uintmax_t)s->addr, (uintmax_t)s->off, (uintmax_t)s->sz,\ | (uintmax_t)s->addr, (uintmax_t)s->off, (uintmax_t)s->sz,\ | ||||
(uintmax_t)s->entsize, section_flags(re, s), \ | (uintmax_t)s->entsize, section_flags(re, s), \ | ||||
s->link, s->info, (uintmax_t)s->align | s->link, s->info, (uintmax_t)s->align | ||||
#define ST_CT i, s->name, section_type(re->ehdr.e_machine, s->type), \ | #define ST_CT i, s->name, section_type(re->ehdr.e_machine, s->type), \ | ||||
(uintmax_t)s->addr, (uintmax_t)s->off, (uintmax_t)s->sz,\ | (uintmax_t)s->addr, (uintmax_t)s->off, (uintmax_t)s->sz,\ | ||||
(uintmax_t)s->entsize, s->link, s->info, \ | (uintmax_t)s->entsize, s->link, s->info, \ | ||||
(uintmax_t)s->align, section_flags(re, s) | (uintmax_t)s->align, section_flags(re, s) | ||||
#define ST_CTL i, s->name, section_type(re->ehdr.e_machine, s->type), \ | #define ST_CTL i, s->name, section_type(re->ehdr.e_machine, s->type), \ | ||||
(uintmax_t)s->addr, (uintmax_t)s->off, s->link, \ | (uintmax_t)s->addr, (uintmax_t)s->off, s->link, \ | ||||
(uintmax_t)s->sz, (uintmax_t)s->entsize, s->info, \ | (uintmax_t)s->sz, (uintmax_t)s->entsize, s->info, \ | ||||
(uintmax_t)s->align, section_flags(re, s) | (uintmax_t)s->align, section_flags(re, s) | ||||
#define SZ_CT i, s->name, section_type(re->ehdr.e_machine, s->type), \ | |||||
(uintmax_t)s->addr, (uintmax_t)s->off, s->link, \ | |||||
(uintmax_t)s->sz, (uintmax_t)s->entsize, s->info, \ | |||||
(uintmax_t)s->align, section_flags(re, s) | |||||
if (re->shnum == 0) { | if (re->shnum == 0) { | ||||
printf("\nThere are no sections in this file.\n"); | printf("\nThere are no sections in this file.\n"); | ||||
return; | return; | ||||
} | } | ||||
printf("There are %ju section headers, starting at offset 0x%jx:\n", | printf("There are %ju section headers, starting at offset 0x%jx:\n", | ||||
(uintmax_t)re->shnum, (uintmax_t)re->ehdr.e_shoff); | (uintmax_t)re->shnum, (uintmax_t)re->ehdr.e_shoff); | ||||
printf("\nSection Headers:\n"); | printf("\nSection Headers:\n"); | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (re->ec == ELFCLASS32) { | ||||
printf(" [%2d] %s\n %-15.15s %16.16jx" | printf(" [%2d] %s\n %-15.15s %16.16jx" | ||||
" %16.16jx %u\n %16.16jx %16.16jx" | " %16.16jx %u\n %16.16jx %16.16jx" | ||||
" %-16u %ju\n %s\n", ST_CTL); | " %-16u %ju\n %s\n", ST_CTL); | ||||
else | else | ||||
printf(" [%2d] %-17.17s %-15.15s %16.16jx" | printf(" [%2d] %-17.17s %-15.15s %16.16jx" | ||||
" %8.8jx\n %16.16jx %16.16jx " | " %8.8jx\n %16.16jx %16.16jx " | ||||
"%3s %2u %3u %ju\n", S_CT); | "%3s %2u %3u %ju\n", S_CT); | ||||
} | } | ||||
if (re->options & RE_Z) { | |||||
if (gelf_getchdr(s, &chdr) != NULL) { | |||||
if (chdr.ch_type == ELFCOMPRESS_ZLIB) | |||||
printf(" [ELF ZLIB (1) %8.8jx %lu]\n", | |||||
(unsigned int) chdr.ch_size, | |||||
(unsigned long) chdr.ch_addralign); | |||||
else | |||||
printf(" [Unknown: %x %8.8jx %lu]\n", | |||||
chdr.ch_type, | |||||
chdr.ch_size, | |||||
(unsigned long) chdr.ch_addralign); | |||||
} else { | |||||
printf(" [Bad compressed section header.]\n") | |||||
} | } | ||||
} | |||||
} | |||||
if ((re->options & RE_T) == 0) | if ((re->options & RE_T) == 0) | ||||
printf("Key to Flags:\n W (write), A (alloc)," | printf("Key to Flags:\n W (write), A (alloc)," | ||||
" X (execute), M (merge), S (strings)\n" | " X (execute), M (merge), S (strings)\n" | ||||
" I (info), L (link order), G (group), x (unknown)\n" | " I (info), L (link order), G (group), x (unknown)\n" | ||||
" O (extra OS processing required)" | " O (extra OS processing required)" | ||||
" o (OS specific), p (processor specific)\n"); | " o (OS specific), p (processor specific)\n"); | ||||
#undef S_HDR | #undef S_HDR | ||||
▲ Show 20 Lines • Show All 4,171 Lines • ▼ Show 20 Lines | get_symbol_value(struct readelf *re, int symtab, int i) | ||||
return (sym.st_value); | return (sym.st_value); | ||||
} | } | ||||
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; | ||||
Done Inline Actions{ goes on next line readelf.c is trickier to deal with using clang-format because much of the existing code is non-compliant. Clang has a tool for formatting just a patch: http://clang.llvm.org/docs/ClangFormat.html#script-for-patch-reformatting emaste: `{` goes on next line
readelf.c is trickier to deal with using clang-format because much of… | |||||
uint8_t *buf; | uint8_t *buf; | ||||
size_t sz, nbytes; | size_t sz, nbytes; | ||||
uint64_t addr; | uint64_t addr; | ||||
int elferr, i, j; | int elferr, i, j; | ||||
Done Inline Actionsdoes not need wrapping emaste: does not need wrapping | |||||
for (i = 1; (size_t) i < re->shnum; i++) { | for (i = 1; (size_t) i < re->shnum; i++) { | ||||
Done Inline Actionsextra blank line emaste: extra blank line | |||||
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; | ||||
(void) elf_errno(); | (void) elf_errno(); | ||||
if ((d = elf_getdata(s->scn, NULL)) == NULL && | if ((d = elf_getdata(s->scn, NULL)) == NULL && | ||||
(d = elf_rawdata(s->scn, NULL)) == NULL) { | (d = elf_rawdata(s->scn, NULL)) == NULL) { | ||||
elferr = elf_errno(); | elferr = elf_errno(); | ||||
if (elferr != 0) | if (elferr != 0) | ||||
warnx("elf_getdata failed: %s", | warnx("elf_getdata failed: %s", | ||||
elf_errmsg(elferr)); | elf_errmsg(elferr)); | ||||
continue; | continue; | ||||
} | } | ||||
(void) elf_errno(); | (void) elf_errno(); | ||||
Done Inline Actionsindentation emaste: indentation | |||||
Done Inline ActionsWhy do we goto fail here but call errx() in the error case immediately above? markj: Why do we `goto fail` here but call `errx()` in the error case immediately above? | |||||
Done Inline ActionsNow that I looked at it, it makes more sense to warn the user that compression type is not supported. Would that be a reasonable way to address this? tig_freebsdfoundation.org: Now that I looked at it, it makes more sense to warn the user that compression type is not… | |||||
Done Inline ActionsSomething like "unknown compression type: %d"? Or perhaps I don't understand your question. markj: Something like "unknown compression type: %d"? Or perhaps I don't understand your question. | |||||
Done Inline ActionsThat makes sense. I'll use this format. tig_freebsdfoundation.org: That makes sense. I'll use this format. | |||||
if (d->d_size <= 0 || d->d_buf == NULL) { | if (d->d_size <= 0 || d->d_buf == NULL) { | ||||
printf("\nSection '%s' has no data to dump.\n", | printf("\nSection '%s' has no data to dump.\n", | ||||
Done Inline Actionsindentation emaste: indentation | |||||
s->name); | s->name); | ||||
continue; | continue; | ||||
} | } | ||||
buf = d->d_buf; | buf = d->d_buf; | ||||
sz = d->d_size; | sz = d->d_size; | ||||
addr = s->addr; | addr = s->addr; | ||||
Done Inline ActionsWe are not checking the return value here. If it should be ignored, add a (void) cast of the return value - that's the conventional way to indicate that the return value is being ignored deliberately. markj: We are not checking the return value here. If it should be ignored, add a `(void)` cast of the… | |||||
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); | ||||
nbytes = sz > 16? 16 : sz; | nbytes = sz > 16? 16 : sz; | ||||
for (j = 0; j < 16; j++) { | for (j = 0; j < 16; j++) { | ||||
if ((size_t)j < nbytes) | if ((size_t)j < nbytes) | ||||
printf("%2.2x", buf[j]); | printf("%2.2x", buf[j]); | ||||
else | else | ||||
printf(" "); | printf(" "); | ||||
if ((j & 3) == 3) | if ((j & 3) == 3) | ||||
printf(" "); | printf(" "); | ||||
} | } | ||||
for (j = 0; (size_t)j < nbytes; j++) { | for (j = 0; (size_t)j < nbytes; j++) { | ||||
if (isprint(buf[j])) | if (isprint(buf[j])) | ||||
Done Inline Actionsextra EOL whitespace emaste: extra EOL whitespace | |||||
printf("%c", buf[j]); | printf("%c", buf[j]); | ||||
else | else | ||||
printf("."); | printf("."); | ||||
} | } | ||||
printf("\n"); | printf("\n"); | ||||
buf += nbytes; | buf += nbytes; | ||||
addr += nbytes; | addr += nbytes; | ||||
sz -= nbytes; | sz -= nbytes; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
str_dump(struct readelf *re) | 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; | ||||
unsigned int len; | unsigned int len; | ||||
Not Done Inline ActionsSo this frees the buffer passed by the caller, in one case it's d_buf from a libelf data descriptor. In other words, we are making assumptions about how libelf is allocating data buffers and that seems a bit fragile. I think it would be better for this function not to make any such assumptions and avoid replacing the input buffer with the output buffer. Just malloc() and return the output buffer (and its size) using separate parameters. markj: So this frees the buffer passed by the caller, in one case it's `d_buf` from a libelf data… | |||||
Done Inline ActionsOne question I have about this is if the decompression is unsuccessful, do we want to pass back the original buffer and size or just check the return value from the caller side? tig_freebsdfoundation.org: One question I have about this is if the decompression is unsuccessful, do we want to pass back… | |||||
Not Done Inline ActionsI think it's better to simply have the caller check the return value and decide which buffer to use. It's a bit more code, but not much, and is easier to follow. The caller has to know whether to free the returned buffer anyway. markj: I think it's better to simply have the caller check the return value and decide which buffer to… | |||||
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++) { | ||||
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; | ||||
Not Done Inline ActionsAll of the error paths that lead to the fail label do not result from a libelf error, so I believe elf_errmsg() will give you garbage here. markj: All of the error paths that lead to the `fail` label do not result from a libelf error, so I… | |||||
Not Done Inline ActionsI can see that now. Would it be good if I just warnx("decompress_section failed")? I'm not experienced in producing error messages would appreciate any suggestions. tig_freebsdfoundation.org: I can see that now. Would it be good if I just warnx("decompress_section failed")? I'm not… | |||||
Not Done Inline ActionsPer the zlib documentation, strm.msg will be set to an error string upon a failure, so you could print that. I would suggest checking it for NULL and just printing the error number in that case as a robustness measure. markj: Per the zlib documentation, `strm.msg` will be set to an error string upon a failure, so you… | |||||
Not Done Inline ActionsCould you specify what you mean by "checking it for NULL and just printing the error number"? I'm not sure which error number you are referring to tig_freebsdfoundation.org: Could you specify what you mean by "checking it for NULL and just printing the error number"? | |||||
Not Done Inline ActionsWhen reporting errors from zlib, you can print strm.msg as part of the error description. I'm not sure that it is guaranteed to be set for all errors (it would be worth reviewing the zlib docs), in which case you could print the error number that you had compared with Z_OK. markj: When reporting errors from zlib, you can print `strm.msg` as part of the error description. I'm… | |||||
Not Done Inline ActionsI looked at zlib manual and it seems like strm.msg handles most errors. In the rare case where there is an error but strm.msg is NULL printing the error number would be helpful. tig_freebsdfoundation.org: I looked at zlib manual and it seems like strm.msg handles most errors. In the rare case where… | |||||
(void) elf_errno(); | (void) elf_errno(); | ||||
if ((d = elf_getdata(s->scn, NULL)) == NULL && | if ((d = elf_getdata(s->scn, NULL)) == NULL && | ||||
(d = elf_rawdata(s->scn, NULL)) == NULL) { | (d = elf_rawdata(s->scn, NULL)) == NULL) { | ||||
Done Inline ActionsI think you want to call inflateEnd() as part of the cleanup here. Also the indentation looks wrong; goto labels should not have any indentation. markj: I think you want to call inflateEnd() as part of the cleanup here.
Also the indentation looks… | |||||
elferr = elf_errno(); | elferr = elf_errno(); | ||||
if (elferr != 0) | if (elferr != 0) | ||||
warnx("elf_getdata failed: %s", | warnx("elf_getdata failed: %s", | ||||
elf_errmsg(elferr)); | elf_errmsg(elferr)); | ||||
continue; | continue; | ||||
} | } | ||||
(void) elf_errno(); | (void) elf_errno(); | ||||
if (d->d_size <= 0 || d->d_buf == NULL) { | if (d->d_size <= 0 || d->d_buf == NULL) { | ||||
▲ Show 20 Lines • Show All 774 Lines • ▼ Show 20 Lines | case 'x': | ||||
re->options |= RE_X; | re->options |= RE_X; | ||||
si = strtoul(optarg, &ep, 10); | si = strtoul(optarg, &ep, 10); | ||||
if (*ep == '\0') | if (*ep == '\0') | ||||
add_dumpop(re, (size_t) si, NULL, HEX_DUMP, | add_dumpop(re, (size_t) si, NULL, HEX_DUMP, | ||||
DUMP_BY_INDEX); | DUMP_BY_INDEX); | ||||
else | else | ||||
add_dumpop(re, 0, optarg, HEX_DUMP, | add_dumpop(re, 0, optarg, HEX_DUMP, | ||||
DUMP_BY_NAME); | DUMP_BY_NAME); | ||||
break; | |||||
case 'z': | |||||
/* section content decompression is not implemented yet | |||||
* only displays compressed header for sections for now | |||||
*/ | |||||
re->options |= RE_Z; | |||||
break; | 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); | ||||
} | } | ||||
} | } | ||||
argv += optind; | argv += optind; | ||||
Show All 40 Lines |
in contrast to the comment above these were already sorted by long option name, so this one should be added in order