mirror of
https://github.com/openbsd/src.git
synced 2025-01-10 06:47:55 -08:00
tedu a.out support
This commit is contained in:
parent
cc16848780
commit
40b3cc4674
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: nlist.c,v 1.42 2013/08/22 04:43:41 guenther Exp $ */
|
||||
/* $OpenBSD: nlist.c,v 1.43 2013/10/15 05:15:12 deraadt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
@ -55,10 +55,6 @@
|
||||
#include <elf_abi.h>
|
||||
#endif
|
||||
|
||||
#ifdef _NLIST_DO_ECOFF
|
||||
#include <sys/exec_ecoff.h>
|
||||
#endif
|
||||
|
||||
typedef struct nlist NLIST;
|
||||
#define _strx n_un.n_strx
|
||||
#define _name n_un.n_name
|
||||
@ -66,229 +62,6 @@ typedef struct nlist NLIST;
|
||||
static char *kfile;
|
||||
static char *fmterr;
|
||||
|
||||
#if defined(_NLIST_DO_AOUT)
|
||||
|
||||
static u_long get_kerntext(char *kfn, u_int magic);
|
||||
|
||||
int
|
||||
__aout_knlist(int fd, DB *db, int ksyms)
|
||||
{
|
||||
int nsyms;
|
||||
struct exec ebuf;
|
||||
FILE *fp;
|
||||
NLIST nbuf;
|
||||
DBT data, key;
|
||||
int nr, strsize;
|
||||
size_t len;
|
||||
u_long kerntextoff;
|
||||
size_t snamesize = 0;
|
||||
char *strtab, buf[1024], *sname, *p;
|
||||
|
||||
/* Read in exec structure. */
|
||||
nr = read(fd, &ebuf, sizeof(struct exec));
|
||||
if (nr != sizeof(struct exec)) {
|
||||
fmterr = "no exec header";
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Check magic number and symbol count. */
|
||||
if (N_BADMAG(ebuf)) {
|
||||
fmterr = "bad magic number";
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Must have a symbol table. */
|
||||
if (!ebuf.a_syms) {
|
||||
fmterr = "stripped";
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Seek to string table. */
|
||||
if (lseek(fd, N_STROFF(ebuf), SEEK_SET) == -1) {
|
||||
fmterr = "corrupted string table";
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Read in the size of the string table. */
|
||||
nr = read(fd, (char *)&strsize, sizeof(strsize));
|
||||
if (nr != sizeof(strsize)) {
|
||||
fmterr = "no symbol table";
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Read in the string table. */
|
||||
strsize -= sizeof(strsize);
|
||||
if (!(strtab = malloc(strsize)))
|
||||
errx(1, "cannot allocate %d bytes for string table", strsize);
|
||||
if ((nr = read(fd, strtab, strsize)) != strsize) {
|
||||
fmterr = "corrupted symbol table";
|
||||
free(strtab);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Seek to symbol table. */
|
||||
if (!(fp = fdopen(fd, "r")))
|
||||
err(1, "%s", kfile);
|
||||
if (fseek(fp, N_SYMOFF(ebuf), SEEK_SET) == -1) {
|
||||
free(strtab);
|
||||
warn("fseek %s", kfile);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
data.data = (u_char *)&nbuf;
|
||||
data.size = sizeof(NLIST);
|
||||
|
||||
kerntextoff = get_kerntext(kfile, N_GETMAGIC(ebuf));
|
||||
|
||||
/* Read each symbol and enter it into the database. */
|
||||
nsyms = ebuf.a_syms / sizeof(struct nlist);
|
||||
sname = NULL;
|
||||
while (nsyms--) {
|
||||
if (fread((char *)&nbuf, sizeof (NLIST), 1, fp) != 1) {
|
||||
if (feof(fp))
|
||||
fmterr = "corrupted symbol table";
|
||||
else
|
||||
warn("%s", kfile);
|
||||
free(strtab);
|
||||
return (-1);
|
||||
}
|
||||
if (!nbuf._strx || (nbuf.n_type & N_STAB))
|
||||
continue;
|
||||
|
||||
/* If the symbol does not start with '_', add one */
|
||||
p = strtab + nbuf._strx - sizeof(int);
|
||||
if (*p != '_') {
|
||||
len = strlen(p) + 1;
|
||||
if (len >= snamesize) {
|
||||
char *newsname;
|
||||
int newsnamesize = len + 1024;
|
||||
|
||||
newsname = realloc(sname, newsnamesize);
|
||||
if (newsname == NULL) {
|
||||
if (sname)
|
||||
free(sname);
|
||||
sname = NULL;
|
||||
} else {
|
||||
sname = newsname;
|
||||
snamesize = newsnamesize;
|
||||
}
|
||||
}
|
||||
if (sname == NULL)
|
||||
errx(1, "cannot allocate memory");
|
||||
*sname = '_';
|
||||
strlcpy(sname + 1, p, snamesize - 1);
|
||||
key.data = (u_char *)sname;
|
||||
key.size = len;
|
||||
} else {
|
||||
key.data = (u_char *)p;
|
||||
key.size = strlen((char *)key.data);
|
||||
}
|
||||
if (db->put(db, &key, &data, 0))
|
||||
err(1, "record enter");
|
||||
|
||||
if (strcmp((char *)key.data, VRS_SYM) == 0) {
|
||||
long cur_off;
|
||||
|
||||
if (!ksyms) {
|
||||
/*
|
||||
* Calculate offset relative to a normal
|
||||
* (non-kernel) a.out. Kerntextoff is where the
|
||||
* kernel is really loaded; N_TXTADDR is where
|
||||
* a normal file is loaded. From there, locate
|
||||
* file offset in text or data.
|
||||
*/
|
||||
long voff;
|
||||
|
||||
voff = nbuf.n_value-kerntextoff+N_TXTADDR(ebuf);
|
||||
if ((nbuf.n_type & N_TYPE) == N_TEXT)
|
||||
voff += N_TXTOFF(ebuf)-N_TXTADDR(ebuf);
|
||||
else
|
||||
voff += N_DATOFF(ebuf)-N_DATADDR(ebuf);
|
||||
cur_off = ftell(fp);
|
||||
if (fseek(fp, voff, SEEK_SET) == -1) {
|
||||
fmterr = "corrupted string table";
|
||||
free(strtab);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read version string up to, and including
|
||||
* newline. This code assumes that a newline
|
||||
* terminates the version line.
|
||||
*/
|
||||
if (fgets(buf, sizeof(buf), fp) == NULL) {
|
||||
fmterr = "corrupted string table";
|
||||
free(strtab);
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* This is /dev/ksyms or a look alike.
|
||||
* Use sysctl() to get version since we
|
||||
* don't have real text or data.
|
||||
*/
|
||||
int mib[2];
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_VERSION;
|
||||
len = sizeof(buf);
|
||||
if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
|
||||
err(1, "sysctl can't find kernel "
|
||||
"version string");
|
||||
}
|
||||
if ((p = strchr(buf, '\n')) != NULL)
|
||||
*(p+1) = '\0';
|
||||
}
|
||||
key.data = (u_char *)VRS_KEY;
|
||||
key.size = sizeof(VRS_KEY) - 1;
|
||||
data.data = (u_char *)buf;
|
||||
data.size = strlen(buf);
|
||||
if (db->put(db, &key, &data, 0))
|
||||
err(1, "record enter");
|
||||
|
||||
/* Restore to original values. */
|
||||
data.data = (u_char *)&nbuf;
|
||||
data.size = sizeof(NLIST);
|
||||
if (!ksyms && fseek(fp, cur_off, SEEK_SET) == -1) {
|
||||
fmterr = "corrupted string table";
|
||||
free(strtab);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
(void)fclose(fp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: Using this value from machine/param.h introduces a
|
||||
* XXX: machine dependency on this program, so /usr can not
|
||||
* XXX: be shared between (i.e.) several m68k machines.
|
||||
* Instead of compiling in KERNTEXTOFF or KERNBASE, try to
|
||||
* determine the text start address from a standard symbol.
|
||||
* For backward compatibility, use the old compiled-in way
|
||||
* when the standard symbol name is not found.
|
||||
*/
|
||||
#ifndef KERNTEXTOFF
|
||||
#define KERNTEXTOFF KERNBASE
|
||||
#endif
|
||||
|
||||
static u_long
|
||||
get_kerntext(char *name, u_int magic)
|
||||
{
|
||||
NLIST nl[2];
|
||||
|
||||
bzero((caddr_t)nl, sizeof(nl));
|
||||
nl[0]._name = "_kernel_text";
|
||||
|
||||
if (nlist(name, nl) != 0)
|
||||
return (KERNTEXTOFF);
|
||||
|
||||
return (nl[0].n_value);
|
||||
}
|
||||
|
||||
#endif /* _NLIST_DO_AOUT */
|
||||
|
||||
#ifdef _NLIST_DO_ELF
|
||||
int
|
||||
__elf_knlist(int fd, DB *db, int ksyms)
|
||||
@ -532,159 +305,12 @@ done:
|
||||
}
|
||||
#endif /* _NLIST_DO_ELF */
|
||||
|
||||
#ifdef _NLIST_DO_ECOFF
|
||||
|
||||
#define check(off, size) ((off < 0) || (off + size > mappedsize))
|
||||
#define BAD do { rv = -1; goto out; } while (0)
|
||||
#define BADUNMAP do { rv = -1; goto unmap; } while (0)
|
||||
#define ECOFF_INTXT(p, e) ((p) > (e)->a.text_start && \
|
||||
(p) < (e)->a.text_start + (e)->a.tsize)
|
||||
#define ECOFF_INDAT(p, e) ((p) > (e)->a.data_start && \
|
||||
(p) < (e)->a.data_start + (e)->a.dsize)
|
||||
|
||||
int
|
||||
__ecoff_knlist(int fd, DB *db, int ksyms)
|
||||
{
|
||||
struct ecoff_exechdr *exechdrp;
|
||||
struct ecoff_symhdr *symhdrp;
|
||||
struct ecoff_extsym *esyms;
|
||||
struct stat st;
|
||||
char *mappedfile, *cp;
|
||||
size_t mappedsize;
|
||||
u_long symhdroff, extstroff, off;
|
||||
u_int symhdrsize;
|
||||
int rv = 0;
|
||||
long i, nesyms;
|
||||
DBT data, key;
|
||||
NLIST nbuf;
|
||||
char *sname = NULL;
|
||||
size_t len, snamesize = 0;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
err(1, "can't stat %s", kfile);
|
||||
if (st.st_size > SIZE_T_MAX) {
|
||||
fmterr = "file too large";
|
||||
BAD;
|
||||
}
|
||||
|
||||
mappedsize = st.st_size;
|
||||
mappedfile = mmap(NULL, mappedsize, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
|
||||
if (mappedfile == MAP_FAILED) {
|
||||
fmterr = "unable to mmap";
|
||||
BAD;
|
||||
}
|
||||
|
||||
if (check(0, sizeof *exechdrp))
|
||||
BADUNMAP;
|
||||
exechdrp = (struct ecoff_exechdr *)&mappedfile[0];
|
||||
|
||||
if (ECOFF_BADMAG(exechdrp))
|
||||
BADUNMAP;
|
||||
|
||||
symhdroff = exechdrp->f.f_symptr;
|
||||
symhdrsize = exechdrp->f.f_nsyms;
|
||||
if (symhdrsize == 0) {
|
||||
fmterr = "stripped";
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (check(symhdroff, sizeof *symhdrp) ||
|
||||
sizeof *symhdrp != symhdrsize)
|
||||
BADUNMAP;
|
||||
symhdrp = (struct ecoff_symhdr *)&mappedfile[symhdroff];
|
||||
|
||||
nesyms = symhdrp->esymMax;
|
||||
if (check(symhdrp->cbExtOffset, nesyms * sizeof *esyms))
|
||||
BADUNMAP;
|
||||
esyms = (struct ecoff_extsym *)&mappedfile[symhdrp->cbExtOffset];
|
||||
extstroff = symhdrp->cbSsExtOffset;
|
||||
|
||||
data.data = (u_char *)&nbuf;
|
||||
data.size = sizeof(NLIST);
|
||||
|
||||
for (sname = NULL, i = 0; i < nesyms; i++) {
|
||||
/* Need to prepend a '_' */
|
||||
len = strlen(&mappedfile[extstroff + esyms[i].es_strindex]) + 1;
|
||||
if (len >= snamesize) {
|
||||
char *newsname;
|
||||
int newsnamesize = len + 1024;
|
||||
|
||||
newsname = realloc(sname, newsnamesize);
|
||||
if (newsname == NULL) {
|
||||
if (sname)
|
||||
free(sname);
|
||||
sname = NULL;
|
||||
} else {
|
||||
sname = newsname;
|
||||
snamesize = newsnamesize;
|
||||
}
|
||||
}
|
||||
if (sname == NULL)
|
||||
errx(1, "cannot allocate memory");
|
||||
*sname = '_';
|
||||
strlcpy(sname+1, &mappedfile[extstroff + esyms[i].es_strindex],
|
||||
snamesize - 1);
|
||||
|
||||
/* Fill in NLIST */
|
||||
bzero(&nbuf, sizeof(nbuf));
|
||||
nbuf.n_value = esyms[i].es_value;
|
||||
nbuf.n_type = N_EXT; /* XXX */
|
||||
|
||||
/* Store entry in db */
|
||||
key.data = (u_char *)sname;
|
||||
key.size = strlen(sname);
|
||||
if (db->put(db, &key, &data, 0))
|
||||
err(1, "record enter");
|
||||
|
||||
if (strcmp(sname, VRS_SYM) == 0) {
|
||||
key.data = (u_char *)VRS_KEY;
|
||||
key.size = sizeof(VRS_KEY) - 1;
|
||||
|
||||
/* Version string may be in either text or data segs */
|
||||
if (ECOFF_INTXT(nbuf.n_value, exechdrp))
|
||||
off = nbuf.n_value - exechdrp->a.text_start +
|
||||
ECOFF_TXTOFF(exechdrp);
|
||||
else if (ECOFF_INDAT(nbuf.n_value, exechdrp))
|
||||
off = nbuf.n_value - exechdrp->a.data_start +
|
||||
ECOFF_DATOFF(exechdrp);
|
||||
else
|
||||
err(1, "unable to find version string");
|
||||
|
||||
/* Version string should end in newline but... */
|
||||
data.data = &mappedfile[off];
|
||||
if ((cp = strchr(data.data, '\n')) != NULL)
|
||||
data.size = cp - (char *)data.data;
|
||||
else
|
||||
data.size = strlen((char *)data.data);
|
||||
|
||||
if (db->put(db, &key, &data, 0))
|
||||
err(1, "record enter");
|
||||
|
||||
/* Restore to original values */
|
||||
data.data = (u_char *)&nbuf;
|
||||
data.size = sizeof(nbuf);
|
||||
}
|
||||
}
|
||||
|
||||
unmap:
|
||||
munmap(mappedfile, mappedsize);
|
||||
out:
|
||||
return (rv);
|
||||
}
|
||||
#endif /* _NLIST_DO_ECOFF */
|
||||
|
||||
static struct knlist_handlers {
|
||||
int (*fn)(int fd, DB *db, int ksyms);
|
||||
} nlist_fn[] = {
|
||||
#ifdef _NLIST_DO_AOUT
|
||||
{ __aout_knlist },
|
||||
#endif
|
||||
#ifdef _NLIST_DO_ELF
|
||||
{ __elf_knlist },
|
||||
#endif
|
||||
#ifdef _NLIST_DO_ECOFF
|
||||
{ __ecoff_knlist },
|
||||
#endif
|
||||
};
|
||||
|
||||
int
|
||||
|
Loading…
Reference in New Issue
Block a user