load_elf.c revision 44069
1231858Sbz/*-
2231858Sbz * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3231858Sbz * Copyright (c) 1998 Peter Wemm <peter@freebsd.org>
4231858Sbz * All rights reserved.
5231858Sbz *
6231858Sbz * Redistribution and use in source and binary forms, with or without
7231858Sbz * modification, are permitted provided that the following conditions
8231858Sbz * are met:
9231858Sbz * 1. Redistributions of source code must retain the above copyright
10231858Sbz *    notice, this list of conditions and the following disclaimer.
11231858Sbz * 2. Redistributions in binary form must reproduce the above copyright
12231858Sbz *    notice, this list of conditions and the following disclaimer in the
13231858Sbz *    documentation and/or other materials provided with the distribution.
14231858Sbz *
15231858Sbz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16231858Sbz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17231858Sbz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18231858Sbz * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19231858Sbz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20231858Sbz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21231858Sbz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22231858Sbz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23231858Sbz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24231858Sbz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25231858Sbz * SUCH DAMAGE.
26231858Sbz *
27231858Sbz *	$Id: load_elf.c,v 1.10 1999/01/04 18:37:41 peter Exp $
28231858Sbz */
29231858Sbz
30231858Sbz#include <sys/param.h>
31231858Sbz#include <sys/exec.h>
32231858Sbz#include <sys/reboot.h>
33231858Sbz#include <sys/linker.h>
34231858Sbz#include <string.h>
35231858Sbz#include <machine/bootinfo.h>
36231858Sbz#include <machine/elf.h>
37231858Sbz#include <stand.h>
38231858Sbz#define FREEBSD_ELF
39231858Sbz#include <link.h>
40231858Sbz
41231858Sbz#include "bootstrap.h"
42231858Sbz
43231858Sbzstatic int	elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t loadaddr, Elf_Ehdr *ehdr, int kernel, caddr_t firstpage, int firstlen);
44231858Sbz
45231858Sbzchar	*elf_kerneltype = "elf kernel";
46231858Sbzchar	*elf_moduletype = "elf module";
47231858Sbz
48231858Sbz/*
49231858Sbz * Attempt to load the file (file) as an ELF module.  It will be stored at
50231858Sbz * (dest), and a pointer to a module structure describing the loaded object
51231858Sbz * will be saved in (result).
52231858Sbz */
53231858Sbzint
54231858Sbzelf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result)
55231858Sbz{
56231858Sbz    struct loaded_module	*mp, *kmp;
57231858Sbz    Elf_Ehdr			*ehdr;
58231858Sbz    int				fd;
59231858Sbz    int				err, kernel;
60231858Sbz    u_int			pad;
61231858Sbz    char			*s;
62231858Sbz    caddr_t			firstpage;
63231858Sbz    int				firstlen;
64231858Sbz
65231858Sbz    mp = NULL;
66231858Sbz
67231858Sbz    /*
68231858Sbz     * Open the image, read and validate the ELF header
69231858Sbz     */
70231858Sbz    if (filename == NULL)	/* can't handle nameless */
71231858Sbz	return(EFTYPE);
72231858Sbz    if ((fd = open(filename, O_RDONLY)) == -1)
73232114Sbz	return(errno);
74231858Sbz    firstpage = malloc(PAGE_SIZE);
75231858Sbz    if (firstpage == NULL)
76231858Sbz	return(ENOMEM);
77231858Sbz    firstlen = read(fd, firstpage, PAGE_SIZE);
78231858Sbz    if (firstlen <= sizeof(ehdr)) {
79231858Sbz	err = EFTYPE;		/* could be EIO, but may be small file */
80231858Sbz	goto oerr;
81231858Sbz    }
82231858Sbz    ehdr = (Elf_Ehdr *)firstpage;
83231858Sbz
84231858Sbz    /* Is it ELF? */
85231858Sbz    if (!IS_ELF(*ehdr)) {
86231858Sbz	err = EFTYPE;
87231858Sbz	goto oerr;
88231858Sbz    }
89231858Sbz    if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||	/* Layout ? */
90231858Sbz	ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
91231858Sbz	ehdr->e_ident[EI_VERSION] != EV_CURRENT ||	/* Version ? */
92231858Sbz	ehdr->e_version != EV_CURRENT ||
93231858Sbz	ehdr->e_machine != ELF_TARG_MACH) {		/* Machine ? */
94231858Sbz	err = EFTYPE;
95231858Sbz	goto oerr;
96231858Sbz    }
97231858Sbz
98231858Sbz
99231858Sbz    /*
100231858Sbz     * Check to see what sort of module we are.
101231858Sbz     */
102231858Sbz    kmp = mod_findmodule(NULL, NULL);
103231858Sbz    if (ehdr->e_type == ET_DYN) {
104231858Sbz	/* Looks like a kld module */
105231858Sbz	if (kmp == NULL) {
106231858Sbz	    printf("elf_loadmodule: can't load module before kernel\n");
107231858Sbz	    err = EPERM;
108231858Sbz	    goto oerr;
109231858Sbz	}
110231858Sbz	if (strcmp(elf_kerneltype, kmp->m_type)) {
111231858Sbz	    printf("elf_loadmodule: can't load module with kernel type '%s'\n", kmp->m_type);
112231858Sbz	    err = EPERM;
113231858Sbz	    goto oerr;
114231858Sbz	}
115231858Sbz	/* Looks OK, got ahead */
116231858Sbz	kernel = 0;
117231858Sbz
118231858Sbz	/* Page-align the load address */
119231858Sbz	pad = (u_int)dest & PAGE_MASK;
120231858Sbz	if (pad != 0) {
121231858Sbz	    pad = PAGE_SIZE - pad;
122231858Sbz	    dest += pad;
123231858Sbz	}
124231858Sbz    } else if (ehdr->e_type == ET_EXEC) {
125231858Sbz	/* Looks like a kernel */
126231858Sbz	if (kmp != NULL) {
127231858Sbz	    printf("elf_loadmodule: kernel already loaded\n");
128231858Sbz	    err = EPERM;
129231858Sbz	    goto oerr;
130231858Sbz	}
131231858Sbz	/*
132231858Sbz	 * Calculate destination address based on kernel entrypoint
133231858Sbz	 */
134231858Sbz	dest = (vm_offset_t) ehdr->e_entry;
135231858Sbz	if (dest == 0) {
136231858Sbz	    printf("elf_loadmodule: not a kernel (maybe static binary?)\n");
137231858Sbz	    err = EPERM;
138231858Sbz	    goto oerr;
139231858Sbz	}
140231858Sbz	kernel = 1;
141231858Sbz
142231858Sbz    } else {
143231858Sbz	err = EFTYPE;
144231858Sbz	goto oerr;
145231858Sbz    }
146231858Sbz
147231858Sbz    /*
148231858Sbz     * Ok, we think we should handle this.
149231858Sbz     */
150231858Sbz    mp = mod_allocmodule();
151231858Sbz    if (mp == NULL) {
152231858Sbz	    printf("elf_loadmodule: cannot allocate module info\n");
153231858Sbz	    err = EPERM;
154231858Sbz	    goto out;
155231858Sbz    }
156231858Sbz    if (kernel)
157231858Sbz	setenv("kernelname", filename, 1);
158231858Sbz    s = strrchr(filename, '/');
159231858Sbz    if (s)
160231858Sbz	mp->m_name = strdup(s + 1);
161231858Sbz    else
162231858Sbz	mp->m_name = strdup(filename);
163231858Sbz    mp->m_type = strdup(kernel ? elf_kerneltype : elf_moduletype);
164231858Sbz
165231858Sbz#ifdef ELF_VERBOSE
166231858Sbz    if (kernel)
167231858Sbz	printf("%s entry at %p\n", filename, (void *) dest);
168231858Sbz#else
169231858Sbz    printf("%s ", filename);
170231858Sbz#endif
171231858Sbz
172231858Sbz    mp->m_size = elf_loadimage(mp, fd, dest, ehdr, kernel, firstpage, firstlen);
173231858Sbz    if (mp->m_size == 0 || mp->m_addr == 0)
174231858Sbz	goto ioerr;
175231858Sbz
176231858Sbz    /* save exec header as metadata */
177231858Sbz    mod_addmetadata(mp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr);
178231858Sbz
179231858Sbz    /* Load OK, return module pointer */
180231858Sbz    *result = (struct loaded_module *)mp;
181231858Sbz    err = 0;
182231858Sbz    goto out;
183231858Sbz
184231858Sbz ioerr:
185231858Sbz    err = EIO;
186231858Sbz oerr:
187231858Sbz    mod_discard(mp);
188231858Sbz out:
189231858Sbz    if (firstpage)
190231858Sbz	free(firstpage);
191231858Sbz    close(fd);
192231858Sbz    return(err);
193231858Sbz}
194231858Sbz
195231858Sbz/*
196231858Sbz * With the file (fd) open on the image, and (ehdr) containing
197231858Sbz * the Elf header, load the image at (off)
198231858Sbz */
199231858Sbzstatic int
200231858Sbzelf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off,
201231858Sbz	      Elf_Ehdr *ehdr, int kernel, caddr_t firstpage, int firstlen)
202231858Sbz{
203231858Sbz    int 	i, j;
204231858Sbz    Elf_Phdr	*phdr;
205231858Sbz    Elf_Shdr	*shdr;
206231858Sbz    int		ret;
207231858Sbz    vm_offset_t firstaddr;
208231858Sbz    vm_offset_t lastaddr;
209231858Sbz    void	*buf;
210231858Sbz    size_t	resid, chunk;
211231858Sbz    vm_offset_t	dest;
212231858Sbz    vm_offset_t	ssym, esym;
213231858Sbz    Elf_Dyn	*dp;
214231858Sbz    int		ndp;
215231858Sbz    int		deplen;
216231858Sbz    char	*depdata;
217231858Sbz    char	*s;
218231858Sbz    int		len;
219231858Sbz    char	*strtab;
220231858Sbz    size_t	strsz;
221231858Sbz    int		symstrindex;
222231858Sbz    int		symtabindex;
223231858Sbz    long	size;
224231858Sbz    int		fpcopy;
225231858Sbz
226232114Sbz    dp = NULL;
227231858Sbz    shdr = NULL;
228231858Sbz    ret = 0;
229231858Sbz    firstaddr = lastaddr = 0;
230231858Sbz    if (kernel) {
231231858Sbz#ifdef __i386__
232231858Sbz	off = - (off & 0xff000000u);	/* i386 relocates after locore */
233231858Sbz#else
234231858Sbz	off = 0;		/* alpha is direct mapped for kernels */
235232114Sbz#endif
236232114Sbz    }
237231858Sbz
238232114Sbz    if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > firstlen) {
239231858Sbz	printf("elf_loadimage: program header not within first page\n");
240232114Sbz	goto out;
241231858Sbz    }
242232114Sbz    phdr = (Elf_Phdr *)(firstpage + ehdr->e_phoff);
243231858Sbz
244231858Sbz    for (i = 0; i < ehdr->e_phnum; i++) {
245231858Sbz	/* We want to load PT_LOAD segments only.. */
246231858Sbz	if (phdr[i].p_type != PT_LOAD)
247231858Sbz	    continue;
248232114Sbz
249231858Sbz#ifdef ELF_VERBOSE
250231858Sbz	printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
251231858Sbz	    (long)phdr[i].p_filesz, (long)phdr[i].p_offset,
252231858Sbz	    (long)(phdr[i].p_vaddr + off),
253231858Sbz	    (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
254231858Sbz#else
255231858Sbz	if ((phdr[i].p_flags & PF_W) == 0) {
256231858Sbz	    printf("text=0x%lx ", (long)phdr[i].p_filesz);
257232114Sbz	} else {
258232114Sbz	    printf("data=0x%lx", (long)phdr[i].p_filesz);
259231858Sbz	    if (phdr[i].p_filesz < phdr[i].p_memsz)
260232114Sbz		printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz));
261231858Sbz	    printf(" ");
262232114Sbz	}
263231858Sbz#endif
264232114Sbz	fpcopy = 0;
265231858Sbz	if (firstlen > phdr[i].p_offset) {
266231858Sbz	    fpcopy = firstlen - phdr[i].p_offset;
267231858Sbz	    archsw.arch_copyin(firstpage + phdr[i].p_offset,
268231858Sbz			       phdr[i].p_vaddr + off, fpcopy);
269231858Sbz	}
270232114Sbz	if (phdr[i].p_filesz > fpcopy) {
271231858Sbz	    if (lseek(fd, phdr[i].p_offset + fpcopy, SEEK_SET) == -1) {
272231858Sbz		printf("\nelf_loadexec: cannot seek\n");
273231858Sbz		goto out;
274231858Sbz	    }
275231858Sbz	    if (archsw.arch_readin(fd, phdr[i].p_vaddr + off + fpcopy,
276231858Sbz		phdr[i].p_filesz - fpcopy) != phdr[i].p_filesz - fpcopy) {
277231858Sbz		printf("\nelf_loadexec: archsw.readin failed\n");
278231858Sbz		goto out;
279232114Sbz	    }
280232114Sbz	}
281231858Sbz	/* clear space from oversized segments; eg: bss */
282232114Sbz	if (phdr[i].p_filesz < phdr[i].p_memsz) {
283231858Sbz#ifdef ELF_VERBOSE
284232114Sbz	    printf(" (bss: 0x%lx-0x%lx)",
285231858Sbz		(long)(phdr[i].p_vaddr + off + phdr[i].p_filesz),
286232114Sbz		(long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
287231858Sbz#endif
288231858Sbz
289231858Sbz	    /* no archsw.arch_bzero */
290231858Sbz	    buf = malloc(PAGE_SIZE);
291231858Sbz	    bzero(buf, PAGE_SIZE);
292231858Sbz	    resid = phdr[i].p_memsz - phdr[i].p_filesz;
293231858Sbz	    dest = phdr[i].p_vaddr + off + phdr[i].p_filesz;
294232114Sbz	    while (resid > 0) {
295231858Sbz		chunk = min(PAGE_SIZE, resid);
296231858Sbz		archsw.arch_copyin(buf, dest, chunk);
297231858Sbz		resid -= chunk;
298231858Sbz		dest += chunk;
299231858Sbz	    }
300231858Sbz	    free(buf);
301231858Sbz	}
302231858Sbz#ifdef ELF_VERBOSE
303231858Sbz	printf("\n");
304231858Sbz#endif
305231858Sbz
306232114Sbz	if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off))
307232114Sbz	    firstaddr = phdr[i].p_vaddr + off;
308232114Sbz	if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz))
309232114Sbz	    lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz;
310232114Sbz    }
311231858Sbz    lastaddr = roundup(lastaddr, sizeof(long));
312231858Sbz
313232114Sbz    /*
314232114Sbz     * Now grab the symbol tables.  This isn't easy if we're reading a
315232114Sbz     * .gz file.  I think the rule is going to have to be that you must
316232114Sbz     * strip a file to remove symbols before gzipping it so that we do not
317231858Sbz     * try to lseek() on it.
318232114Sbz     */
319231858Sbz    chunk = ehdr->e_shnum * ehdr->e_shentsize;
320231858Sbz    if (chunk == 0 || ehdr->e_shoff == 0)
321231858Sbz	goto nosyms;
322232114Sbz    shdr = malloc(chunk);
323232114Sbz    if (shdr == NULL)
324232114Sbz	goto nosyms;
325232114Sbz    if (lseek(fd, ehdr->e_shoff, SEEK_SET) == -1) {
326231858Sbz	printf("\nelf_loadimage: cannot lseek() to section headers");
327232114Sbz	goto nosyms;
328231858Sbz    }
329231858Sbz    if (read(fd, shdr, chunk) != chunk) {
330231858Sbz	printf("\nelf_loadimage: read section headers failed");
331231858Sbz	goto nosyms;
332231858Sbz    }
333231858Sbz    symtabindex = -1;
334231858Sbz    symstrindex = -1;
335231858Sbz    for (i = 0; i < ehdr->e_shnum; i++) {
336231858Sbz	if (shdr[i].sh_type != SHT_SYMTAB)
337231858Sbz	    continue;
338231858Sbz	for (j = 0; j < ehdr->e_phnum; j++) {
339231858Sbz	    if (phdr[j].p_type != PT_LOAD)
340231858Sbz		continue;
341231858Sbz	    if (shdr[i].sh_offset >= phdr[j].p_offset &&
342231858Sbz		(shdr[i].sh_offset + shdr[i].sh_size <=
343231858Sbz		 phdr[j].p_offset + phdr[j].p_filesz)) {
344231858Sbz		shdr[i].sh_offset = 0;
345231858Sbz		shdr[i].sh_size = 0;
346231858Sbz		break;
347231858Sbz	    }
348231858Sbz	}
349231858Sbz	if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
350231858Sbz	    continue;		/* alread loaded in a PT_LOAD above */
351231858Sbz	/* Save it for loading below */
352231858Sbz	symtabindex = i;
353231858Sbz	symstrindex = shdr[i].sh_link;
354231858Sbz    }
355231858Sbz    if (symtabindex < 0 || symstrindex < 0)
356231858Sbz	goto nosyms;
357231858Sbz
358231858Sbz    /* Ok, committed to a load. */
359231858Sbz#ifndef ELF_VERBOSE
360231858Sbz    printf("syms=[");
361231858Sbz#endif
362231858Sbz    ssym = lastaddr;
363231858Sbz    for (i = symtabindex; i >= 0; i = symstrindex) {
364231858Sbz#ifdef ELF_VERBOSE
365231858Sbz	char	*secname;
366231858Sbz
367231858Sbz	switch(shdr[i].sh_type) {
368231858Sbz	    case SHT_SYMTAB:		/* Symbol table */
369231858Sbz		secname = "symtab";
370231858Sbz		break;
371231858Sbz	    case SHT_STRTAB:		/* String table */
372231858Sbz		secname = "strtab";
373231858Sbz		break;
374231858Sbz	    default:
375231858Sbz		secname = "WHOA!!";
376231858Sbz		break;
377231858Sbz	}
378231858Sbz#endif
379231858Sbz
380231858Sbz	size = shdr[i].sh_size;
381231858Sbz	archsw.arch_copyin(&size, lastaddr, sizeof(size));
382231858Sbz	lastaddr += sizeof(long);
383231858Sbz
384231858Sbz#ifdef ELF_VERBOSE
385231858Sbz	printf("\n%s: 0x%lx@0x%lx -> 0x%lx-0x%lx", secname,
386231858Sbz	    shdr[i].sh_size, shdr[i].sh_offset,
387231858Sbz	    lastaddr, lastaddr + shdr[i].sh_size);
388231858Sbz#else
389231858Sbz	if (i == symstrindex)
390231858Sbz	    printf("+");
391231858Sbz	printf("0x%lx+0x%lx", (long)sizeof(size), size);
392231858Sbz#endif
393231858Sbz
394231858Sbz	if (lseek(fd, shdr[i].sh_offset, SEEK_SET) == -1) {
395231858Sbz	    printf("\nelf_loadimage: could not seek for symbols - skipped!");
396231858Sbz	    lastaddr = ssym;
397231858Sbz	    ssym = 0;
398231858Sbz	    goto nosyms;
399231858Sbz	}
400231858Sbz	if (archsw.arch_readin(fd, lastaddr, shdr[i].sh_size) !=
401231858Sbz	    shdr[i].sh_size) {
402231858Sbz	    printf("\nelf_loadimage: could not read symbols - skipped!");
403231858Sbz	    lastaddr = ssym;
404231858Sbz	    ssym = 0;
405231858Sbz	    goto nosyms;
406231858Sbz	}
407231858Sbz	/* Reset offsets relative to ssym */
408231858Sbz	lastaddr += shdr[i].sh_size;
409231858Sbz	lastaddr = roundup(lastaddr, sizeof(long));
410231858Sbz	if (i == symtabindex)
411231858Sbz	    symtabindex = -1;
412231858Sbz	else if (i == symstrindex)
413231858Sbz	    symstrindex = -1;
414231858Sbz    }
415231858Sbz    esym = lastaddr;
416231858Sbz#ifndef ELF_VERBOSE
417231858Sbz    printf("]");
418231858Sbz#endif
419231858Sbz
420231858Sbz    mod_addmetadata(mp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
421231858Sbz    mod_addmetadata(mp, MODINFOMD_ESYM, sizeof(esym), &esym);
422231858Sbz
423231858Sbznosyms:
424232114Sbz    printf("\n");
425231858Sbz
426231858Sbz    ret = lastaddr - firstaddr;
427231858Sbz    mp->m_addr = firstaddr;
428231858Sbz
429231858Sbz    for (i = 0; i < ehdr->e_phnum; i++) {
430231858Sbz	if (phdr[i].p_type == PT_DYNAMIC) {
431231858Sbz	    dp = (Elf_Dyn *)(phdr[i].p_vaddr);
432231858Sbz	    mod_addmetadata(mp, MODINFOMD_DYNAMIC, sizeof(dp), &dp);
433231858Sbz	    dp = NULL;
434231858Sbz	    break;
435231858Sbz	}
436232114Sbz    }
437232114Sbz
438232114Sbz    if (kernel)		/* kernel must not depend on anything */
439232114Sbz	goto out;
440232114Sbz
441231858Sbz    ndp = 0;
442231858Sbz    for (i = 0; i < ehdr->e_phnum; i++) {
443231858Sbz	if (phdr[i].p_type == PT_DYNAMIC) {
444231858Sbz	    ndp = phdr[i].p_filesz / sizeof(Elf_Dyn);
445231858Sbz	    dp = malloc(phdr[i].p_filesz);
446231858Sbz	    archsw.arch_copyout(phdr[i].p_vaddr + off, dp, phdr[i].p_filesz);
447231858Sbz	}
448231858Sbz    }
449231858Sbz    if (dp == NULL || ndp == 0)
450231858Sbz	goto out;
451231858Sbz    strtab = NULL;
452231858Sbz    strsz = 0;
453231858Sbz    deplen = 0;
454231858Sbz    for (i = 0; i < ndp; i++) {
455231858Sbz	if (dp[i].d_tag == NULL)
456232114Sbz	    break;
457232114Sbz	switch (dp[i].d_tag) {
458232114Sbz	case DT_STRTAB:
459232114Sbz	    strtab = (char *)(dp[i].d_un.d_ptr + off);
460231858Sbz	    break;
461232114Sbz	case DT_STRSZ:
462231858Sbz	    strsz = dp[i].d_un.d_val;
463231858Sbz	    break;
464231858Sbz	default:
465231858Sbz	    break;
466231858Sbz	}
467231858Sbz    }
468231858Sbz    if (strtab == NULL || strsz == 0)
469231858Sbz	goto out;
470231858Sbz
471231858Sbz    deplen = 0;
472231858Sbz    for (i = 0; i < ndp; i++) {
473231858Sbz	if (dp[i].d_tag == NULL)
474231858Sbz	    break;
475231858Sbz	switch (dp[i].d_tag) {
476231858Sbz	case DT_NEEDED:		/* count size for dependency list */
477231858Sbz	    j = dp[i].d_un.d_ptr;
478231858Sbz	    if (j < 1 || j > (strsz - 2))
479231858Sbz		continue;	/* bad symbol name index */
480231858Sbz	    deplen += strlenout((vm_offset_t)&strtab[j]) + 1;
481231858Sbz	    break;
482231858Sbz	default:
483231858Sbz	    break;
484231858Sbz	}
485231858Sbz    }
486231858Sbz
487231858Sbz    if (deplen > 0) {
488231858Sbz	depdata = malloc(deplen);
489231858Sbz	if (depdata == NULL)
490231858Sbz	    goto out;
491231858Sbz	s = depdata;
492232114Sbz	for (i = 0; i < ndp; i++) {
493231858Sbz	    if (dp[i].d_tag == NULL)
494231858Sbz		break;
495231858Sbz	    switch (dp[i].d_tag) {
496231858Sbz	    case DT_NEEDED:	/* dependency list */
497231858Sbz		j = dp[i].d_un.d_ptr;
498231858Sbz	    	len = strlenout((vm_offset_t)&strtab[j]) + 1;
499231858Sbz		archsw.arch_copyout((vm_offset_t)&strtab[j], s, len);
500231858Sbz		s += len;
501231858Sbz		break;
502231858Sbz	    default:
503231858Sbz		break;
504232114Sbz	    }
505232114Sbz	}
506232114Sbz	if ((s - depdata) > 0)
507232114Sbz	    mod_addmetadata(mp, MODINFOMD_DEPLIST, s - depdata, depdata);
508232114Sbz	free(depdata);
509231858Sbz    }
510231858Sbz
511231858Sbzout:
512231858Sbz    if (dp)
513231858Sbz	free(dp);
514231858Sbz    if (shdr)
515231858Sbz	free(shdr);
516231858Sbz    return ret;
517232114Sbz}
518232114Sbz