1 /* $OpenBSD: nlist.c,v 1.57 2014/01/19 20:48:57 deraadt 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 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <sys/mman.h> 34 #include <sys/stat.h> 35 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include <a.out.h> /* pulls in nlist.h */ 43 44 #ifdef _NLIST_DO_ELF 45 #include <elf_abi.h> 46 #endif 47 48 int __fdnlist(int, struct nlist *); 49 #ifdef _NLIST_DO_ELF 50 int __elf_is_okay__(Elf_Ehdr *ehdr); 51 #endif 52 53 #define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0) 54 55 #ifdef _NLIST_DO_ELF 56 /* 57 * __elf_is_okay__ - Determine if ehdr really 58 * is ELF and valid for the target platform. 59 * 60 * WARNING: This is NOT a ELF ABI function and 61 * as such its use should be restricted. 62 */ 63 int 64 __elf_is_okay__(Elf_Ehdr *ehdr) 65 { 66 int retval = 0; 67 /* 68 * We need to check magic, class size, endianess, 69 * and version before we look at the rest of the 70 * Elf_Ehdr structure. These few elements are 71 * represented in a machine independent fashion. 72 */ 73 if (IS_ELF(*ehdr) && 74 ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS && 75 ehdr->e_ident[EI_DATA] == ELF_TARG_DATA && 76 ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) { 77 78 /* Now check the machine dependant header */ 79 if (ehdr->e_machine == ELF_TARG_MACH && 80 ehdr->e_version == ELF_TARG_VER) 81 retval = 1; 82 } 83 84 return retval; 85 } 86 87 int 88 __fdnlist(int fd, struct nlist *list) 89 { 90 struct nlist *p; 91 caddr_t strtab; 92 Elf_Off symoff = 0, symstroff = 0; 93 Elf_Word symsize = 0, symstrsize = 0; 94 Elf_Sword nent, cc, i; 95 Elf_Sym sbuf[1024]; 96 Elf_Sym *s; 97 Elf_Ehdr ehdr; 98 Elf_Shdr *shdr = NULL; 99 Elf_Word shdr_size; 100 struct stat st; 101 int usemalloc = 0; 102 103 /* Make sure obj is OK */ 104 if (pread(fd, &ehdr, sizeof(Elf_Ehdr), (off_t)0) != sizeof(Elf_Ehdr) || 105 !__elf_is_okay__(&ehdr) || fstat(fd, &st) < 0) 106 return (-1); 107 108 /* calculate section header table size */ 109 shdr_size = ehdr.e_shentsize * ehdr.e_shnum; 110 111 /* Make sure it's not too big to mmap */ 112 if (shdr_size > SIZE_T_MAX) { 113 errno = EFBIG; 114 return (-1); 115 } 116 117 /* mmap section header table */ 118 shdr = (Elf_Shdr *)mmap(NULL, (size_t)shdr_size, PROT_READ, 119 MAP_SHARED|MAP_FILE, fd, (off_t) ehdr.e_shoff); 120 if (shdr == MAP_FAILED) { 121 usemalloc = 1; 122 if ((shdr = malloc(shdr_size)) == NULL) 123 return (-1); 124 125 if (pread(fd, shdr, shdr_size, (off_t)ehdr.e_shoff) != shdr_size) { 126 free(shdr); 127 return (-1); 128 } 129 } 130 131 /* 132 * Find the symbol table entry and its corresponding 133 * string table entry. Version 1.1 of the ABI states 134 * that there is only one symbol table but that this 135 * could change in the future. 136 */ 137 for (i = 0; i < ehdr.e_shnum; i++) { 138 if (shdr[i].sh_type == SHT_SYMTAB) { 139 symoff = shdr[i].sh_offset; 140 symsize = shdr[i].sh_size; 141 symstroff = shdr[shdr[i].sh_link].sh_offset; 142 symstrsize = shdr[shdr[i].sh_link].sh_size; 143 break; 144 } 145 } 146 147 /* Flush the section header table */ 148 if (usemalloc) 149 free(shdr); 150 else 151 munmap((caddr_t)shdr, shdr_size); 152 153 /* Check for files too large to mmap. */ 154 /* XXX is this really possible? */ 155 if (symstrsize > SIZE_T_MAX) { 156 errno = EFBIG; 157 return (-1); 158 } 159 /* 160 * Map string table into our address space. This gives us 161 * an easy way to randomly access all the strings, without 162 * making the memory allocation permanent as with malloc/free 163 * (i.e., munmap will return it to the system). 164 */ 165 if (usemalloc) { 166 if ((strtab = malloc(symstrsize)) == NULL) 167 return (-1); 168 if (pread(fd, strtab, symstrsize, (off_t)symstroff) != symstrsize) { 169 free(strtab); 170 return (-1); 171 } 172 } else { 173 strtab = mmap(NULL, (size_t)symstrsize, PROT_READ, 174 MAP_SHARED|MAP_FILE, fd, (off_t) symstroff); 175 if (strtab == MAP_FAILED) 176 return (-1); 177 } 178 /* 179 * clean out any left-over information for all valid entries. 180 * Type and value defined to be 0 if not found; historical 181 * versions cleared other and desc as well. Also figure out 182 * the largest string length so don't read any more of the 183 * string table than we have to. 184 * 185 * XXX clearing anything other than n_type and n_value violates 186 * the semantics given in the man page. 187 */ 188 nent = 0; 189 for (p = list; !ISLAST(p); ++p) { 190 p->n_type = 0; 191 p->n_other = 0; 192 p->n_desc = 0; 193 p->n_value = 0; 194 ++nent; 195 } 196 197 /* Don't process any further if object is stripped. */ 198 /* ELFism - dunno if stripped by looking at header */ 199 if (symoff == 0) 200 goto elf_done; 201 202 while (symsize > 0) { 203 cc = MIN(symsize, sizeof(sbuf)); 204 if (pread(fd, sbuf, cc, (off_t)symoff) != cc) 205 break; 206 symsize -= cc; 207 symoff += cc; 208 for (s = sbuf; cc > 0; ++s, cc -= sizeof(*s)) { 209 int soff = s->st_name; 210 211 if (soff == 0) 212 continue; 213 for (p = list; !ISLAST(p); p++) { 214 char *sym; 215 216 /* 217 * First we check for the symbol as it was 218 * provided by the user. If that fails 219 * and the first char is an '_', skip over 220 * the '_' and try again. 221 * XXX - What do we do when the user really 222 * wants '_foo' and the are symbols 223 * for both 'foo' and '_foo' in the 224 * table and 'foo' is first? 225 */ 226 sym = p->n_un.n_name; 227 if (strcmp(&strtab[soff], sym) != 0 && 228 (sym[0] != '_' || 229 strcmp(&strtab[soff], sym + 1) != 0)) 230 continue; 231 232 p->n_value = s->st_value; 233 234 /* XXX - type conversion */ 235 /* is pretty rude. */ 236 switch(ELF_ST_TYPE(s->st_info)) { 237 case STT_NOTYPE: 238 switch (s->st_shndx) { 239 case SHN_UNDEF: 240 p->n_type = N_UNDF; 241 break; 242 case SHN_ABS: 243 p->n_type = N_ABS; 244 break; 245 case SHN_COMMON: 246 p->n_type = N_COMM; 247 break; 248 default: 249 p->n_type = N_COMM | N_EXT; 250 break; 251 } 252 break; 253 case STT_OBJECT: 254 p->n_type = N_DATA; 255 break; 256 case STT_FUNC: 257 p->n_type = N_TEXT; 258 break; 259 case STT_FILE: 260 p->n_type = N_FN; 261 break; 262 } 263 if (ELF_ST_BIND(s->st_info) == 264 STB_LOCAL) 265 p->n_type = N_EXT; 266 p->n_desc = 0; 267 p->n_other = 0; 268 if (--nent <= 0) 269 break; 270 } 271 } 272 } 273 elf_done: 274 if (usemalloc) 275 free(strtab); 276 else 277 munmap(strtab, symstrsize); 278 return (nent); 279 } 280 #endif /* _NLIST_DO_ELF */ 281 282 int 283 nlist(const char *name, struct nlist *list) 284 { 285 int fd, n; 286 287 fd = open(name, O_RDONLY, 0); 288 if (fd < 0) 289 return (-1); 290 n = __fdnlist(fd, list); 291 (void)close(fd); 292 return (n); 293 } 294