1 /* $OpenBSD: i386_nlist.c,v 1.1 2014/01/19 02:58:50 jsing Exp $ */ 2 /* 3 * Copyright (c) 1989, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #define ELFSIZE 32 32 33 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <sys/mman.h> 36 #include <sys/stat.h> 37 38 #include <elf_abi.h> 39 #include <fcntl.h> 40 #include <nlist.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 static int __elf_fdnlist(int, struct nlist *); 46 static int __elf_is_okay__(Elf_Ehdr *ehdr); 47 48 int nlist_elf32(const char *, struct nlist *); 49 50 #define ISLAST(p) (p->n_name == 0 || p->n_name[0] == 0) 51 52 /* 53 * __elf_is_okay__ - Determine if ehdr really 54 * is ELF and valid for the target platform. 55 * 56 * WARNING: This is NOT a ELF ABI function and 57 * as such its use should be restricted. 58 */ 59 static int 60 __elf_is_okay__(Elf_Ehdr *ehdr) 61 { 62 int retval = 0; 63 /* 64 * We need to check magic, class size, endianess, 65 * and version before we look at the rest of the 66 * Elf_Ehdr structure. These few elements are 67 * represented in a machine independent fashion. 68 */ 69 70 /* 71 * We are constructing a 32-bit executable. So we can't 72 * use the libc nlist.c, which would be upset. Manually 73 * check for the i386 values for EI_CLASS and e_machine. 74 */ 75 76 if (IS_ELF(*ehdr) && 77 ehdr->e_ident[EI_CLASS] == ELFCLASS32 && 78 ehdr->e_ident[EI_DATA] == ELF_TARG_DATA && 79 ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) { 80 81 /* Now check the machine dependant header */ 82 if (ehdr->e_machine == EM_386 && 83 ehdr->e_version == ELF_TARG_VER) 84 retval = 1; 85 } 86 87 return retval; 88 } 89 90 static int 91 __elf_fdnlist(int fd, struct nlist *list) 92 { 93 struct nlist *p; 94 caddr_t strtab; 95 Elf_Off symoff = 0, symstroff = 0; 96 Elf_Word symsize = 0, symstrsize = 0; 97 Elf_Sword nent, cc, i; 98 Elf_Sym sbuf[1024]; 99 Elf_Sym *s; 100 Elf_Ehdr ehdr; 101 Elf_Shdr *shdr = NULL; 102 Elf_Word shdr_size; 103 struct stat st; 104 int usemalloc = 0; 105 106 /* Make sure obj is OK */ 107 if (pread(fd, &ehdr, sizeof(Elf_Ehdr), (off_t)0) != sizeof(Elf_Ehdr) || 108 !__elf_is_okay__(&ehdr) || fstat(fd, &st) < 0) 109 return (-1); 110 111 /* calculate section header table size */ 112 shdr_size = ehdr.e_shentsize * ehdr.e_shnum; 113 114 /* mmap section header table */ 115 shdr = (Elf_Shdr *)mmap(NULL, (size_t)shdr_size, PROT_READ, 116 MAP_SHARED|MAP_FILE, fd, (off_t) ehdr.e_shoff); 117 if (shdr == MAP_FAILED) { 118 usemalloc = 1; 119 if ((shdr = malloc(shdr_size)) == NULL) 120 return (-1); 121 122 if (pread(fd, shdr, shdr_size, (off_t)ehdr.e_shoff) != 123 shdr_size) { 124 free(shdr); 125 return (-1); 126 } 127 } 128 129 /* 130 * Find the symbol table entry and its corresponding 131 * string table entry. Version 1.1 of the ABI states 132 * that there is only one symbol table but that this 133 * could change in the future. 134 */ 135 for (i = 0; i < ehdr.e_shnum; i++) { 136 if (shdr[i].sh_type == SHT_SYMTAB) { 137 symoff = shdr[i].sh_offset; 138 symsize = shdr[i].sh_size; 139 symstroff = shdr[shdr[i].sh_link].sh_offset; 140 symstrsize = shdr[shdr[i].sh_link].sh_size; 141 break; 142 } 143 } 144 145 /* Flush the section header table */ 146 if (usemalloc) 147 free(shdr); 148 else 149 munmap((caddr_t)shdr, shdr_size); 150 151 /* 152 * Map string table into our address space. This gives us 153 * an easy way to randomly access all the strings, without 154 * making the memory allocation permanent as with malloc/free 155 * (i.e., munmap will return it to the system). 156 */ 157 if (usemalloc) { 158 if ((strtab = malloc(symstrsize)) == NULL) 159 return (-1); 160 if (pread(fd, strtab, symstrsize, (off_t)symstroff) != 161 symstrsize) { 162 free(strtab); 163 return (-1); 164 } 165 } else { 166 strtab = mmap(NULL, (size_t)symstrsize, PROT_READ, 167 MAP_SHARED|MAP_FILE, fd, (off_t) symstroff); 168 if (strtab == MAP_FAILED) 169 return (-1); 170 } 171 /* 172 * clean out any left-over information for all valid entries. 173 * Type and value defined to be 0 if not found; historical 174 * versions cleared other and desc as well. Also figure out 175 * the largest string length so don't read any more of the 176 * string table than we have to. 177 * 178 * XXX clearing anything other than n_type and n_value violates 179 * the semantics given in the man page. 180 */ 181 nent = 0; 182 for (p = list; !ISLAST(p); ++p) { 183 p->n_type = 0; 184 p->n_other = 0; 185 p->n_desc = 0; 186 p->n_value = 0; 187 ++nent; 188 } 189 190 /* Don't process any further if object is stripped. */ 191 /* ELFism - dunno if stripped by looking at header */ 192 if (symoff == 0) 193 goto elf_done; 194 195 while (symsize > 0) { 196 cc = MIN(symsize, sizeof(sbuf)); 197 if (pread(fd, sbuf, cc, (off_t)symoff) != cc) 198 break; 199 symsize -= cc; 200 symoff += cc; 201 for (s = sbuf; cc > 0; ++s, cc -= sizeof(*s)) { 202 int soff = s->st_name; 203 204 if (soff == 0) 205 continue; 206 for (p = list; !ISLAST(p); p++) { 207 char *sym; 208 209 /* 210 * First we check for the symbol as it was 211 * provided by the user. If that fails 212 * and the first char is an '_', skip over 213 * the '_' and try again. 214 * XXX - What do we do when the user really 215 * wants '_foo' and the are symbols 216 * for both 'foo' and '_foo' in the 217 * table and 'foo' is first? 218 */ 219 sym = p->n_name; 220 if (strcmp(&strtab[soff], sym) != 0 && 221 (sym[0] != '_' || 222 strcmp(&strtab[soff], sym + 1) != 0)) 223 continue; 224 225 p->n_value = s->st_value; 226 227 /* XXX - type conversion */ 228 /* is pretty rude. */ 229 switch(ELF_ST_TYPE(s->st_info)) { 230 case STT_NOTYPE: 231 switch (s->st_shndx) { 232 case SHN_UNDEF: 233 p->n_type = N_UNDF; 234 break; 235 case SHN_ABS: 236 p->n_type = N_ABS; 237 break; 238 case SHN_COMMON: 239 p->n_type = N_COMM; 240 break; 241 default: 242 p->n_type = N_COMM | N_EXT; 243 break; 244 } 245 break; 246 case STT_OBJECT: 247 p->n_type = N_DATA; 248 break; 249 case STT_FUNC: 250 p->n_type = N_TEXT; 251 break; 252 case STT_FILE: 253 p->n_type = N_FN; 254 break; 255 } 256 if (ELF_ST_BIND(s->st_info) == 257 STB_LOCAL) 258 p->n_type = N_EXT; 259 p->n_desc = 0; 260 p->n_other = 0; 261 if (--nent <= 0) 262 break; 263 } 264 } 265 } 266 elf_done: 267 if (usemalloc) 268 free(strtab); 269 else 270 munmap(strtab, symstrsize); 271 return (nent); 272 } 273 274 int 275 nlist_elf32(const char *name, struct nlist *list) 276 { 277 int fd, n; 278 279 fd = open(name, O_RDONLY, 0); 280 if (fd < 0) 281 return (-1); 282 n = __elf_fdnlist(fd, list); 283 close(fd); 284 285 return (n); 286 } 287