330 lines
7.2 KiB
C
330 lines
7.2 KiB
C
|
/*
|
||
|
read_nlist.c
|
||
|
|
||
|
Read the symbol table of an executable into memory.
|
||
|
|
||
|
Created: Mar 6, 1992 by Philip Homburg
|
||
|
*/
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
#include <assert.h>
|
||
|
#include <a.out.h>
|
||
|
#include <errno.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include "extra.h"
|
||
|
|
||
|
#define USE_OLD_NLIST 1
|
||
|
|
||
|
static u16_t le16 _ARGS(( u16_t *word_p ));
|
||
|
static u32_t le32 _ARGS(( u32_t *word_p ));
|
||
|
static u16_t be16 _ARGS(( u16_t *word_p ));
|
||
|
static u32_t be32 _ARGS(( u32_t *word_p ));
|
||
|
|
||
|
static u16_t le16(word_p)
|
||
|
u16_t *word_p;
|
||
|
{
|
||
|
return (((u8_t *)word_p)[0] << 0) | (((u8_t *)word_p)[1] << 8);
|
||
|
}
|
||
|
|
||
|
static u16_t be16(word_p)
|
||
|
u16_t *word_p;
|
||
|
{
|
||
|
return (((u8_t *)word_p)[1] << 0) | (((u8_t *)word_p)[0] << 8);
|
||
|
}
|
||
|
|
||
|
static u32_t le32(dword_p)
|
||
|
u32_t *dword_p;
|
||
|
{
|
||
|
return le16(&((u16_t *)dword_p)[0]) |
|
||
|
((u32_t)le16(&((u16_t *)dword_p)[1]) << 16);
|
||
|
}
|
||
|
|
||
|
static u32_t be32(dword_p)
|
||
|
u32_t *dword_p;
|
||
|
{
|
||
|
return be16(&((u16_t *)dword_p)[1]) |
|
||
|
((u32_t)be16(&((u16_t *)dword_p)[0]) << 16);
|
||
|
}
|
||
|
|
||
|
#ifndef USE_OLD_NLIST
|
||
|
struct old_nlist
|
||
|
{
|
||
|
char n_name[8];
|
||
|
long n_value;
|
||
|
unsigned char n_sclass;
|
||
|
unsigned char n_numaux;
|
||
|
unsigned char n_type;
|
||
|
};
|
||
|
|
||
|
/* Low bits of storage class (section). */
|
||
|
#define O_N_SECT 07 /* section mask */
|
||
|
#define O_N_UNDF 00 /* undefined */
|
||
|
#define O_N_ABS 01 /* absolute */
|
||
|
#define O_N_TEXT 02 /* text */
|
||
|
#define O_N_DATA 03 /* data */
|
||
|
#define O_N_BSS 04 /* bss */
|
||
|
#define O_N_COMM 05 /* (common) */
|
||
|
|
||
|
/* High bits of storage class. */
|
||
|
#define O_N_CLASS 0370 /* storage class mask */
|
||
|
#define O_C_NULL
|
||
|
#define O_C_EXT 0020 /* external symbol */
|
||
|
#define O_C_STAT 0030 /* static */
|
||
|
#endif
|
||
|
|
||
|
int read_nlist(filename, nlist_table)
|
||
|
const char *filename;
|
||
|
struct nlist **nlist_table;
|
||
|
{
|
||
|
int r, n_entries, save_err;
|
||
|
u32_t (*cnv32) _ARGS(( u32_t *addr ));
|
||
|
u16_t (*cnv16) _ARGS(( u16_t *addr ));
|
||
|
struct nlist *nlist_p, *nlist_ptr;
|
||
|
int exec_fd;
|
||
|
struct exec exec_header;
|
||
|
#ifndef USE_OLD_NLIST
|
||
|
struct old_nlist *old_nlist, *old_nlist_p;
|
||
|
void *old_nlist_end;
|
||
|
#endif
|
||
|
char *str_tab, *str_base, *str_null;
|
||
|
u32_t string_siz;
|
||
|
|
||
|
exec_fd= open(filename, O_RDONLY);
|
||
|
if (exec_fd == -1) /* No executable present */
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
r= read(exec_fd, (char *)&exec_header, A_MINHDR);
|
||
|
if (r != A_MINHDR)
|
||
|
{
|
||
|
if (r != -1)
|
||
|
errno= ENOEXEC;
|
||
|
return -1;
|
||
|
}
|
||
|
if (BADMAG(exec_header))
|
||
|
{
|
||
|
errno= ENOEXEC;
|
||
|
return -1;
|
||
|
}
|
||
|
switch(exec_header.a_cpu & 3)
|
||
|
{
|
||
|
case 0: /* little endian */
|
||
|
cnv32= le32;
|
||
|
cnv16= le16;
|
||
|
break;
|
||
|
case 3: /* big endian */
|
||
|
cnv32= be32;
|
||
|
cnv16= be16;
|
||
|
break;
|
||
|
default:
|
||
|
errno= ENOEXEC;
|
||
|
return -1;
|
||
|
}
|
||
|
exec_header.a_version= cnv16((u16_t *)&exec_header.a_version);
|
||
|
exec_header.a_text= cnv32((u32_t *)&exec_header.a_text);
|
||
|
exec_header.a_data= cnv32((u32_t *)&exec_header.a_data);
|
||
|
exec_header.a_bss= cnv32((u32_t *)&exec_header.a_bss);
|
||
|
exec_header.a_entry= cnv32((u32_t *)&exec_header.a_entry);
|
||
|
exec_header.a_total= cnv32((u32_t *)&exec_header.a_total);
|
||
|
exec_header.a_syms= cnv32((u32_t *)&exec_header.a_syms);
|
||
|
exec_header.a_trsize= cnv32((u32_t *)&exec_header.a_trsize);
|
||
|
exec_header.a_drsize= cnv32((u32_t *)&exec_header.a_drsize);
|
||
|
exec_header.a_tbase= cnv32((u32_t *)&exec_header.a_tbase);
|
||
|
exec_header.a_dbase= cnv32((u32_t *)&exec_header.a_dbase);
|
||
|
|
||
|
if (!exec_header.a_syms)
|
||
|
return 0;
|
||
|
|
||
|
if (exec_header.a_flags & A_NSYM)
|
||
|
{
|
||
|
#if USE_OLD_NLIST
|
||
|
errno= EINVAL;
|
||
|
return -1;
|
||
|
#else
|
||
|
r= lseek(exec_fd, A_SYMPOS(exec_header)+exec_header.a_syms,
|
||
|
SEEK_SET);
|
||
|
if (r == -1)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
r= read(exec_fd, (char *)&string_siz, 4);
|
||
|
if (r != 4)
|
||
|
return -1;
|
||
|
string_siz= cnv32(&string_siz)-4;
|
||
|
nlist_p= malloc(exec_header.a_syms + string_siz+1);
|
||
|
if (!nlist_p)
|
||
|
{
|
||
|
errno= ENOMEM;
|
||
|
return -1;
|
||
|
}
|
||
|
r= lseek(exec_fd, A_SYMPOS(exec_header)+exec_header.a_syms+4,
|
||
|
SEEK_SET);
|
||
|
if (r == -1)
|
||
|
{
|
||
|
save_err= errno;
|
||
|
free(nlist_p);
|
||
|
errno= save_err;
|
||
|
return -1;
|
||
|
}
|
||
|
r= read(exec_fd, ((char *)nlist_p)+exec_header.a_syms,
|
||
|
string_siz);
|
||
|
if (r != string_siz)
|
||
|
{
|
||
|
save_err= errno;
|
||
|
free(nlist_p);
|
||
|
errno= save_err;
|
||
|
return -1;
|
||
|
}
|
||
|
r= lseek(exec_fd, A_SYMPOS(exec_header), SEEK_SET);
|
||
|
if (r == -1)
|
||
|
{
|
||
|
save_err= errno;
|
||
|
free(nlist_p);
|
||
|
errno= save_err;
|
||
|
return -1;
|
||
|
}
|
||
|
r= read(exec_fd, ((char *)nlist_p), exec_header.a_syms);
|
||
|
if (r != exec_header.a_syms)
|
||
|
{
|
||
|
save_err= errno;
|
||
|
free(nlist_p);
|
||
|
errno= save_err;
|
||
|
return -1;
|
||
|
}
|
||
|
str_base= ((char *)nlist_p) + exec_header.a_syms -4;
|
||
|
str_null= (char *)nlist_p + exec_header.a_syms + string_siz;
|
||
|
*str_null= '\0';
|
||
|
for (nlist_ptr= nlist_p; (char *)nlist_ptr+1 <= str_base+4;
|
||
|
nlist_ptr++)
|
||
|
{
|
||
|
nlist_ptr->n_desc= le16((u16_t *)&nlist_ptr->n_desc);
|
||
|
nlist_ptr->n_value= le32(&nlist_ptr->n_value);
|
||
|
if (nlist_ptr->n_un.n_strx)
|
||
|
nlist_ptr->n_un.n_name= str_base+
|
||
|
cnv32((u32_t *)&nlist_ptr->n_un.n_strx);
|
||
|
else
|
||
|
nlist_ptr->n_un.n_name= str_null;
|
||
|
}
|
||
|
*nlist_table= nlist_p;
|
||
|
return nlist_ptr-nlist_p;
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
r= lseek(exec_fd, A_SYMPOS(exec_header), SEEK_SET);
|
||
|
if (r == -1)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
#if USE_OLD_NLIST
|
||
|
n_entries= exec_header.a_syms/sizeof(struct nlist);
|
||
|
nlist_p= malloc(exec_header.a_syms);
|
||
|
if (!nlist_p)
|
||
|
{
|
||
|
free(nlist_p);
|
||
|
errno= ENOMEM;
|
||
|
return -1;
|
||
|
}
|
||
|
r= read(exec_fd, (char *)nlist_p, exec_header.a_syms);
|
||
|
if (r != exec_header.a_syms)
|
||
|
{
|
||
|
save_err= errno;
|
||
|
free(nlist_p);
|
||
|
errno= save_err;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
*nlist_table= nlist_p;
|
||
|
return n_entries;
|
||
|
#else
|
||
|
n_entries= exec_header.a_syms/sizeof(struct old_nlist)+1;
|
||
|
nlist_p= NULL;
|
||
|
old_nlist= NULL;
|
||
|
|
||
|
nlist_p= malloc(n_entries * (sizeof(struct nlist)+
|
||
|
sizeof(old_nlist->n_name)+1));
|
||
|
old_nlist= malloc(exec_header.a_syms);
|
||
|
if (!old_nlist || !nlist_p)
|
||
|
{
|
||
|
if (nlist_p)
|
||
|
free(nlist_p);
|
||
|
if (old_nlist)
|
||
|
free(old_nlist);
|
||
|
errno= ENOMEM;
|
||
|
return -1;
|
||
|
}
|
||
|
r= read(exec_fd, (char *)old_nlist, exec_header.a_syms);
|
||
|
if (r != exec_header.a_syms)
|
||
|
{
|
||
|
save_err= errno;
|
||
|
free(nlist_p);
|
||
|
free(old_nlist);
|
||
|
errno= save_err;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
old_nlist_end= (char *)old_nlist+exec_header.a_syms;
|
||
|
str_tab= (char *)&nlist_p[n_entries];
|
||
|
n_entries= 0;
|
||
|
for (old_nlist_p= old_nlist;
|
||
|
(void *)(old_nlist_p+1)<=old_nlist_end; old_nlist_p++)
|
||
|
{
|
||
|
switch(old_nlist_p->n_sclass & O_N_SECT)
|
||
|
{
|
||
|
case O_N_UNDF:
|
||
|
nlist_p[n_entries].n_type= N_UNDF;
|
||
|
break;
|
||
|
case O_N_ABS:
|
||
|
nlist_p[n_entries].n_type= N_ABS;
|
||
|
break;
|
||
|
case O_N_TEXT:
|
||
|
nlist_p[n_entries].n_type= N_TEXT;
|
||
|
break;
|
||
|
case O_N_DATA:
|
||
|
nlist_p[n_entries].n_type= N_DATA;
|
||
|
break;
|
||
|
case O_N_BSS:
|
||
|
nlist_p[n_entries].n_type= N_BSS;
|
||
|
break;
|
||
|
case O_N_COMM:
|
||
|
nlist_p[n_entries].n_type= N_COMM;
|
||
|
break;
|
||
|
default:
|
||
|
continue;
|
||
|
}
|
||
|
switch(old_nlist_p->n_sclass & O_N_CLASS)
|
||
|
{
|
||
|
case O_C_EXT:
|
||
|
nlist_p[n_entries].n_type |= N_EXT;
|
||
|
case O_C_STAT:
|
||
|
break;
|
||
|
default:
|
||
|
continue;
|
||
|
}
|
||
|
nlist_p[n_entries].n_value=
|
||
|
cnv32((u32_t *)&old_nlist_p->n_value);
|
||
|
nlist_p[n_entries].n_un.n_name= str_tab;
|
||
|
memcpy(str_tab, old_nlist_p->n_name,
|
||
|
sizeof(old_nlist_p->n_name));
|
||
|
str_tab += sizeof(old_nlist_p->n_name);
|
||
|
*str_tab++= '\0';
|
||
|
n_entries++;
|
||
|
}
|
||
|
free(old_nlist);
|
||
|
nlist_p= realloc(nlist_p, str_tab-(char *)nlist_p);
|
||
|
*nlist_table= nlist_p;
|
||
|
return n_entries;
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* $PchId: read_nlist.c,v 1.5 1996/04/11 07:47:38 philip Exp $
|
||
|
*/
|