mirror of
https://github.com/opnsense/src.git
synced 2026-06-05 06:42:56 -04:00
The elf_lookup_symbol function looks up the symbol with a given symbol name. A pointer to the GElf_Sym of the symbol is returned if the symbol exists in the opened ELF file. Sponsored by: Juniper Networks, Inc. Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D46764
694 lines
15 KiB
C
694 lines
15 KiB
C
/*-
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2021-2023 John Baldwin <jhb@FreeBSD.org>
|
|
*
|
|
* This software was developed by SRI International and the University
|
|
* of Cambridge Computer Laboratory (Department of Computer Science
|
|
* and Technology) under Defense Advanced Research Projects Agency
|
|
* (DARPA) contract HR0011-18-C-0016 ("ECATS"), as part of the DARPA
|
|
* SSITH research programme and under DARPA Contract No. HR001123C0031
|
|
* ("MTSS").
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/endian.h>
|
|
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <gelf.h>
|
|
#include <libelf.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "kldelf.h"
|
|
|
|
SET_DECLARE(elf_reloc, struct elf_reloc_data);
|
|
|
|
static elf_reloc_t *
|
|
elf_find_reloc(const GElf_Ehdr *hdr)
|
|
{
|
|
struct elf_reloc_data **erd;
|
|
|
|
SET_FOREACH(erd, elf_reloc) {
|
|
if (hdr->e_ident[EI_CLASS] == (*erd)->class &&
|
|
hdr->e_ident[EI_DATA] == (*erd)->data &&
|
|
hdr->e_machine == (*erd)->machine)
|
|
return ((*erd)->reloc);
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
int
|
|
elf_open_file(struct elf_file *efile, const char *filename, int verbose)
|
|
{
|
|
int error;
|
|
|
|
memset(efile, 0, sizeof(*efile));
|
|
efile->ef_filename = filename;
|
|
efile->ef_fd = open(filename, O_RDONLY);
|
|
if (efile->ef_fd == -1) {
|
|
if (verbose)
|
|
warn("open(%s)", filename);
|
|
return (errno);
|
|
}
|
|
|
|
efile->ef_elf = elf_begin(efile->ef_fd, ELF_C_READ, NULL);
|
|
if (efile->ef_elf == NULL) {
|
|
if (verbose)
|
|
warnx("elf_begin(%s): %s", filename, elf_errmsg(0));
|
|
elf_close_file(efile);
|
|
return (EINVAL);
|
|
}
|
|
|
|
if (elf_kind(efile->ef_elf) != ELF_K_ELF) {
|
|
if (verbose)
|
|
warnx("%s: not an ELF file", filename);
|
|
elf_close_file(efile);
|
|
return (EINVAL);
|
|
}
|
|
|
|
if (gelf_getehdr(efile->ef_elf, &efile->ef_hdr) == NULL) {
|
|
if (verbose)
|
|
warnx("gelf_getehdr(%s): %s", filename, elf_errmsg(0));
|
|
elf_close_file(efile);
|
|
return (EINVAL);
|
|
}
|
|
|
|
efile->ef_reloc = elf_find_reloc(&efile->ef_hdr);
|
|
if (efile->ef_reloc == NULL) {
|
|
if (verbose)
|
|
warnx("%s: unsupported architecture", filename);
|
|
elf_close_file(efile);
|
|
return (EFTYPE);
|
|
}
|
|
|
|
error = ef_open(efile, verbose);
|
|
if (error != 0) {
|
|
error = ef_obj_open(efile, verbose);
|
|
if (error != 0) {
|
|
if (verbose)
|
|
warnc(error, "%s: not a valid DSO or object file",
|
|
filename);
|
|
elf_close_file(efile);
|
|
return (error);
|
|
}
|
|
}
|
|
|
|
efile->ef_pointer_size = elf_object_size(efile, ELF_T_ADDR);
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
elf_close_file(struct elf_file *efile)
|
|
{
|
|
if (efile->ef_ops != NULL) {
|
|
EF_CLOSE(efile);
|
|
}
|
|
if (efile->ef_elf != NULL) {
|
|
elf_end(efile->ef_elf);
|
|
efile->ef_elf = NULL;
|
|
}
|
|
if (efile->ef_fd > 0) {
|
|
close(efile->ef_fd);
|
|
efile->ef_fd = -1;
|
|
}
|
|
}
|
|
|
|
bool
|
|
elf_compatible(struct elf_file *efile, const GElf_Ehdr *hdr)
|
|
{
|
|
if (efile->ef_hdr.e_ident[EI_CLASS] != hdr->e_ident[EI_CLASS] ||
|
|
efile->ef_hdr.e_ident[EI_DATA] != hdr->e_ident[EI_DATA] ||
|
|
efile->ef_hdr.e_machine != hdr->e_machine)
|
|
return (false);
|
|
return (true);
|
|
}
|
|
|
|
size_t
|
|
elf_object_size(struct elf_file *efile, Elf_Type type)
|
|
{
|
|
return (gelf_fsize(efile->ef_elf, type, 1, efile->ef_hdr.e_version));
|
|
}
|
|
|
|
/*
|
|
* The number of objects of 'type' in region of the file of size
|
|
* 'file_size'.
|
|
*/
|
|
static size_t
|
|
elf_object_count(struct elf_file *efile, Elf_Type type, size_t file_size)
|
|
{
|
|
return (file_size / elf_object_size(efile, type));
|
|
}
|
|
|
|
int
|
|
elf_read_raw_data(struct elf_file *efile, off_t offset, void *dst, size_t len)
|
|
{
|
|
ssize_t nread;
|
|
|
|
nread = pread(efile->ef_fd, dst, len, offset);
|
|
if (nread == -1)
|
|
return (errno);
|
|
if (nread != len)
|
|
return (EIO);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_raw_data_alloc(struct elf_file *efile, off_t offset, size_t len,
|
|
void **out)
|
|
{
|
|
void *buf;
|
|
int error;
|
|
|
|
buf = malloc(len);
|
|
if (buf == NULL)
|
|
return (ENOMEM);
|
|
error = elf_read_raw_data(efile, offset, buf, len);
|
|
if (error != 0) {
|
|
free(buf);
|
|
return (error);
|
|
}
|
|
*out = buf;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_raw_string(struct elf_file *efile, off_t offset, char *dst, size_t len)
|
|
{
|
|
ssize_t nread;
|
|
|
|
nread = pread(efile->ef_fd, dst, len, offset);
|
|
if (nread == -1)
|
|
return (errno);
|
|
if (nread == 0)
|
|
return (EIO);
|
|
|
|
/* A short read is ok so long as the data contains a terminator. */
|
|
if (strnlen(dst, nread) == nread)
|
|
return (EFAULT);
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_data(struct elf_file *efile, Elf_Type type, off_t offset, size_t len,
|
|
void **out)
|
|
{
|
|
Elf_Data dst, src;
|
|
void *buf;
|
|
int error;
|
|
|
|
buf = malloc(len);
|
|
if (buf == NULL)
|
|
return (ENOMEM);
|
|
|
|
error = elf_read_raw_data(efile, offset, buf, len);
|
|
if (error != 0) {
|
|
free(buf);
|
|
return (error);
|
|
}
|
|
|
|
memset(&dst, 0, sizeof(dst));
|
|
memset(&src, 0, sizeof(src));
|
|
|
|
src.d_buf = buf;
|
|
src.d_size = len;
|
|
src.d_type = type;
|
|
src.d_version = efile->ef_hdr.e_version;
|
|
|
|
dst.d_buf = buf;
|
|
dst.d_size = len;
|
|
dst.d_version = EV_CURRENT;
|
|
|
|
if (gelf_xlatetom(efile->ef_elf, &dst, &src, elf_encoding(efile)) ==
|
|
NULL) {
|
|
free(buf);
|
|
return (ENXIO);
|
|
}
|
|
|
|
if (dst.d_size != len)
|
|
warnx("elf_read_data: translation of type %u size mismatch",
|
|
type);
|
|
|
|
*out = buf;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_relocated_data(struct elf_file *efile, GElf_Addr address, size_t len,
|
|
void **buf)
|
|
{
|
|
int error;
|
|
void *p;
|
|
|
|
p = malloc(len);
|
|
if (p == NULL)
|
|
return (ENOMEM);
|
|
error = EF_SEG_READ_REL(efile, address, len, p);
|
|
if (error != 0) {
|
|
free(p);
|
|
return (error);
|
|
}
|
|
*buf = p;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_phdrs(struct elf_file *efile, size_t *nphdrp, GElf_Phdr **phdrp)
|
|
{
|
|
GElf_Phdr *phdr;
|
|
size_t nphdr, i;
|
|
int error;
|
|
|
|
if (elf_getphdrnum(efile->ef_elf, &nphdr) == -1)
|
|
return (EFTYPE);
|
|
|
|
phdr = calloc(nphdr, sizeof(*phdr));
|
|
if (phdr == NULL)
|
|
return (ENOMEM);
|
|
|
|
for (i = 0; i < nphdr; i++) {
|
|
if (gelf_getphdr(efile->ef_elf, i, &phdr[i]) == NULL) {
|
|
error = EFTYPE;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
*nphdrp = nphdr;
|
|
*phdrp = phdr;
|
|
return (0);
|
|
out:
|
|
free(phdr);
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
elf_read_shdrs(struct elf_file *efile, size_t *nshdrp, GElf_Shdr **shdrp)
|
|
{
|
|
GElf_Shdr *shdr;
|
|
Elf_Scn *scn;
|
|
size_t nshdr, i;
|
|
int error;
|
|
|
|
if (elf_getshdrnum(efile->ef_elf, &nshdr) == -1)
|
|
return (EFTYPE);
|
|
|
|
shdr = calloc(nshdr, sizeof(*shdr));
|
|
if (shdr == NULL)
|
|
return (ENOMEM);
|
|
|
|
for (i = 0; i < nshdr; i++) {
|
|
scn = elf_getscn(efile->ef_elf, i);
|
|
if (scn == NULL) {
|
|
error = EFTYPE;
|
|
goto out;
|
|
}
|
|
if (gelf_getshdr(scn, &shdr[i]) == NULL) {
|
|
error = EFTYPE;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
*nshdrp = nshdr;
|
|
*shdrp = shdr;
|
|
return (0);
|
|
out:
|
|
free(shdr);
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
elf_read_dynamic(struct elf_file *efile, int section_index, size_t *ndynp,
|
|
GElf_Dyn **dynp)
|
|
{
|
|
GElf_Shdr shdr;
|
|
Elf_Scn *scn;
|
|
Elf_Data *data;
|
|
GElf_Dyn *dyn;
|
|
long i, ndyn;
|
|
|
|
scn = elf_getscn(efile->ef_elf, section_index);
|
|
if (scn == NULL)
|
|
return (EINVAL);
|
|
if (gelf_getshdr(scn, &shdr) == NULL)
|
|
return (EINVAL);
|
|
data = elf_getdata(scn, NULL);
|
|
if (data == NULL)
|
|
return (EINVAL);
|
|
|
|
ndyn = elf_object_count(efile, ELF_T_DYN, shdr.sh_size);
|
|
dyn = calloc(ndyn, sizeof(*dyn));
|
|
if (dyn == NULL)
|
|
return (ENOMEM);
|
|
|
|
for (i = 0; i < ndyn; i++) {
|
|
if (gelf_getdyn(data, i, &dyn[i]) == NULL) {
|
|
free(dyn);
|
|
return (EINVAL);
|
|
}
|
|
}
|
|
|
|
*ndynp = ndyn;
|
|
*dynp = dyn;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_symbols(struct elf_file *efile, int section_index, size_t *nsymp,
|
|
GElf_Sym **symp)
|
|
{
|
|
GElf_Shdr shdr;
|
|
Elf_Scn *scn;
|
|
Elf_Data *data;
|
|
GElf_Sym *sym;
|
|
size_t i, nsym;
|
|
|
|
scn = elf_getscn(efile->ef_elf, section_index);
|
|
if (scn == NULL)
|
|
return (EINVAL);
|
|
if (gelf_getshdr(scn, &shdr) == NULL)
|
|
return (EINVAL);
|
|
data = elf_getdata(scn, NULL);
|
|
if (data == NULL)
|
|
return (EINVAL);
|
|
|
|
nsym = elf_object_count(efile, ELF_T_SYM, shdr.sh_size);
|
|
sym = calloc(nsym, sizeof(*sym));
|
|
if (sym == NULL)
|
|
return (ENOMEM);
|
|
|
|
for (i = 0; i < nsym; i++) {
|
|
if (gelf_getsym(data, i, &sym[i]) == NULL) {
|
|
free(sym);
|
|
return (EINVAL);
|
|
}
|
|
}
|
|
|
|
*nsymp = nsym;
|
|
*symp = sym;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_string_table(struct elf_file *efile, const GElf_Shdr *shdr,
|
|
long *strcnt, char **strtab)
|
|
{
|
|
int error;
|
|
|
|
if (shdr->sh_type != SHT_STRTAB)
|
|
return (EINVAL);
|
|
error = elf_read_raw_data_alloc(efile, shdr->sh_offset, shdr->sh_size,
|
|
(void **)strtab);
|
|
if (error != 0)
|
|
return (error);
|
|
*strcnt = shdr->sh_size;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_rel(struct elf_file *efile, int section_index, long *nrelp,
|
|
GElf_Rel **relp)
|
|
{
|
|
GElf_Shdr shdr;
|
|
Elf_Scn *scn;
|
|
Elf_Data *data;
|
|
GElf_Rel *rel;
|
|
long i, nrel;
|
|
|
|
scn = elf_getscn(efile->ef_elf, section_index);
|
|
if (scn == NULL)
|
|
return (EINVAL);
|
|
if (gelf_getshdr(scn, &shdr) == NULL)
|
|
return (EINVAL);
|
|
data = elf_getdata(scn, NULL);
|
|
if (data == NULL)
|
|
return (EINVAL);
|
|
|
|
nrel = elf_object_count(efile, ELF_T_REL, shdr.sh_size);
|
|
rel = calloc(nrel, sizeof(*rel));
|
|
if (rel == NULL)
|
|
return (ENOMEM);
|
|
|
|
for (i = 0; i < nrel; i++) {
|
|
if (gelf_getrel(data, i, &rel[i]) == NULL) {
|
|
free(rel);
|
|
return (EINVAL);
|
|
}
|
|
}
|
|
|
|
*nrelp = nrel;
|
|
*relp = rel;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_rela(struct elf_file *efile, int section_index, long *nrelap,
|
|
GElf_Rela **relap)
|
|
{
|
|
GElf_Shdr shdr;
|
|
Elf_Scn *scn;
|
|
Elf_Data *data;
|
|
GElf_Rela *rela;
|
|
long i, nrela;
|
|
|
|
scn = elf_getscn(efile->ef_elf, section_index);
|
|
if (scn == NULL)
|
|
return (EINVAL);
|
|
if (gelf_getshdr(scn, &shdr) == NULL)
|
|
return (EINVAL);
|
|
data = elf_getdata(scn, NULL);
|
|
if (data == NULL)
|
|
return (EINVAL);
|
|
|
|
nrela = elf_object_count(efile, ELF_T_RELA, shdr.sh_size);
|
|
rela = calloc(nrela, sizeof(*rela));
|
|
if (rela == NULL)
|
|
return (ENOMEM);
|
|
|
|
for (i = 0; i < nrela; i++) {
|
|
if (gelf_getrela(data, i, &rela[i]) == NULL) {
|
|
free(rela);
|
|
return (EINVAL);
|
|
}
|
|
}
|
|
|
|
*nrelap = nrela;
|
|
*relap = rela;
|
|
return (0);
|
|
}
|
|
|
|
size_t
|
|
elf_pointer_size(struct elf_file *efile)
|
|
{
|
|
return (efile->ef_pointer_size);
|
|
}
|
|
|
|
int
|
|
elf_int(struct elf_file *efile, const void *p)
|
|
{
|
|
if (elf_encoding(efile) == ELFDATA2LSB)
|
|
return (le32dec(p));
|
|
else
|
|
return (be32dec(p));
|
|
}
|
|
|
|
GElf_Addr
|
|
elf_address_from_pointer(struct elf_file *efile, const void *p)
|
|
{
|
|
switch (elf_class(efile)) {
|
|
case ELFCLASS32:
|
|
if (elf_encoding(efile) == ELFDATA2LSB)
|
|
return (le32dec(p));
|
|
else
|
|
return (be32dec(p));
|
|
case ELFCLASS64:
|
|
if (elf_encoding(efile) == ELFDATA2LSB)
|
|
return (le64dec(p));
|
|
else
|
|
return (be64dec(p));
|
|
default:
|
|
__unreachable();
|
|
}
|
|
}
|
|
|
|
int
|
|
elf_read_string(struct elf_file *efile, GElf_Addr address, void *dst,
|
|
size_t len)
|
|
{
|
|
return (EF_SEG_READ_STRING(efile, address, len, dst));
|
|
}
|
|
|
|
int
|
|
elf_read_linker_set(struct elf_file *efile, const char *name, GElf_Addr **bufp,
|
|
long *countp)
|
|
{
|
|
GElf_Addr *buf, start, stop;
|
|
char *p;
|
|
void *raw;
|
|
long i, count;
|
|
int error;
|
|
|
|
error = EF_LOOKUP_SET(efile, name, &start, &stop, &count);
|
|
if (error != 0)
|
|
return (error);
|
|
|
|
error = elf_read_relocated_data(efile, start,
|
|
count * elf_pointer_size(efile), &raw);
|
|
if (error != 0)
|
|
return (error);
|
|
|
|
buf = calloc(count, sizeof(*buf));
|
|
if (buf == NULL) {
|
|
free(raw);
|
|
return (ENOMEM);
|
|
}
|
|
|
|
p = raw;
|
|
for (i = 0; i < count; i++) {
|
|
buf[i] = elf_address_from_pointer(efile, p);
|
|
p += elf_pointer_size(efile);
|
|
}
|
|
free(raw);
|
|
|
|
*bufp = buf;
|
|
*countp = count;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_mod_depend(struct elf_file *efile, GElf_Addr addr,
|
|
struct Gmod_depend *mdp)
|
|
{
|
|
int *p;
|
|
int error;
|
|
|
|
error = elf_read_relocated_data(efile, addr, sizeof(int) * 3,
|
|
(void **)&p);
|
|
if (error != 0)
|
|
return (error);
|
|
|
|
memset(mdp, 0, sizeof(*mdp));
|
|
mdp->md_ver_minimum = elf_int(efile, p);
|
|
mdp->md_ver_preferred = elf_int(efile, p + 1);
|
|
mdp->md_ver_maximum = elf_int(efile, p + 2);
|
|
free(p);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_mod_version(struct elf_file *efile, GElf_Addr addr,
|
|
struct Gmod_version *mdv)
|
|
{
|
|
int error, value;
|
|
|
|
error = EF_SEG_READ_REL(efile, addr, sizeof(int), &value);
|
|
if (error != 0)
|
|
return (error);
|
|
|
|
memset(mdv, 0, sizeof(*mdv));
|
|
mdv->mv_version = elf_int(efile, &value);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_mod_metadata(struct elf_file *efile, GElf_Addr addr,
|
|
struct Gmod_metadata *md)
|
|
{
|
|
char *p;
|
|
size_t len, offset, pointer_size;
|
|
int error;
|
|
|
|
pointer_size = elf_pointer_size(efile);
|
|
len = 2 * sizeof(int);
|
|
len = roundup(len, pointer_size);
|
|
len += 2 * pointer_size;
|
|
|
|
error = elf_read_relocated_data(efile, addr, len, (void **)&p);
|
|
if (error != 0)
|
|
return (error);
|
|
|
|
memset(md, 0, sizeof(*md));
|
|
offset = 0;
|
|
md->md_version = elf_int(efile, p + offset);
|
|
offset += sizeof(int);
|
|
md->md_type = elf_int(efile, p + offset);
|
|
offset += sizeof(int);
|
|
offset = roundup(offset, pointer_size);
|
|
md->md_data = elf_address_from_pointer(efile, p + offset);
|
|
offset += pointer_size;
|
|
md->md_cval = elf_address_from_pointer(efile, p + offset);
|
|
free(p);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_read_mod_pnp_match_info(struct elf_file *efile, GElf_Addr addr,
|
|
struct Gmod_pnp_match_info *pnp)
|
|
{
|
|
char *p;
|
|
size_t len, offset, pointer_size;
|
|
int error;
|
|
|
|
pointer_size = elf_pointer_size(efile);
|
|
len = 3 * pointer_size;
|
|
len = roundup(len, pointer_size);
|
|
len += 2 * sizeof(int);
|
|
|
|
error = elf_read_relocated_data(efile, addr, len, (void **)&p);
|
|
if (error != 0)
|
|
return (error);
|
|
|
|
memset(pnp, 0, sizeof(*pnp));
|
|
offset = 0;
|
|
pnp->descr = elf_address_from_pointer(efile, p + offset);
|
|
offset += pointer_size;
|
|
pnp->bus = elf_address_from_pointer(efile, p + offset);
|
|
offset += pointer_size;
|
|
pnp->table = elf_address_from_pointer(efile, p + offset);
|
|
offset += pointer_size;
|
|
offset = roundup(offset, pointer_size);
|
|
pnp->entry_len = elf_int(efile, p + offset);
|
|
offset += sizeof(int);
|
|
pnp->num_entry = elf_int(efile, p + offset);
|
|
free(p);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elf_reloc(struct elf_file *efile, const void *reldata, Elf_Type reltype,
|
|
GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
|
|
{
|
|
return (efile->ef_reloc(efile, reldata, reltype, relbase, dataoff, len,
|
|
dest));
|
|
}
|
|
|
|
int
|
|
elf_lookup_symbol(struct elf_file *efile, const char *name, GElf_Sym **sym)
|
|
{
|
|
return (EF_LOOKUP_SYMBOL(efile, name, sym));
|
|
}
|