1
0
Files
2022-09-29 17:59:04 +03:00

225 lines
4.8 KiB
C

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <getopt.h>
#include <libelf.h>
#define NONE 0x0 /* "..." = <nothing> */
#define OP 0x1 /* "..." = open() */
#define OPELF 0x2 /* "..." = elf_begin(), open() */
#define OK 0x4
#define ELF_NONE 0
#define ELF_UNKNOWN 1
#define ELF_MIPS32 2
#define ELF_MIPS64 3
char *Cmd;
int verbose;
/* prototypes */
static void process(char *);
static void usage_error(void);
extern int elf_type(Elf *elf);
extern Elf_Scn *find_section(Elf *elf, char *scn_name);
extern void xerror(char *msg, int closes, ...);
int
main(int argc, char **argv)
{
int c;
char *filename = NULL;
if ((Cmd = strrchr(argv[0], '/')) == NULL)
Cmd = argv[0];
else
Cmd++;
/* read command line */
while ((c = getopt(argc, argv, "f:v")) != -1) {
switch(c) {
case 'v':
verbose = 1;
break;
case 'f':
filename = optarg;
break;
case '?':
usage_error();
break;
}
}
if (filename == NULL)
usage_error();
process(filename);
return 0;
}
static void
process(char *filename)
{
int fd;
Elf *elf;
Elf_Scn *options;
if (elf_version(EV_CURRENT) == EV_NONE)
xerror("out of date with respect to current ELF version", NONE);
if ((fd = open(filename, O_RDWR)) == -1)
xerror("cannot open file", NONE);
if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL)
xerror("cannot open ELF file", OP, fd);
/* get .MIPS_options section */
options = find_section(elf, ".MIPS.options");
if (options == NULL)
xerror("could not access the .MIPS.options section. Not a valid ELF file", OPELF|OK, elf, fd);
if (elf_type(elf) == ELF_MIPS64) {
Elf_Data *opdata = NULL;
Elf_Options *optptr;
int off = 0;
opdata = elf_getdata(options, opdata);
if (opdata && (opdata->d_size > 0)) {
while (off < opdata->d_size) {
optptr = (Elf_Options *)((char *)opdata->d_buf + off);
off += optptr->size;
if (optptr->kind == ODK_EXCEPTIONS) {
if (verbose)
printf("found exceptions! - currently 0x%x\n", optptr->info);
optptr->info |= OEX_PAGE0;
break;
}
}
}
} else {
xerror("only supports 64 bits!", OPELF|OK, elf, fd);
}
elf_flagelf(elf, ELF_C_SET, ELF_F_DIRTY|ELF_F_LAYOUT);
if (elf_update(elf, ELF_C_WRITE) < 0) {
unlink(filename);
xerror("elf_update error - binary trashed! will remove!",
OPELF, elf, fd);
}
elf_end(elf);
close(fd);
}
void
xerror(char *msg, int closes, ...)
{
va_list ap;
va_start(ap, closes);
fprintf(stderr, "%s: %s: %s.\n", Cmd, closes & OK ? "Note" : "Error", msg);
if (closes & OPELF)
elf_end((Elf *) va_arg(ap, Elf *));
if (closes & OP)
close((int) va_arg(ap, int));
va_end(ap);
exit(closes & OK ? 0 : 1);
}
static void
usage_error(void)
{
fprintf(stderr, "\n");
fprintf(stderr, "Usage: setex [-v] [-f filename] value\n");
fprintf(stderr, " -v: Verbose\n");
fprintf(stderr, "\n");
exit(1);
}
int
elf_type(Elf *elf)
{
/* these statics are here so that if the same file is repeatedly
checked, the code isn't repeated */
static Elf *oldelf = NULL;
static int oldtype;
if (elf == oldelf)
return(oldtype);
/* otherwise do calculations */
else
{
unsigned char MipsElf32Ident[EI_NIDENT] = {
0x7f, 'E', 'L', 'F',
ELFCLASS32, ELFDATA2MSB, EV_CURRENT,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char MipsElf64Ident[EI_NIDENT] = {
0x7f, 'E', 'L', 'F',
ELFCLASS64, ELFDATA2MSB, EV_CURRENT,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
char *elf_ident;
oldelf = elf;
if ((elf_ident = elf_getident(elf, NULL)) == NULL)
return((oldtype = ELF_NONE));
if (memcmp(MipsElf32Ident, elf_ident, EI_NIDENT) == 0)
return((oldtype = ELF_MIPS32));
else if (memcmp(MipsElf64Ident, elf_ident, EI_NIDENT) == 0)
return((oldtype = ELF_MIPS64));
else
return((oldtype = ELF_UNKNOWN));
}
}
/*
* returns section with the name of scn_name, & puts its header in shdr64 or
* shdr32 based on elf's file type
*
*/
Elf_Scn *
find_section(Elf *elf, char *scn_name)
{
Elf64_Ehdr *ehdr64;
Elf32_Ehdr *ehdr32;
Elf_Scn *scn = NULL;
Elf64_Shdr *shdr64;
Elf32_Shdr *shdr32;
if (elf_type(elf) == ELF_MIPS64) {
if ((ehdr64 = elf64_getehdr(elf)) == NULL)
return(NULL);
do {
if ((scn = elf_nextscn(elf, scn)) == NULL)
break;
if ((shdr64 = elf64_getshdr(scn)) == NULL)
return(NULL);
} while (strcmp(scn_name, elf_strptr(elf, ehdr64->e_shstrndx,
shdr64->sh_name)));
}
else if (elf_type(elf) == ELF_MIPS32) {
if ((ehdr32 = elf32_getehdr(elf)) == NULL)
return(NULL);
do {
if ((scn = elf_nextscn(elf, scn)) == NULL)
break;
if ((shdr32 = elf32_getshdr(scn)) == NULL)
return(NULL);
} while (strcmp(scn_name, elf_strptr(elf, ehdr32->e_shstrndx,
shdr32->sh_name)));
}
else
scn = NULL;
return(scn);
}