1 1.39 christos /* $NetBSD: nlist_elf32.c,v 1.39 2016/02/26 17:12:53 christos Exp $ */ 2 1.1 cgd 3 1.1 cgd /* 4 1.21 cgd * Copyright (c) 1996 Christopher G. Demetriou 5 1.21 cgd * All rights reserved. 6 1.21 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.1 cgd * 3. All advertising materials mentioning features or use of this software 16 1.1 cgd * must display the following acknowledgement: 17 1.21 cgd * This product includes software developed for the 18 1.24 salo * NetBSD Project. See http://www.NetBSD.org/ for 19 1.21 cgd * information about NetBSD. 20 1.3 cgd * 4. The name of the author may not be used to endorse or promote products 21 1.21 cgd * derived from this software without specific prior written permission. 22 1.21 cgd * 23 1.3 cgd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 1.3 cgd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 1.3 cgd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 1.3 cgd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 1.3 cgd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 1.3 cgd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 1.3 cgd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 1.3 cgd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 1.3 cgd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 1.3 cgd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 1.21 cgd * 34 1.21 cgd * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>> 35 1.1 cgd */ 36 1.1 cgd 37 1.28 lukem #include <sys/cdefs.h> 38 1.28 lukem #if defined(LIBC_SCCS) && !defined(lint) 39 1.39 christos __RCSID("$NetBSD: nlist_elf32.c,v 1.39 2016/02/26 17:12:53 christos Exp $"); 40 1.28 lukem #endif /* LIBC_SCCS and not lint */ 41 1.28 lukem 42 1.1 cgd /* If not included by nlist_elf64.c, ELFSIZE won't be defined. */ 43 1.1 cgd #ifndef ELFSIZE 44 1.1 cgd #define ELFSIZE 32 45 1.1 cgd #endif 46 1.1 cgd 47 1.11 kleink #include "namespace.h" 48 1.1 cgd #include <sys/param.h> 49 1.1 cgd #include <sys/mman.h> 50 1.1 cgd #include <sys/stat.h> 51 1.1 cgd #include <sys/file.h> 52 1.22 ragge #include <sys/ioctl.h> 53 1.1 cgd 54 1.14 lukem #include <assert.h> 55 1.1 cgd #include <errno.h> 56 1.1 cgd #include <stdio.h> 57 1.1 cgd #include <string.h> 58 1.1 cgd #include <unistd.h> 59 1.31 he #include <nlist.h> 60 1.1 cgd 61 1.1 cgd #include "nlist_private.h" 62 1.1 cgd #if defined(NLIST_ELF32) || defined(NLIST_ELF64) 63 1.1 cgd #include <sys/exec_elf.h> 64 1.1 cgd #endif 65 1.1 cgd 66 1.38 matt #include <sys/ksyms.h> /* after sys/exec_elf.h */ 67 1.38 matt 68 1.1 cgd #if (defined(NLIST_ELF32) && (ELFSIZE == 32)) || \ 69 1.1 cgd (defined(NLIST_ELF64) && (ELFSIZE == 64)) 70 1.17 hannken 71 1.12 christos /* No need to check for off < 0 because it is unsigned */ 72 1.12 christos #define check(off, size) (off + size > mappedsize) 73 1.12 christos #define BAD goto out 74 1.12 christos #define BADUNMAP goto unmap 75 1.3 cgd 76 1.1 cgd int 77 1.34 matt ELFNAMEEND(__fdnlist)(int fd, struct nlist *list) 78 1.1 cgd { 79 1.2 cgd struct stat st; 80 1.35 christos Elf_Ehdr ehdr; 81 1.37 matt #if defined(_LP64) || ELFSIZE == 32 || defined(ELF64_MACHDEP_ID) 82 1.35 christos #if (ELFSIZE == 32) 83 1.35 christos Elf32_Half nshdr; 84 1.35 christos #elif (ELFSIZE == 64) 85 1.35 christos Elf64_Word nshdr; 86 1.35 christos #endif 87 1.37 matt /* Only support 64+32 mode on LP64 and those that have defined */ 88 1.37 matt /* ELF64_MACHDEP_ID, otherwise no support for 64 mode on ILP32 */ 89 1.35 christos Elf_Ehdr *ehdrp; 90 1.3 cgd Elf_Shdr *shdrp, *symshdrp, *symstrshdrp; 91 1.3 cgd Elf_Sym *symp; 92 1.5 cgd Elf_Off shdr_off; 93 1.5 cgd Elf_Word shdr_size; 94 1.35 christos struct nlist *p; 95 1.35 christos char *mappedfile, *strtab; 96 1.35 christos size_t mappedsize, nsyms; 97 1.35 christos int nent; 98 1.3 cgd #endif 99 1.35 christos int rv; 100 1.35 christos size_t i; 101 1.14 lukem 102 1.14 lukem _DIAGASSERT(fd != -1); 103 1.14 lukem _DIAGASSERT(list != NULL); 104 1.3 cgd 105 1.3 cgd rv = -1; 106 1.3 cgd 107 1.3 cgd /* 108 1.4 cgd * If we can't fstat() the file, something bad is going on. 109 1.3 cgd */ 110 1.3 cgd if (fstat(fd, &st) < 0) 111 1.3 cgd BAD; 112 1.4 cgd 113 1.4 cgd /* 114 1.4 cgd * Map the file in its entirety. 115 1.4 cgd */ 116 1.30 lukem if ((uintmax_t)st.st_size > (uintmax_t)SIZE_T_MAX) { 117 1.3 cgd errno = EFBIG; 118 1.3 cgd BAD; 119 1.3 cgd } 120 1.22 ragge 121 1.22 ragge /* 122 1.22 ragge * Read the elf header of the file. 123 1.22 ragge */ 124 1.23 christos if ((ssize_t)(i = pread(fd, &ehdr, sizeof(Elf_Ehdr), (off_t)0)) == -1) 125 1.22 ragge BAD; 126 1.22 ragge 127 1.22 ragge /* 128 1.22 ragge * Check that the elf header is correct. 129 1.22 ragge */ 130 1.22 ragge if (i != sizeof(Elf_Ehdr)) 131 1.22 ragge BAD; 132 1.22 ragge if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || 133 1.22 ragge ehdr.e_ident[EI_CLASS] != ELFCLASS) 134 1.22 ragge BAD; 135 1.22 ragge 136 1.22 ragge switch (ehdr.e_machine) { 137 1.22 ragge ELFDEFNNAME(MACHDEP_ID_CASES) 138 1.22 ragge 139 1.22 ragge default: 140 1.27 lukem BAD; 141 1.22 ragge } 142 1.37 matt #if defined(_LP64) || ELFSIZE == 32 || defined(ELF64_MACHDEP_ID) 143 1.35 christos symshdrp = symstrshdrp = NULL; 144 1.22 ragge 145 1.37 matt /* Only support 64+32 mode on LP64 and those that have defined */ 146 1.37 matt /* ELF64_MACHDEP_ID, otherwise no support for 64 mode on ILP32 */ 147 1.22 ragge if (S_ISCHR(st.st_mode)) { 148 1.22 ragge const char *nlistname; 149 1.22 ragge Elf_Sym sym; 150 1.22 ragge 151 1.22 ragge /* 152 1.22 ragge * Character device; assume /dev/ksyms. 153 1.22 ragge */ 154 1.22 ragge nent = 0; 155 1.22 ragge for (p = list; !ISLAST(p); ++p) { 156 1.37 matt struct ksyms_gsymbol kg; 157 1.37 matt int error; 158 1.22 ragge 159 1.22 ragge p->n_other = 0; 160 1.22 ragge p->n_desc = 0; 161 1.31 he nlistname = N_NAME(p); 162 1.22 ragge if (*nlistname == '_') 163 1.22 ragge nlistname++; 164 1.22 ragge 165 1.37 matt memset(&kg, 0, sizeof(kg)); 166 1.22 ragge kg.kg_name = nlistname; 167 1.37 matt #ifdef OKIOCGSYMBOL 168 1.37 matt struct ksyms_ogsymbol okg; 169 1.37 matt error = ioctl(fd, KIOCGSYMBOL, &kg); 170 1.37 matt if (error == 0) { 171 1.37 matt sym = kg.kg_sym; 172 1.37 matt } else if (error && errno == ENOTTY) { 173 1.37 matt memset(&okg, 0, sizeof(okg)); 174 1.37 matt okg.kg_name = nlistname; 175 1.37 matt okg.kg_sym = &sym; 176 1.37 matt error = ioctl(fd, OKIOCGSYMBOL, &okg); 177 1.37 matt } 178 1.37 matt #else 179 1.22 ragge kg.kg_sym = &sym; 180 1.37 matt error = ioctl(fd, KIOCGSYMBOL, &kg); 181 1.37 matt #endif 182 1.37 matt if (error == 0 183 1.37 matt #if !defined(_LP64) && ELFSIZE == 64 184 1.37 matt #if __mips__ 185 1.37 matt && (intptr_t)sym.st_value == (intmax_t)sym.st_value 186 1.37 matt #else 187 1.37 matt && (uintptr_t)sym.st_value == sym.st_value 188 1.37 matt #endif 189 1.37 matt #endif 190 1.39 christos && /*CONSTCOND*/1) { 191 1.35 christos p->n_value = (uintptr_t)sym.st_value; 192 1.25 thorpej switch (ELF_ST_TYPE(sym.st_info)) { 193 1.22 ragge case STT_NOTYPE: 194 1.22 ragge p->n_type = N_UNDF; 195 1.22 ragge break; 196 1.33 christos case STT_COMMON: 197 1.22 ragge case STT_OBJECT: 198 1.22 ragge p->n_type = N_DATA; 199 1.22 ragge break; 200 1.22 ragge case STT_FUNC: 201 1.22 ragge p->n_type = N_TEXT; 202 1.22 ragge break; 203 1.22 ragge case STT_FILE: 204 1.22 ragge p->n_type = N_FN; 205 1.22 ragge break; 206 1.22 ragge default: 207 1.22 ragge p->n_type = 0; 208 1.22 ragge /* catch other enumerations for gcc */ 209 1.22 ragge break; 210 1.22 ragge } 211 1.26 thorpej if (ELF_ST_BIND(sym.st_info) != STB_LOCAL) 212 1.22 ragge p->n_type |= N_EXT; 213 1.22 ragge } else { 214 1.22 ragge nent++; 215 1.22 ragge p->n_value = 0; 216 1.22 ragge p->n_type = 0; 217 1.22 ragge } 218 1.22 ragge } 219 1.22 ragge return nent; 220 1.22 ragge } 221 1.22 ragge 222 1.12 christos mappedsize = (size_t)st.st_size; 223 1.13 thorpej mappedfile = mmap(NULL, mappedsize, PROT_READ, MAP_PRIVATE|MAP_FILE, 224 1.12 christos fd, (off_t)0); 225 1.3 cgd if (mappedfile == (char *)-1) 226 1.3 cgd BAD; 227 1.3 cgd 228 1.3 cgd /* 229 1.3 cgd * Make sure we can access the executable's header 230 1.3 cgd * directly, and make sure the recognize the executable 231 1.3 cgd * as an ELF binary. 232 1.3 cgd */ 233 1.3 cgd if (check(0, sizeof *ehdrp)) 234 1.3 cgd BADUNMAP; 235 1.12 christos ehdrp = (Elf_Ehdr *)(void *)&mappedfile[0]; 236 1.1 cgd 237 1.2 cgd /* 238 1.3 cgd * Find the symbol list and string table. 239 1.2 cgd */ 240 1.3 cgd nshdr = ehdrp->e_shnum; 241 1.3 cgd shdr_off = ehdrp->e_shoff; 242 1.3 cgd shdr_size = ehdrp->e_shentsize * nshdr; 243 1.3 cgd 244 1.3 cgd if (check(shdr_off, shdr_size) || 245 1.3 cgd (sizeof *shdrp != ehdrp->e_shentsize)) 246 1.3 cgd BADUNMAP; 247 1.35 christos shdrp = (void *)&mappedfile[(size_t)shdr_off]; 248 1.3 cgd 249 1.3 cgd for (i = 0; i < nshdr; i++) { 250 1.18 kleink if (shdrp[i].sh_type == SHT_SYMTAB) { 251 1.3 cgd symshdrp = &shdrp[i]; 252 1.3 cgd symstrshdrp = &shdrp[shdrp[i].sh_link]; 253 1.2 cgd } 254 1.2 cgd } 255 1.2 cgd 256 1.3 cgd /* Make sure we're not stripped. */ 257 1.6 thorpej if (symshdrp == NULL || symshdrp->sh_offset == 0) 258 1.3 cgd BADUNMAP; 259 1.3 cgd 260 1.3 cgd /* Make sure the symbols and strings are safely mapped. */ 261 1.3 cgd if (check(symshdrp->sh_offset, symshdrp->sh_size)) 262 1.3 cgd BADUNMAP; 263 1.3 cgd if (check(symstrshdrp->sh_offset, symstrshdrp->sh_size)) 264 1.3 cgd BADUNMAP; 265 1.3 cgd 266 1.35 christos symp = (void *)&mappedfile[(size_t)symshdrp->sh_offset]; 267 1.35 christos nsyms = (size_t)(symshdrp->sh_size / sizeof(*symp)); 268 1.35 christos strtab = &mappedfile[(size_t)symstrshdrp->sh_offset]; 269 1.1 cgd 270 1.2 cgd /* 271 1.4 cgd * Clean out any left-over information for all valid entries. 272 1.4 cgd * Type and value are defined to be 0 if not found; historical 273 1.3 cgd * versions cleared other and desc as well. 274 1.2 cgd * 275 1.4 cgd * XXX Clearing anything other than n_type and n_value violates 276 1.2 cgd * the semantics given in the man page. 277 1.2 cgd */ 278 1.2 cgd nent = 0; 279 1.2 cgd for (p = list; !ISLAST(p); ++p) { 280 1.2 cgd p->n_type = 0; 281 1.2 cgd p->n_other = 0; 282 1.2 cgd p->n_desc = 0; 283 1.2 cgd p->n_value = 0; 284 1.2 cgd ++nent; 285 1.2 cgd } 286 1.2 cgd 287 1.3 cgd for (i = 0; i < nsyms; i++) { 288 1.3 cgd for (p = list; !ISLAST(p); ++p) { 289 1.9 mycroft const char *nlistname; 290 1.3 cgd char *symtabname; 291 1.3 cgd 292 1.3 cgd /* This may be incorrect */ 293 1.31 he nlistname = N_NAME(p); 294 1.3 cgd if (*nlistname == '_') 295 1.3 cgd nlistname++; 296 1.3 cgd 297 1.3 cgd symtabname = &strtab[symp[i].st_name]; 298 1.3 cgd 299 1.3 cgd if (!strcmp(symtabname, nlistname)) { 300 1.4 cgd /* 301 1.4 cgd * Translate (roughly) from ELF to nlist 302 1.4 cgd */ 303 1.35 christos p->n_value = (uintptr_t)symp[i].st_value; 304 1.26 thorpej switch (ELF_ST_TYPE(symp[i].st_info)) { 305 1.18 kleink case STT_NOTYPE: 306 1.3 cgd p->n_type = N_UNDF; 307 1.3 cgd break; 308 1.18 kleink case STT_OBJECT: 309 1.33 christos case STT_COMMON: 310 1.3 cgd p->n_type = N_DATA; 311 1.3 cgd break; 312 1.18 kleink case STT_FUNC: 313 1.3 cgd p->n_type = N_TEXT; 314 1.3 cgd break; 315 1.18 kleink case STT_FILE: 316 1.3 cgd p->n_type = N_FN; 317 1.6 thorpej break; 318 1.6 thorpej default: 319 1.6 thorpej /* catch other enumerations for gcc */ 320 1.3 cgd break; 321 1.2 cgd } 322 1.26 thorpej if (ELF_ST_BIND(symp[i].st_info) != STB_LOCAL) 323 1.3 cgd p->n_type |= N_EXT; 324 1.3 cgd p->n_desc = 0; /* XXX */ 325 1.3 cgd p->n_other = 0; /* XXX */ 326 1.3 cgd 327 1.3 cgd if (--nent <= 0) 328 1.3 cgd goto done; 329 1.3 cgd break; /* into next run of outer loop */ 330 1.2 cgd } 331 1.2 cgd } 332 1.2 cgd } 333 1.3 cgd 334 1.2 cgd done: 335 1.3 cgd rv = nent; 336 1.3 cgd unmap: 337 1.3 cgd munmap(mappedfile, mappedsize); 338 1.37 matt #endif /* _LP64 || ELFSIZE == 32 || ELF64_MACHDEP_ID */ 339 1.3 cgd out: 340 1.3 cgd return (rv); 341 1.1 cgd } 342 1.1 cgd 343 1.1 cgd #endif 344