New ELFTC(3) APIs
Tools that display the internal structure of ELF and DWARF files (like
elfdump(1)
, readelf(1)
, and nm(1)
) frequently need to translate
ELF constants to human-readable strings.
Previously, Elftoolchain's tools contained ad-hoc code
to perform these translations. Take
elfdump
,
as an example. To convert an EM_*
value to its corresponding
symbolic name, it uses code like:
elfdump/elfdump.c
:228static const char *
e_machines(unsigned int mach)
{
static char machdesc[64];
switch (mach) {
case EM_NONE: return "EM_NONE";
case EM_M32: return "EM_M32";
/* ... similar lines of code ... */
case EM_RISCV: return "EM_RISCV";
}
snprintf(machdesc, sizeof(machdesc),
"(unknown machine) -- type 0x%x", mach);
return (machdesc);
}
elfdump
has similar code for converting the other ELF constant
values to their corresponding names. The other tools — nm
,
readelf
, etc. — also have code doing more or less the same thing.
As of revision [r4065] I have started adding new ELFTC(3) APIs that could help ease code maintenance in the future. These APIs follow the general template below:
/* Returns the symbolic name for a constant. */
const char *elftc_get_machine_name(unsigned int e_machine);
/* Returns any associated additional comment text. */
const char *elftc_get_machine_description(unsigned int e_machine);
Some notes about these APIs:
-
These functions are intended to be thread-safe by default — when they succeed, the functions return pointers to read-only data, and when they fail they return
NULL
and seterrno
(a thread-private value). -
Error handling is being left to the caller. This is because the caller usually has the best context on how to handle the error. In contrast, APIs that return a preformatted error string in the event of an error (such as,
"Unknown value NNN"
) make it tedious for the caller to tell if the call had actually succeeded. -
The implementations of these APIs are generated at build time from the information in the file
elfconstants.m4
.
There are manual pages for these functions, e.g. elftc_get_machine_name(3).
Revision [r4075] shows how these functions could be used.
const char *em_name;
char em_name_buffer[64];
if ((em_name = elftc_get_machine_name(ed->ehdr.e_machine)) == NULL) {
(void) snprintf(em_name_buffer, sizeof(em_name_buffer),
"(unknown machine) -- type 0x%x", ed->ehdr.e_machine);
em_name = em_name_buffer;
}
printf(" e_machine: %-18s\n", em_name);