/*
** get_nlist.c -- This file contains the routines for getting a symbol
**		  table entry when booting the Amiga Linux kernel.
**
** Copyright 1993 by Hamish Macdonald
**
** This file is subject to the terms and conditions of the GNU General Public
** License.  See the file README.legal in the main directory of this archive
** for more details.
**
*/


#include <stdlib.h>
#include <stdio.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <linux/a.out.h>

struct nlist *get_nlist (const char *fname, const char *symname)
{
    int fd = open (fname, O_RDONLY);
    struct exec ex;
    struct nlist *nl, *p = NULL, *syms;
    char *strs;
    off_t filesize;
    long strsize, numsyms;

    if (fd == -1)
	return NULL;

#ifdef DEBUG
    printf ("fd is %d\n", fd);
#endif

    read (fd, &ex, sizeof(ex));
    if (!ex.a_syms) {
	close (fd);
	return NULL;
    }

#ifdef DEBUG
    printf ("%d bytes of symbol data\n", ex.a_syms);
#endif

    syms = (struct nlist *)malloc (ex.a_syms);
    if (!syms) {
	close (fd);
	return NULL;
    }
    lseek (fd, N_SYMOFF(ex), L_SET);
    read (fd, syms, ex.a_syms);
    numsyms = ex.a_syms / sizeof (struct nlist);
#ifdef DEBUG
    printf ("there are %d symbols\n", numsyms);
#endif

    filesize = lseek (fd, 0L, L_XTND);
#ifdef DEBUG
    printf ("there are %d characters in the file\n", filesize);
#endif
    strsize = filesize - N_STROFF(ex);
#ifdef DEBUG
    printf ("%d characters in the string table\n", strsize);
#endif

    strs = (char *)malloc (strsize);
    if (!strs) {
	free (syms);
	close (fd);
	return NULL;
    }
    lseek (fd, N_STROFF(ex), L_SET);
    read (fd, strs, strsize);

    for (nl = syms; nl < syms + numsyms; nl++) {
#ifdef DEBUG
	printf ("checking symbol number %d, name %s\n",
		nl - syms, strs + nl->n_un.n_strx);
#endif
	if (strcmp (symname, strs + nl->n_un.n_strx) == 0
	    && nl->n_type == N_BSS | N_EXT) {
	    p = (struct nlist *)malloc (sizeof (struct nlist)
					+ strlen(strs + nl->n_un.n_strx) + 1);
	    if (!p)
		break;
	    *p = *nl;
	    p->n_un.n_name = (char *)(p+1);
	    strcpy (p->n_un.n_name, strs + nl->n_un.n_strx);
	}
    }

    free (strs);
    free (syms);
    close (fd);
    return p;
}
