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