Call the file format specific code through a table of function
pointers and remove knowledge of the file format from kldxref.c. This will make it possible to support more than one file format.
This commit is contained in:
parent
8ae136ae71
commit
9772dc2aff
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=134358
@ -48,11 +48,70 @@
|
||||
|
||||
#include "ef.h"
|
||||
|
||||
struct ef_file {
|
||||
char* ef_name;
|
||||
struct elf_file *ef_efile;
|
||||
Elf_Phdr * ef_ph;
|
||||
int ef_fd;
|
||||
int ef_type;
|
||||
Elf_Ehdr ef_hdr;
|
||||
void* ef_fpage; /* First block of the file */
|
||||
int ef_fplen; /* length of first block */
|
||||
Elf_Dyn* ef_dyn; /* Symbol table etc. */
|
||||
Elf_Hashelt ef_nbuckets;
|
||||
Elf_Hashelt ef_nchains;
|
||||
Elf_Hashelt* ef_buckets;
|
||||
Elf_Hashelt* ef_chains;
|
||||
Elf_Hashelt* ef_hashtab;
|
||||
Elf_Off ef_stroff;
|
||||
caddr_t ef_strtab;
|
||||
int ef_strsz;
|
||||
Elf_Off ef_symoff;
|
||||
Elf_Sym* ef_symtab;
|
||||
int ef_nsegs;
|
||||
Elf_Phdr * ef_segs[2];
|
||||
int ef_verbose;
|
||||
Elf_Rel * ef_rel; /* relocation table */
|
||||
int ef_relsz; /* number of entries */
|
||||
Elf_Rela * ef_rela; /* relocation table */
|
||||
int ef_relasz; /* number of entries */
|
||||
};
|
||||
|
||||
static void ef_print_phdr(Elf_Phdr *);
|
||||
static u_long ef_get_offset(elf_file_t, Elf_Off);
|
||||
static int ef_parse_dynamic(elf_file_t);
|
||||
|
||||
void
|
||||
static int ef_get_type(elf_file_t ef);
|
||||
static int ef_close(elf_file_t ef);
|
||||
static int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest);
|
||||
static int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr);
|
||||
static int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
|
||||
static int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len,
|
||||
void *dest);
|
||||
static int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
|
||||
void **ptr);
|
||||
static int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
|
||||
void **ptr);
|
||||
static Elf_Addr ef_symaddr(elf_file_t ef, Elf_Word symidx);
|
||||
static int ef_lookup_set(elf_file_t ef, const char *name, long *startp,
|
||||
long *stopp, long *countp);
|
||||
static int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym);
|
||||
|
||||
static struct elf_file_ops ef_file_ops = {
|
||||
ef_get_type,
|
||||
ef_close,
|
||||
ef_read,
|
||||
ef_read_entry,
|
||||
ef_seg_read,
|
||||
ef_seg_read_rel,
|
||||
ef_seg_read_entry,
|
||||
ef_seg_read_entry_rel,
|
||||
ef_symaddr,
|
||||
ef_lookup_set,
|
||||
ef_lookup_symbol
|
||||
};
|
||||
|
||||
static void
|
||||
ef_print_phdr(Elf_Phdr *phdr)
|
||||
{
|
||||
|
||||
@ -66,7 +125,7 @@ ef_print_phdr(Elf_Phdr *phdr)
|
||||
}
|
||||
}
|
||||
|
||||
u_long
|
||||
static u_long
|
||||
ef_get_offset(elf_file_t ef, Elf_Off off)
|
||||
{
|
||||
Elf_Phdr *ph;
|
||||
@ -81,6 +140,13 @@ ef_get_offset(elf_file_t ef, Elf_Off off)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ef_get_type(elf_file_t ef)
|
||||
{
|
||||
|
||||
return (ef->ef_type);
|
||||
}
|
||||
|
||||
/*
|
||||
* next three functions copied from link_elf.c
|
||||
*/
|
||||
@ -100,7 +166,7 @@ elf_hash(const char *name)
|
||||
return h;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
|
||||
{
|
||||
unsigned long symnum;
|
||||
@ -144,7 +210,57 @@ ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
ef_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp,
|
||||
long *countp)
|
||||
{
|
||||
Elf_Sym *sym;
|
||||
char *setsym;
|
||||
int error, len;
|
||||
|
||||
len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */
|
||||
setsym = malloc(len);
|
||||
if (setsym == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/* get address of first entry */
|
||||
snprintf(setsym, len, "%s%s", "__start_set_", name);
|
||||
error = ef_lookup_symbol(ef, setsym, &sym);
|
||||
if (error)
|
||||
goto out;
|
||||
*startp = sym->st_value;
|
||||
|
||||
/* get address of last entry */
|
||||
snprintf(setsym, len, "%s%s", "__stop_set_", name);
|
||||
error = ef_lookup_symbol(ef, setsym, &sym);
|
||||
if (error)
|
||||
goto out;
|
||||
*stopp = sym->st_value;
|
||||
|
||||
/* and the number of entries */
|
||||
*countp = (*stopp - *startp) / sizeof(void *);
|
||||
|
||||
out:
|
||||
free(setsym);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static Elf_Addr
|
||||
ef_symaddr(elf_file_t ef, Elf_Word symidx)
|
||||
{
|
||||
const Elf_Sym *sym;
|
||||
|
||||
if (symidx >= ef->ef_nchains)
|
||||
return (0);
|
||||
sym = ef->ef_symtab + symidx;
|
||||
|
||||
if (ELF_ST_BIND(sym->st_info) == STB_LOCAL &&
|
||||
sym->st_shndx != SHN_UNDEF && sym->st_value != 0)
|
||||
return (sym->st_value);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ef_parse_dynamic(elf_file_t ef)
|
||||
{
|
||||
Elf_Dyn *dp;
|
||||
@ -302,7 +418,7 @@ ef_parse_dynamic(elf_file_t ef)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
ef_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
|
||||
{
|
||||
ssize_t r;
|
||||
@ -319,7 +435,7 @@ ef_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
|
||||
return EIO;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
|
||||
{
|
||||
int error;
|
||||
@ -333,7 +449,7 @@ ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
|
||||
{
|
||||
u_long ofs = ef_get_offset(ef, offset);
|
||||
@ -347,10 +463,12 @@ ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
|
||||
return ef_read(ef, ofs, len, dest);
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
|
||||
{
|
||||
u_long ofs = ef_get_offset(ef, offset);
|
||||
const Elf_Rela *a;
|
||||
const Elf_Rel *r;
|
||||
int error;
|
||||
|
||||
if (ofs == 0) {
|
||||
@ -361,10 +479,23 @@ ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
|
||||
}
|
||||
if ((error = ef_read(ef, ofs, len, dest)) != 0)
|
||||
return (error);
|
||||
return (ef_reloc(ef, offset, len, dest));
|
||||
|
||||
for (r = ef->ef_rel; r < &ef->ef_rel[ef->ef_relsz]; r++) {
|
||||
error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, offset, len,
|
||||
dest);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) {
|
||||
error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, offset, len,
|
||||
dest);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
|
||||
{
|
||||
int error;
|
||||
@ -378,7 +509,7 @@ ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
|
||||
{
|
||||
int error;
|
||||
@ -393,8 +524,9 @@ ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
|
||||
}
|
||||
|
||||
int
|
||||
ef_open(const char *filename, elf_file_t ef, int verbose)
|
||||
ef_open(const char *filename, struct elf_file *efile, int verbose)
|
||||
{
|
||||
elf_file_t ef;
|
||||
Elf_Ehdr *hdr;
|
||||
int fd;
|
||||
int error;
|
||||
@ -402,14 +534,25 @@ ef_open(const char *filename, elf_file_t ef, int verbose)
|
||||
int nsegs;
|
||||
Elf_Phdr *phdr, *phdyn, *phphdr, *phlimit;
|
||||
|
||||
bzero(ef, sizeof(*ef));
|
||||
if (filename == NULL)
|
||||
return EFTYPE;
|
||||
ef->ef_verbose = verbose;
|
||||
if ((fd = open(filename, O_RDONLY)) == -1)
|
||||
return errno;
|
||||
|
||||
ef = malloc(sizeof(*ef));
|
||||
if (ef == NULL) {
|
||||
close(fd);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
efile->ef_ef = ef;
|
||||
efile->ef_ops = &ef_file_ops;
|
||||
|
||||
bzero(ef, sizeof(*ef));
|
||||
ef->ef_verbose = verbose;
|
||||
ef->ef_fd = fd;
|
||||
ef->ef_name = strdup(filename);
|
||||
ef->ef_efile = efile;
|
||||
hdr = (Elf_Ehdr *)&ef->ef_hdr;
|
||||
do {
|
||||
res = read(fd, hdr, sizeof(*hdr));
|
||||
@ -485,15 +628,12 @@ ef_open(const char *filename, elf_file_t ef, int verbose)
|
||||
} else
|
||||
break;
|
||||
} while(0);
|
||||
if (error) {
|
||||
if (error)
|
||||
ef_close(ef);
|
||||
if (ef->ef_verbose)
|
||||
warnc(error, "elf_open(%s)", filename);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
ef_close(elf_file_t ef)
|
||||
{
|
||||
close(ef->ef_fd);
|
||||
@ -501,5 +641,8 @@ ef_close(elf_file_t ef)
|
||||
free(ef->ef_fpage);*/
|
||||
if (ef->ef_name)
|
||||
free(ef->ef_name);
|
||||
ef->ef_efile->ef_ops = NULL;
|
||||
ef->ef_efile->ef_ef = NULL;
|
||||
free(ef);
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,45 +6,64 @@
|
||||
#define EFT_KLD 1
|
||||
#define EFT_KERNEL 2
|
||||
|
||||
typedef struct elf_file {
|
||||
char* ef_name;
|
||||
Elf_Phdr * ef_ph;
|
||||
int ef_fd;
|
||||
int ef_type;
|
||||
Elf_Ehdr ef_hdr;
|
||||
void* ef_fpage; /* First block of the file */
|
||||
int ef_fplen; /* length of first block */
|
||||
Elf_Dyn* ef_dyn; /* Symbol table etc. */
|
||||
Elf_Hashelt ef_nbuckets;
|
||||
Elf_Hashelt ef_nchains;
|
||||
Elf_Hashelt* ef_buckets;
|
||||
Elf_Hashelt* ef_chains;
|
||||
Elf_Hashelt* ef_hashtab;
|
||||
Elf_Off ef_stroff;
|
||||
caddr_t ef_strtab;
|
||||
int ef_strsz;
|
||||
Elf_Off ef_symoff;
|
||||
Elf_Sym* ef_symtab;
|
||||
int ef_nsegs;
|
||||
Elf_Phdr * ef_segs[2];
|
||||
int ef_verbose;
|
||||
Elf_Rel * ef_rel; /* relocation table */
|
||||
int ef_relsz; /* number of entries */
|
||||
Elf_Rela * ef_rela; /* relocation table */
|
||||
int ef_relasz; /* number of entries */
|
||||
} *elf_file_t;
|
||||
#define EF_RELOC_REL 1
|
||||
#define EF_RELOC_RELA 2
|
||||
|
||||
#define EF_GET_TYPE(ef) \
|
||||
(ef)->ef_ops->get_type((ef)->ef_ef)
|
||||
#define EF_CLOSE(ef) \
|
||||
(ef)->ef_ops->close((ef)->ef_ef)
|
||||
#define EF_READ(ef, offset, len, dest) \
|
||||
(ef)->ef_ops->read((ef)->ef_ef, offset, len, dest)
|
||||
#define EF_READ_ENTRY(ef, offset, len, ptr) \
|
||||
(ef)->ef_ops->read_entry((ef)->ef_ef, offset, len, ptr)
|
||||
#define EF_SEG_READ(ef, offset, len, dest) \
|
||||
(ef)->ef_ops->seg_read((ef)->ef_ef, offset, len, dest)
|
||||
#define EF_SEG_READ_REL(ef, offset, len, dest) \
|
||||
(ef)->ef_ops->seg_read_rel((ef)->ef_ef, offset, len, dest)
|
||||
#define EF_SEG_READ_ENTRY(ef, offset, len, ptr) \
|
||||
(ef)->ef_ops->seg_read_entry((ef)->kf_ef, offset, len, ptr)
|
||||
#define EF_SEG_READ_ENTRY_REL(ef, offset, len, ptr) \
|
||||
(ef)->ef_ops->seg_read_entry_rel((ef)->ef_ef, offset, len, ptr)
|
||||
#define EF_SYMADDR(ef, symidx) \
|
||||
(ef)->ef_ops->symaddr((ef)->ef_ef, symidx)
|
||||
#define EF_LOOKUP_SET(ef, name, startp, stopp, countp) \
|
||||
(ef)->ef_ops->lookup_set((ef)->ef_ef, name, startp, stopp, countp)
|
||||
#define EF_LOOKUP_SYMBOL(ef, name, sym) \
|
||||
(ef)->ef_ops->lookup_symbol((ef)->ef_ef, name, sym)
|
||||
|
||||
/* XXX, should have a different name. */
|
||||
typedef struct ef_file *elf_file_t;
|
||||
|
||||
struct elf_file_ops {
|
||||
int (*get_type)(elf_file_t ef);
|
||||
int (*close)(elf_file_t ef);
|
||||
int (*read)(elf_file_t ef, Elf_Off offset, size_t len, void* dest);
|
||||
int (*read_entry)(elf_file_t ef, Elf_Off offset, size_t len,
|
||||
void **ptr);
|
||||
int (*seg_read)(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
|
||||
int (*seg_read_rel)(elf_file_t ef, Elf_Off offset, size_t len,
|
||||
void *dest);
|
||||
int (*seg_read_entry)(elf_file_t ef, Elf_Off offset, size_t len,
|
||||
void**ptr);
|
||||
int (*seg_read_entry_rel)(elf_file_t ef, Elf_Off offset, size_t len,
|
||||
void**ptr);
|
||||
Elf_Addr (*symaddr)(elf_file_t ef, Elf_Word symidx);
|
||||
int (*lookup_set)(elf_file_t ef, const char *name, long *startp,
|
||||
long *stopp, long *countp);
|
||||
int (*lookup_symbol)(elf_file_t ef, const char* name, Elf_Sym** sym);
|
||||
};
|
||||
|
||||
struct elf_file {
|
||||
elf_file_t ef_ef;
|
||||
struct elf_file_ops *ef_ops;
|
||||
};
|
||||
|
||||
__BEGIN_DECLS
|
||||
int ef_open(const char *, elf_file_t, int);
|
||||
int ef_close(elf_file_t ef);
|
||||
int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest);
|
||||
int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr);
|
||||
int ef_reloc(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
|
||||
int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
|
||||
int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
|
||||
int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr);
|
||||
int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr);
|
||||
int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym);
|
||||
int ef_open(const char *filename, struct elf_file *ef, int verbose);
|
||||
int ef_obj_open(const char *filename, struct elf_file *ef, int verbose);
|
||||
int ef_reloc(struct elf_file *ef, const void *data, int type, Elf_Off offset,
|
||||
size_t len, void *dest);
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _EF_H_*/
|
||||
|
@ -32,7 +32,8 @@
|
||||
#include "ef.h"
|
||||
|
||||
int
|
||||
ef_reloc(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
|
||||
ef_reloc(struct elf_file *ef, const void *data, int type, Elf_Off offset,
|
||||
size_t len, void *dest)
|
||||
{
|
||||
|
||||
return (0);
|
||||
|
@ -38,12 +38,15 @@
|
||||
* Apply relocations to the values we got from the file.
|
||||
*/
|
||||
int
|
||||
ef_reloc(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
|
||||
ef_reloc(struct elf_file *ef, const void *data, int type, Elf_Off offset,
|
||||
size_t len, void *dest)
|
||||
{
|
||||
const Elf_Rela *a;
|
||||
Elf_Word w;
|
||||
|
||||
for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) {
|
||||
switch (type) {
|
||||
case EF_RELOC_RELA:
|
||||
a = data;
|
||||
if (a->r_offset >= offset && a->r_offset < offset + len) {
|
||||
switch (ELF_R_TYPE(a->r_info)) {
|
||||
case R_SPARC_RELATIVE:
|
||||
@ -58,6 +61,7 @@ ef_reloc(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
@ -164,12 +164,12 @@ parse_entry(struct mod_metadata *md, const char *cval,
|
||||
case MDT_DEPEND:
|
||||
if (!dflag)
|
||||
break;
|
||||
check(ef_seg_read(ef, data, sizeof(mdp), &mdp));
|
||||
check(EF_SEG_READ(ef, data, sizeof(mdp), &mdp));
|
||||
printf(" depends on %s.%d (%d,%d)\n", cval,
|
||||
mdp.md_ver_preferred, mdp.md_ver_minimum, mdp.md_ver_maximum);
|
||||
break;
|
||||
case MDT_VERSION:
|
||||
check(ef_seg_read(ef, data, sizeof(mdv), &mdv));
|
||||
check(EF_SEG_READ(ef, data, sizeof(mdv), &mdv));
|
||||
record_int(MDT_VERSION);
|
||||
record_string(cval);
|
||||
record_int(mdv.mv_version);
|
||||
@ -202,18 +202,21 @@ read_kld(char *filename, char *kldname)
|
||||
/* struct kld_info *kip;
|
||||
struct mod_info *mip;*/
|
||||
void **p, **orgp;
|
||||
int error, nmlen;
|
||||
int error, eftype, nmlen;
|
||||
long start, finish, entries;
|
||||
Elf_Sym *sym;
|
||||
char kldmodname[MAXMODNAME + 1], cval[MAXMODNAME + 1], *cp;
|
||||
|
||||
if (verbose || dflag)
|
||||
printf("%s\n", filename);
|
||||
error = ef_open(filename, &ef, verbose);
|
||||
if (error)
|
||||
if (error) {
|
||||
if (verbose)
|
||||
warnc(error, "elf_open(%s)", filename);
|
||||
return error;
|
||||
if (ef.ef_type != EFT_KLD && ef.ef_type != EFT_KERNEL) {
|
||||
ef_close(&ef);
|
||||
}
|
||||
eftype = EF_GET_TYPE(&ef);
|
||||
if (eftype != EFT_KLD && eftype != EFT_KERNEL) {
|
||||
EF_CLOSE(&ef);
|
||||
return 0;
|
||||
}
|
||||
if (!dflag) {
|
||||
@ -225,18 +228,17 @@ read_kld(char *filename, char *kldname)
|
||||
/* fprintf(fxref, "%s:%s:%d\n", kldmodname, kldname, 0);*/
|
||||
}
|
||||
do {
|
||||
check(ef_lookup_symbol(&ef, "__start_set_" MDT_SETNAME, &sym));
|
||||
start = sym->st_value;
|
||||
check(ef_lookup_symbol(&ef, "__stop_set_" MDT_SETNAME, &sym));
|
||||
finish = sym->st_value;
|
||||
entries = (finish - start) / sizeof(void *);
|
||||
check(ef_seg_read_entry_rel(&ef, start, sizeof(*p) * entries,
|
||||
check(EF_LOOKUP_SET(&ef, MDT_SETNAME, &start, &finish,
|
||||
&entries));
|
||||
check(EF_SEG_READ_ENTRY_REL(&ef, start, sizeof(*p) * entries,
|
||||
(void *)&p));
|
||||
orgp = p;
|
||||
while(entries--) {
|
||||
check(ef_seg_read_rel(&ef, (Elf_Off)*p, sizeof(md), &md));
|
||||
check(EF_SEG_READ_REL(&ef, (Elf_Off)*p, sizeof(md),
|
||||
&md));
|
||||
p++;
|
||||
check(ef_seg_read(&ef, (Elf_Off)md.md_cval, sizeof(cval), cval));
|
||||
check(EF_SEG_READ(&ef, (Elf_Off)md.md_cval,
|
||||
sizeof(cval), cval));
|
||||
cval[MAXMODNAME] = '\0';
|
||||
parse_entry(&md, cval, &ef, kldname);
|
||||
}
|
||||
@ -244,7 +246,7 @@ read_kld(char *filename, char *kldname)
|
||||
warnc(error, "error while reading %s", filename);
|
||||
free(orgp);
|
||||
} while(0);
|
||||
ef_close(&ef);
|
||||
EF_CLOSE(&ef);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user