Changeset View
Changeset View
Standalone View
Standalone View
usr.bin/elfctl/elfctl.c
Show First 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include "_elftc.h" | #include "_elftc.h" | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
static bool convert_to_feature_val(char *, uint32_t *); | static bool convert_to_feature_val(char *, uint32_t *); | ||||
static bool edit_file_features(Elf *, int, int, char *); | static bool edit_file_features(Elf *, int, int, char *, bool); | ||||
static bool get_file_features(Elf *, int, int, uint32_t *, uint64_t *); | static bool get_file_features(Elf *, int, int, uint32_t *, uint64_t *, bool); | ||||
static void print_features(void); | static void print_features(void); | ||||
static bool print_file_features(Elf *, int, int, char *); | static bool print_file_features(Elf *, int, int, char *, bool); | ||||
static void usage(void); | static void usage(void); | ||||
struct ControlFeatures { | struct ControlFeatures { | ||||
const char *alias; | const char *alias; | ||||
unsigned long value; | unsigned long value; | ||||
const char *desc; | const char *desc; | ||||
}; | }; | ||||
Show All 9 Lines | |||||
}; | }; | ||||
static struct option long_opts[] = { | static struct option long_opts[] = { | ||||
{ "help", no_argument, NULL, 'h' }, | { "help", no_argument, NULL, 'h' }, | ||||
{ NULL, 0, NULL, 0 } | { NULL, 0, NULL, 0 } | ||||
}; | }; | ||||
#if BYTE_ORDER == LITTLE_ENDIAN | #if BYTE_ORDER == LITTLE_ENDIAN | ||||
#define SUPPORTED_ENDIAN ELFDATA2LSB | #define HOST_ENDIAN ELFDATA2LSB | ||||
#define SWAP_ENDIAN ELFDATA2MSB | |||||
#else | #else | ||||
#define SUPPORTED_ENDIAN ELFDATA2MSB | #define HOST_ENDIAN ELFDATA2MSB | ||||
#define SWAP_ENDIAN ELFDATA2LSB | |||||
#endif | #endif | ||||
static bool iflag; | static bool iflag; | ||||
int | int | ||||
main(int argc, char **argv) | main(int argc, char **argv) | ||||
{ | { | ||||
GElf_Ehdr ehdr; | GElf_Ehdr ehdr; | ||||
Elf *elf; | Elf *elf; | ||||
Elf_Kind kind; | Elf_Kind kind; | ||||
int ch, fd, retval; | int ch, fd, retval; | ||||
char *features; | char *features; | ||||
bool editfeatures, lflag; | bool editfeatures, lflag, endian_swap; | ||||
lflag = 0; | lflag = 0; | ||||
editfeatures = false; | editfeatures = false; | ||||
retval = 0; | retval = 0; | ||||
features = NULL; | features = NULL; | ||||
if (elf_version(EV_CURRENT) == EV_NONE) | if (elf_version(EV_CURRENT) == EV_NONE) | ||||
errx(EXIT_FAILURE, "elf_version error"); | errx(EXIT_FAILURE, "elf_version error"); | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | if ((kind = elf_kind(elf)) != ELF_K_ELF) { | ||||
goto fail; | goto fail; | ||||
} | } | ||||
if (gelf_getehdr(elf, &ehdr) == NULL) { | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||||
warnx("gelf_getehdr: %s", elf_errmsg(-1)); | warnx("gelf_getehdr: %s", elf_errmsg(-1)); | ||||
retval = 1; | retval = 1; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
/* | |||||
* XXX need to support cross-endian operation, but for now | if (ehdr.e_ident[EI_DATA] == HOST_ENDIAN) { | ||||
* exit on error rather than misbehaving. | endian_swap = false; | ||||
*/ | } else if (ehdr.e_ident[EI_DATA] == SWAP_ENDIAN) { | ||||
if (ehdr.e_ident[EI_DATA] != SUPPORTED_ENDIAN) { | endian_swap = true; | ||||
warnx("file endianness must match host"); | } else { | ||||
warnx("file endianness unknown"); | |||||
retval = 1; | retval = 1; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
if (!editfeatures) { | if (!editfeatures) { | ||||
if (!print_file_features(elf, ehdr.e_phnum, fd, | if (!print_file_features(elf, ehdr.e_phnum, fd, | ||||
argv[0])) { | argv[0], endian_swap)) { | ||||
retval = 1; | retval = 1; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
} else if (!edit_file_features(elf, ehdr.e_phnum, fd, | } else if (!edit_file_features(elf, ehdr.e_phnum, fd, | ||||
features)) { | features, endian_swap)) { | ||||
retval = 1; | retval = 1; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
fail: | fail: | ||||
if (elf != NULL) | if (elf != NULL) | ||||
elf_end(elf); | elf_end(elf); | ||||
if (fd >= 0) | if (fd >= 0) | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | if (operation == '+') { | ||||
warnx("'%c' not an operator - use '+', '-', '='", | warnx("'%c' not an operator - use '+', '-', '='", | ||||
feature_str[0]); | feature_str[0]); | ||||
return (false); | return (false); | ||||
} | } | ||||
return (true); | return (true); | ||||
} | } | ||||
static bool | static bool | ||||
edit_file_features(Elf *elf, int phcount, int fd, char *val) | edit_file_features(Elf *elf, int phcount, int fd, char *val, bool endian_swap) | ||||
{ | { | ||||
uint32_t features; | uint32_t features; | ||||
uint64_t off; | uint64_t off; | ||||
if (!get_file_features(elf, phcount, fd, &features, &off)) { | if (!get_file_features(elf, phcount, fd, &features, &off, | ||||
endian_swap)) { | |||||
warnx("NT_FREEBSD_FEATURE_CTL note not found"); | warnx("NT_FREEBSD_FEATURE_CTL note not found"); | ||||
return (false); | return (false); | ||||
} | } | ||||
if (!convert_to_feature_val(val, &features)) | if (!convert_to_feature_val(val, &features)) | ||||
return (false); | return (false); | ||||
if (endian_swap) | |||||
features = bswap32(features); | |||||
if (lseek(fd, off, SEEK_SET) == -1 || | if (lseek(fd, off, SEEK_SET) == -1 || | ||||
write(fd, &features, sizeof(features)) < | write(fd, &features, sizeof(features)) < | ||||
(ssize_t)sizeof(features)) { | (ssize_t)sizeof(features)) { | ||||
warnx("error writing feature value"); | warnx("error writing feature value"); | ||||
return (false); | return (false); | ||||
} | } | ||||
return (true); | return (true); | ||||
} | } | ||||
static void | static void | ||||
print_features(void) | print_features(void) | ||||
{ | { | ||||
size_t i; | size_t i; | ||||
printf("Known features are:\n"); | printf("Known features are:\n"); | ||||
for (i = 0; i < nitems(featurelist); ++i) | for (i = 0; i < nitems(featurelist); ++i) | ||||
printf("%-16s%s\n", featurelist[i].alias, | printf("%-16s%s\n", featurelist[i].alias, | ||||
featurelist[i].desc); | featurelist[i].desc); | ||||
} | } | ||||
static bool | static bool | ||||
print_file_features(Elf *elf, int phcount, int fd, char *filename) | print_file_features(Elf *elf, int phcount, int fd, char *filename, | ||||
bool endian_swap) | |||||
{ | { | ||||
uint32_t features; | uint32_t features; | ||||
unsigned long i; | unsigned long i; | ||||
if (!get_file_features(elf, phcount, fd, &features, NULL)) { | if (!get_file_features(elf, phcount, fd, &features, NULL, | ||||
endian_swap)) { | |||||
return (false); | return (false); | ||||
} | } | ||||
printf("File '%s' features:\n", filename); | printf("File '%s' features:\n", filename); | ||||
for (i = 0; i < nitems(featurelist); ++i) { | for (i = 0; i < nitems(featurelist); ++i) { | ||||
printf("%-16s'%s' is ", featurelist[i].alias, | printf("%-16s'%s' is ", featurelist[i].alias, | ||||
featurelist[i].desc); | featurelist[i].desc); | ||||
if ((featurelist[i].value & features) == 0) | if ((featurelist[i].value & features) == 0) | ||||
printf("un"); | printf("un"); | ||||
printf("set.\n"); | printf("set.\n"); | ||||
} | } | ||||
return (true); | return (true); | ||||
} | } | ||||
static bool | static bool | ||||
get_file_features(Elf *elf, int phcount, int fd, uint32_t *features, | get_file_features(Elf *elf, int phcount, int fd, uint32_t *features, | ||||
uint64_t *off) | uint64_t *off, bool endian_swap) | ||||
{ | { | ||||
GElf_Phdr phdr; | GElf_Phdr phdr; | ||||
Elf_Note note; | Elf_Note note; | ||||
unsigned long read_total; | unsigned long read_total; | ||||
int namesz, descsz, i; | int namesz, descsz, i; | ||||
char *name; | char *name; | ||||
/* | /* | ||||
Show All 18 Lines | for (i = 0; i < phcount; ++i) { | ||||
while (read_total < phdr.p_filesz) { | while (read_total < phdr.p_filesz) { | ||||
if (read(fd, ¬e, sizeof(note)) < | if (read(fd, ¬e, sizeof(note)) < | ||||
(ssize_t)sizeof(note)) { | (ssize_t)sizeof(note)) { | ||||
warnx("elf note header too short"); | warnx("elf note header too short"); | ||||
return (false); | return (false); | ||||
} | } | ||||
read_total += sizeof(note); | read_total += sizeof(note); | ||||
if (endian_swap) { | |||||
note.n_namesz = bswap32(note.n_namesz); | |||||
note.n_descsz = bswap32(note.n_descsz); | |||||
note.n_type = bswap32(note.n_type); | |||||
} | |||||
/* | /* | ||||
* XXX: Name and descriptor are 4 byte aligned, however, | * XXX: Name and descriptor are 4 byte aligned, however, | ||||
* the size given doesn't include the padding. | * the size given doesn't include the padding. | ||||
*/ | */ | ||||
namesz = roundup2(note.n_namesz, 4); | namesz = roundup2(note.n_namesz, 4); | ||||
name = malloc(namesz); | name = malloc(namesz); | ||||
if (name == NULL) { | if (name == NULL) { | ||||
warn("malloc() failed."); | warn("malloc() failed."); | ||||
Show All 35 Lines | while (read_total < phdr.p_filesz) { | ||||
if (note.n_descsz > sizeof(uint32_t)) | if (note.n_descsz > sizeof(uint32_t)) | ||||
warnx("Feature note is bigger than expected"); | warnx("Feature note is bigger than expected"); | ||||
if (read(fd, features, sizeof(uint32_t)) < | if (read(fd, features, sizeof(uint32_t)) < | ||||
(ssize_t)sizeof(uint32_t)) { | (ssize_t)sizeof(uint32_t)) { | ||||
warnx("feature note data too short"); | warnx("feature note data too short"); | ||||
free(name); | free(name); | ||||
return (false); | return (false); | ||||
} | } | ||||
if (endian_swap) | |||||
*features = bswap32(*features); | |||||
if (off != NULL) | if (off != NULL) | ||||
*off = phdr.p_offset + read_total; | *off = phdr.p_offset + read_total; | ||||
free(name); | free(name); | ||||
return (true); | return (true); | ||||
} | } | ||||
} | } | ||||
warnx("NT_FREEBSD_FEATURE_CTL note not found"); | warnx("NT_FREEBSD_FEATURE_CTL note not found"); | ||||
return (false); | return (false); | ||||
} | } |