1
0
Files
irix-657m-src/eoe/cmd/setsym/setsym_elf.c
2022-09-29 17:59:04 +03:00

419 lines
11 KiB
C

/*
* setsym.c
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <getopt.h>
#include <utime.h>
#include <libelf.h>
#include <libdwarf.h>
#include <syslog.h>
#include "setsym.h"
#include "elfsubr.h"
#include "readsym.h"
/* command line flags */
#define NUM_FLAGS 3
#define V_FLAG 0 /* verbose flag */
#define D_FLAG 1 /* dump to stdout flag */
#define E_FLAG 2 /* elf symbols only */
/* symbol offset indexes*/
#define OFF_LIST_SIZE 4
#define SYMMAX 0
#define NAMESIZE 1
#define DBSTAB 2
#define NAMETAB 3
char *off_name[OFF_LIST_SIZE] = {
"symmax",
"namesize",
"dbstab",
"nametab"
};
char *Cmd;
/* prototypes */
static void process(char *, int [NUM_FLAGS]);
static void usage_error(void);
static void dump_symtab(int, int, int, void *, char *,
off_t [OFF_LIST_SIZE], int);
static void write_symtab(int, Elf *, int, int, void *, char *,
off_t [OFF_LIST_SIZE], int, int, int);
static int compar64(const void *, const void *);
static int compar32(const void *, const void *);
int
main(int argc, char **argv)
{
int c;
int flag[NUM_FLAGS];
char *filename = "unix";
struct stat bsb, asb;
if ((Cmd = strrchr(argv[0], '/')) == NULL)
Cmd = argv[0];
else
Cmd++;
/* set all flags to false */
for (c = 0; c < NUM_FLAGS; c++)
flag[c] = 0;
/* read command line */
while ((c = getopt(argc, argv, "vde")) != -1) {
switch(c) {
case 'v':
(flag[V_FLAG])++;
break;
case 'd':
(flag[D_FLAG])++;
break;
case 'e':
(flag[E_FLAG])++;
break;
case '?':
usage_error();
break;
}
}
if (argc - optind != 1)
usage_error();
else
filename = argv[optind];
if (stat(filename, &bsb) != 0)
bsb.st_mtime = 0;
process(filename, flag);
if (stat(filename, &asb) == 0 && asb.st_mtime < bsb.st_mtime) {
struct utimbuf utb;
syslog(LOG_WARNING, "WARNING: %s mtime was in the future",
filename);
fprintf(stderr, "%s: WARNING: %s mtime was in the future\n",
argv[0], filename);
utb.actime = bsb.st_atime;
utb.modtime = bsb.st_mtime;
if (utime(filename, &utb) == 0) {
syslog(LOG_WARNING, "WARNING: %s was modified but mtime was set back", filename);
fprintf(stderr, "%s: WARNING: %s was modified but mtime was set back\n", argv[0], filename);
}
}
exit(0);
}
static void
process(char *filename, int flag[NUM_FLAGS])
{
off_t offset[OFF_LIST_SIZE];
char *err;
int fd;
Elf *elf;
Elf_Scn *datascn;
Elf_Scn *sdatascn;
Elf_Scn *bssscn;
int i, bits;
void *dbstab; /* debugging symbol table */
int symmax; /* maximum number of symbols in dbstab */
char *nametab; /* name string table */
int namesize; /* indext to next available byte */
if (elf_version(EV_CURRENT) == EV_NONE)
xerror("out of date with respect to current ELF version", NONE);
if (flag[D_FLAG]) {
if ((fd = open(filename, O_RDONLY)) == -1)
xerror("cannot open file", NONE);
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
xerror("cannot open ELF file", OP, fd);
}
else {
if ((fd = open(filename, O_RDWR)) == -1)
xerror("cannot open file", NONE);
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
xerror("cannot open ELF file", OP, fd);
}
/* get .data section */
datascn = find_section(elf, ".data");
if (datascn == NULL)
xerror("could not access the .data section. Not a valid ELF file", OPELF, elf, fd);
/* get .sdata section */
sdatascn = find_section(elf, ".sdata");
/* get .bss section, if any */
bssscn = find_section(elf, ".bss");
/* get file offset and virtual address of data section */
if ((bits = elf_type(elf)) == ELF_MIPS64) {
for (i = 0; i < OFF_LIST_SIZE; i++) {
auto Elf64_Off off;
err = find_sym_offset64(elf, off_name[i],
&off, datascn, sdatascn, bssscn);
if (err) {
fprintf(stderr, "%s: symbol \'%s\' not found\n",
Cmd, off_name[i]);
xerror(err, OPELF, elf, fd);
}
offset[i] = (off_t)off;
}
} else if (bits == ELF_MIPS32) {
for (i = 0; i < OFF_LIST_SIZE; i++) {
auto Elf32_Off off;
err = find_sym_offset32(elf, off_name[i],
&off, datascn, sdatascn, bssscn);
if (err) {
fprintf(stderr, "%s: symbol \'%s\' not found\n",
Cmd, off_name[i]);
xerror(err, OPELF, elf, fd);
}
offset[i] = (off_t)off;
}
} else
xerror("not a valid 64/32-bit MIPS ELF file", OPELF, elf, fd);
/* find size of tables */
if ((lseek(fd, offset[SYMMAX], SEEK_SET) == -1) ||
(read(fd, &symmax, sizeof(symmax)) != sizeof(symmax)))
xerror("could not seek/read symmax in file", OPELF, elf, fd);
if ((lseek(fd, offset[NAMESIZE], SEEK_SET) == -1) ||
(read(fd, &namesize, sizeof(namesize)) != sizeof(namesize)))
xerror("could not seek/read namesize in file", OPELF, elf, fd);
/* allocate space for tables */
if (bits == ELF_MIPS64)
dbstab = (void *) calloc(symmax, sizeof(struct dbstbl64));
else /* bits == ELF_MIPS32 */
dbstab = (void *) calloc(symmax, sizeof(struct dbstbl32));
nametab = (char *) calloc(namesize, sizeof(char));
if ((dbstab == NULL) || (nametab == NULL))
xerror("could not malloc table", OPELF, elf, fd);
/* if verbose then write the sizes */
if (flag[V_FLAG]) {
printf ("Maximum number of symbols: %d\n", symmax);
printf ("Maximum size of name table: %d\n", namesize);
}
/* either dump symbol table or write into it */
if (flag[D_FLAG]) {
elf_end(elf);
dump_symtab(fd, symmax, namesize, dbstab,
nametab, offset, bits);
}
else {
write_symtab(fd, elf, symmax, namesize, dbstab, nametab,
offset, bits, flag[V_FLAG], flag[E_FLAG]);
elf_end(elf);
}
close(fd);
}
static void
dump_symtab( int fd,
int symmax,
int namesize,
void *dbstab,
char *nametab,
off_t offset[OFF_LIST_SIZE],
int bits)
{
int i;
struct dbstbl64 *dbstab64 = (struct dbstbl64 *) dbstab;
struct dbstbl32 *dbstab32 = (struct dbstbl32 *) dbstab;
if (bits == ELF_MIPS64) {
if ((lseek(fd, offset[DBSTAB], SEEK_SET) == -1) ||
(read(fd, dbstab, sizeof(struct dbstbl64) * symmax) !=
sizeof(struct dbstbl64) * symmax))
xerror("could not seek/read dbstab", OP, fd);
if ((lseek(fd, offset[NAMETAB], SEEK_SET) == -1) ||
(read(fd, nametab, sizeof(char) * namesize) !=
sizeof(char) * namesize))
xerror("could not seek/read nametab", OP, fd);
for (i = 0; i < symmax; i++)
printf("addr=%llx\tnoffst=%d\tname=\"%s\"\n",
dbstab64[i].addr, dbstab64[i].noffst,
&nametab[dbstab64[i].noffst]);
}
else /* bits == ELF_MIPS32 */ {
if ((lseek(fd, offset[DBSTAB], SEEK_SET) == -1) ||
(read(fd, dbstab, sizeof(struct dbstbl32) * symmax) !=
sizeof(struct dbstbl32) * symmax))
xerror("could not seek/read dbstab", OP, fd);
if ((lseek(fd, offset[NAMETAB], SEEK_SET) == -1) ||
(read(fd, nametab, sizeof(char) * namesize) !=
sizeof(char) * namesize))
xerror("could not seek/read nametab", OP, fd);
for (i = 0; i < symmax; i++)
printf("addr=%x\tnoffst=%d\tname=\"%s\"\n",
dbstab32[i].addr, dbstab32[i].noffst,
&nametab[dbstab32[i].noffst]);
}
}
static void
write_symtab( int fd,
Elf *elf,
int symmax,
int namesize,
void *dbstab,
char *nametab,
off_t offset[OFF_LIST_SIZE],
int bits,
int Verbose,
int ElfOnly)
{
int symnum;
struct dbstbl64 *dbstab64 = (struct dbstbl64 *) dbstab;
struct dbstbl32 *dbstab32 = (struct dbstbl32 *) dbstab;
init_read_symtab(fd, elf, symmax, namesize, dbstab, nametab, bits);
symnum = elf_read_symtab();
if (!ElfOnly)
symnum = dwarf_read_symtab(Verbose);
if (bits == ELF_MIPS64) {
qsort(dbstab, symnum, sizeof(struct dbstbl64), compar64);
/* print info if verbose flag is on */
if (Verbose) {
printf("First symbol %s @ 0x%llx Last %s @ 0x%llx\n",
&nametab[dbstab64[0].noffst],
dbstab64[0].addr,
&nametab[dbstab64[symnum-1].noffst],
dbstab64[symnum-1].addr);
printf("Using %d out of %d available symbol entries.\n",
symnum, symmax);
printf("Seeking to 0x%llx, writing %d bytes of dbstab.\n",
offset[DBSTAB],
sizeof(struct dbstbl64) * symmax);
}
if ((lseek(fd, offset[DBSTAB], SEEK_SET) == -1) ||
(write(fd, dbstab, sizeof(struct dbstbl64) * symmax) !=
sizeof(struct dbstbl64) * symmax))
xerror("could not seek/write dbstab", OPELF, elf, fd);
}
else /* bits == ELF_MIPS32 */ {
qsort(dbstab, symnum, sizeof(struct dbstbl32), compar32);
/* print info if verbose flag is on */
if (Verbose) {
printf("First symbol %s @ 0x%x Last %s @ 0x%x\n",
&nametab[dbstab32[0].noffst],
dbstab32[0].addr,
&nametab[dbstab32[symnum-1].noffst],
dbstab32[symnum-1].addr);
printf("Using %d out of %d available symbol entries.\n",
symnum, symmax);
printf("Seeking to 0x%llx, writing %d bytes of dbstab.\n",
offset[DBSTAB],
sizeof(struct dbstbl32) * symmax);
}
if ((lseek(fd, offset[DBSTAB], SEEK_SET) == -1) ||
(write(fd, dbstab, sizeof(struct dbstbl32) * symmax) !=
sizeof(struct dbstbl32) * symmax))
xerror("could not seek/write dbstab", OPELF, elf, fd);
}
if (Verbose) {
printf("Using all %d bytes for symbol names.\n", namesize);
printf("Seeking to 0x%llx, writing %d bytes of nametab.\n",
offset[NAMETAB], sizeof(char ) * namesize);
}
if ((lseek(fd, offset[NAMETAB], SEEK_SET) == -1) ||
(write(fd, nametab, sizeof(char) * namesize) !=
sizeof(char) * namesize))
xerror("could not seek/write nametab", OPELF, elf, fd);
/*
* now re-write max symbols "symmax" so that binary search
* won't find a bucket of zeros
*/
if ((lseek(fd, offset[SYMMAX], SEEK_SET) == -1) ||
(write(fd, &symnum, sizeof(symnum)) != sizeof(symnum)))
xerror("could not seek/write symnum", OPELF, elf, fd);
}
static int
compar64(const void *x, const void *y)
{
if (((struct dbstbl64 *)x)->addr > ((struct dbstbl64 *)y)->addr)
return(1);
else if (((struct dbstbl64 *)x)->addr == ((struct dbstbl64 *)y)->addr)
return(0);
return(-1);
}
static int
compar32(const void *x, const void *y)
{
if (((struct dbstbl32 *)x)->addr > ((struct dbstbl32 *)y)->addr)
return(1);
else if (((struct dbstbl32 *)x)->addr == ((struct dbstbl32 *)y)->addr)
return(0);
return(-1);
}
void
xerror(char *msg, int closes, ...)
{
Dwarf_Error derror;
va_list ap;
va_start(ap, closes);
fprintf(stderr, "%s: Error: %s.\n", Cmd, msg);
if (closes == OP)
close((int) va_arg(ap, int));
else if (closes == OPELF) {
elf_end((Elf *) va_arg(ap, Elf *));
close((int) va_arg(ap, int));
}
else if (closes == OPDW) {
dwarf_finish((Dwarf_Debug) va_arg(ap, Dwarf_Debug), &derror);
close((int) va_arg(ap, int));
}
else if (closes == OPELFDW) {
dwarf_finish((Dwarf_Debug) va_arg(ap, Dwarf_Debug), &derror);
elf_end((Elf *) va_arg(ap, Elf *));
close((int) va_arg(ap, int));
}
va_end(ap);
exit(1);
}
static void
usage_error(void)
{
fprintf(stderr, "\n");
fprintf(stderr, "Usage: setsym [-[d]|[[v][e]]]] filename\n");
fprintf(stderr, " -d: Dump symbols from already processed file\n");
fprintf(stderr, " -v: Verbose\n");
fprintf(stderr, " -e: ELF symbols only (default is ELF & DWARF)\n");
fprintf(stderr, "\n");
exit(1);
}