new nlist routines

This commit is contained in:
cgd 1994-05-09 03:14:43 +00:00
parent 221bc33ccd
commit e23e45bcfc
2 changed files with 89 additions and 64 deletions

View File

@ -1,5 +1,5 @@
.\" Copyright (c) 1980, 1991 Regents of the University of California.
.\" All rights reserved.
.\" Copyright (c) 1980, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@ -29,10 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" from: @(#)nlist.3 6.2 (Berkeley) 4/19/91
.\" $Id: nlist.3,v 1.3 1994/01/10 23:32:31 jtc Exp $
.\" @(#)nlist.3 8.3 (Berkeley) 4/19/94
.\"
.Dd April 19, 1991
.Dd April 19, 1994
.Dt NLIST 3
.Os BSD 4
.Sh NAME

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -32,92 +32,118 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)nlist.c 5.8 (Berkeley) 2/23/91";*/
static char *rcsid = "$Id: nlist.c,v 1.3 1993/08/26 00:44:52 jtc Exp $";
static char sccsid[] = "@(#)nlist.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <errno.h>
#include <a.out.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
typedef struct nlist NLIST;
#define _strx n_un.n_strx
#define _name n_un.n_name
#define ISVALID(p) (p->_name && p->_name[0])
int
nlist(name, list)
const char *name;
NLIST *list;
struct nlist *list;
{
register NLIST *p, *s;
struct exec ebuf;
FILE *fstr, *fsym;
NLIST nbuf;
off_t strings_offset, symbol_offset, symbol_size, lseek();
int entries, len, maxlen;
char sbuf[256];
int fd, n;
entries = -1;
fd = open(name, O_RDONLY, 0);
if (fd < 0)
return (-1);
n = __fdnlist(fd, list);
(void)close(fd);
return (n);
}
if (!(fsym = fopen(name, "r")))
return(-1);
if (fread((char *)&ebuf, sizeof(struct exec), 1, fsym) != 1 ||
N_BADMAG(ebuf))
goto done1;
#define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
symbol_offset = N_SYMOFF(ebuf);
symbol_size = ebuf.a_syms;
strings_offset = symbol_offset + symbol_size;
if (fseek(fsym, symbol_offset, SEEK_SET))
goto done1;
int
__fdnlist(fd, list)
register int fd;
register struct nlist *list;
{
register struct nlist *p, *s;
register caddr_t strtab;
register off_t stroff, symoff;
register u_long symsize;
register int nent, cc;
size_t strsize;
struct nlist nbuf[1024];
struct exec exec;
struct stat st;
if (!(fstr = fopen(name, "r")))
goto done1;
if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
read(fd, &exec, sizeof(exec)) != sizeof(exec) ||
N_BADMAG(exec) || fstat(fd, &st) < 0)
return (-1);
symoff = N_SYMOFF(exec);
symsize = exec.a_syms;
stroff = symoff + symsize;
/* Check for files too large to mmap. */
if (st.st_size - stroff > SIZE_T_MAX) {
errno = EFBIG;
return (-1);
}
/*
* Map string table into our address space. This gives us
* an easy way to randomly access all the strings, without
* making the memory allocation permanent as with malloc/free
* (i.e., munmap will return it to the system).
*/
strsize = st.st_size - stroff;
strtab = mmap(NULL, (size_t)strsize, PROT_READ, 0, fd, stroff);
if (strtab == (char *)-1)
return (-1);
/*
* clean out any left-over information for all valid entries.
* Type and value defined to be 0 if not found; historical
* versions cleared other and desc as well. Also figure out
* the largest string length so don't read any more of the
* string table than we have to.
*
* XXX clearing anything other than n_type and n_value violates
* the semantics given in the man page.
*/
for (p = list, entries = maxlen = 0; ISVALID(p); ++p, ++entries) {
nent = 0;
for (p = list; !ISLAST(p); ++p) {
p->n_type = 0;
p->n_other = 0;
p->n_desc = 0;
p->n_value = 0;
if ((len = strlen(p->_name)) > maxlen)
maxlen = len;
}
if (++maxlen > sizeof(sbuf)) { /* for the NULL */
(void)fprintf(stderr, "nlist: symbol too large.\n");
entries = -1;
goto done2;
++nent;
}
if (lseek(fd, symoff, SEEK_SET) == -1)
return (-1);
for (s = &nbuf; symbol_size; symbol_size -= sizeof(NLIST)) {
if (fread((char *)s, sizeof(NLIST), 1, fsym) != 1)
goto done2;
if (!s->_strx || s->n_type&N_STAB)
continue;
if (fseek(fstr, strings_offset + s->_strx, SEEK_SET))
goto done2;
(void)fread(sbuf, sizeof(sbuf[0]), maxlen, fstr);
for (p = list; ISVALID(p); p++)
if (!strcmp(p->_name, sbuf)) {
p->n_value = s->n_value;
p->n_type = s->n_type;
p->n_desc = s->n_desc;
p->n_other = s->n_other;
if (!--entries)
goto done2;
}
while (symsize > 0) {
cc = MIN(symsize, sizeof(nbuf));
if (read(fd, nbuf, cc) != cc)
break;
symsize -= cc;
for (s = nbuf; cc > 0; ++s, cc -= sizeof(*s)) {
register int soff = s->n_un.n_strx;
if (soff == 0 || (s->n_type & N_STAB) != 0)
continue;
for (p = list; !ISLAST(p); p++)
if (!strcmp(&strtab[soff], p->n_un.n_name)) {
p->n_value = s->n_value;
p->n_type = s->n_type;
p->n_desc = s->n_desc;
p->n_other = s->n_other;
if (--nent <= 0)
break;
}
}
}
done2: (void)fclose(fstr);
done1: (void)fclose(fsym);
return(entries);
munmap(strtab, strsize);
return (nent);
}