1 /* 2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 /* 24 * Copyright (c) 1989, 1993 25 * The Regents of the University of California. All rights reserved. 26 * 27 * Redistribution and use in source and binary forms, with or without 28 * modification, are permitted provided that the following conditions 29 * are met: 30 * 1. Redistributions of source code must retain the above copyright 31 * notice, this list of conditions and the following disclaimer. 32 * 2. Redistributions in binary form must reproduce the above copyright 33 * notice, this list of conditions and the following disclaimer in the 34 * documentation and/or other materials provided with the distribution. 35 * 3. All advertising materials mentioning features or use of this software 36 * must display the following acknowledgement: 37 * This product includes software developed by the University of 38 * California, Berkeley and its contributors. 39 * 4. Neither the name of the University nor the names of its contributors 40 * may be used to endorse or promote products derived from this software 41 * without specific prior written permission. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53 * SUCH DAMAGE. 54 */ 55 56 57 /* 58 * This file was copied from libc/gen/nlist.c from Darwin's source code 59 * The version of nlist used as a base is from 10.5.2, libc-498 60 * http://www.opensource.apple.com/darwinsource/10.5.2/Libc-498/gen/nlist.c 61 * 62 * The full tarball is at: 63 * http://www.opensource.apple.com/darwinsource/tarballs/apsl/Libc-498.tar.gz 64 * 65 * I've modified it to be compatible with 64-bit images. 66 */ 67 68 #include "breakpad_nlist_64.h" 69 70 #include <CoreFoundation/CoreFoundation.h> 71 #include <fcntl.h> 72 #include <mach-o/nlist.h> 73 #include <mach-o/loader.h> 74 #include <mach-o/fat.h> 75 #include <mach/mach.h> 76 #include <stdio.h> 77 #include <stdlib.h> 78 #include <sys/types.h> 79 #include <sys/uio.h> 80 #include <TargetConditionals.h> 81 #include <unistd.h> 82 83 /* Stuff lifted from <a.out.h> and <sys/exec.h> since they are gone */ 84 /* 85 * Header prepended to each a.out file. 86 */ 87 struct exec { 88 unsigned short a_machtype; /* machine type */ 89 unsigned short a_magic; /* magic number */ 90 unsigned long a_text; /* size of text segment */ 91 unsigned long a_data; /* size of initialized data */ 92 unsigned long a_bss; /* size of uninitialized data */ 93 unsigned long a_syms; /* size of symbol table */ 94 unsigned long a_entry; /* entry point */ 95 unsigned long a_trsize; /* size of text relocation */ 96 unsigned long a_drsize; /* size of data relocation */ 97 }; 98 99 #define OMAGIC 0407 /* old impure format */ 100 #define NMAGIC 0410 /* read-only text */ 101 #define ZMAGIC 0413 /* demand load format */ 102 103 #define N_BADMAG(x) \ 104 (((x).a_magic)!=OMAGIC && ((x).a_magic)!=NMAGIC && ((x).a_magic)!=ZMAGIC) 105 #define N_TXTOFF(x) \ 106 ((x).a_magic==ZMAGIC ? 0 : sizeof (struct exec)) 107 #define N_SYMOFF(x) \ 108 (N_TXTOFF(x) + (x).a_text+(x).a_data + (x).a_trsize+(x).a_drsize) 109 110 // Traits structs for specializing function templates to handle 111 // 32-bit/64-bit Mach-O files. 112 template<typename T> 113 struct MachBits {}; 114 115 typedef struct nlist nlist32; 116 typedef struct nlist_64 nlist64; 117 118 template<> 119 struct MachBits<nlist32> { 120 typedef mach_header mach_header_type; 121 typedef uint32_t word_type; 122 static const uint32_t magic = MH_MAGIC; 123 }; 124 125 template<> 126 struct MachBits<nlist64> { 127 typedef mach_header_64 mach_header_type; 128 typedef uint64_t word_type; 129 static const uint32_t magic = MH_MAGIC_64; 130 }; 131 132 template<typename nlist_type> 133 int 134 __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, 135 cpu_type_t cpu_type); 136 137 /* 138 * nlist - retreive attributes from name list (string table version) 139 */ 140 141 template <typename nlist_type> 142 int breakpad_nlist_common(const char *name, 143 nlist_type *list, 144 const char **symbolNames, 145 cpu_type_t cpu_type) { 146 int fd = open(name, O_RDONLY, 0); 147 if (fd < 0) 148 return -1; 149 int n = __breakpad_fdnlist(fd, list, symbolNames, cpu_type); 150 close(fd); 151 return n; 152 } 153 154 int breakpad_nlist(const char *name, 155 struct nlist *list, 156 const char **symbolNames, 157 cpu_type_t cpu_type) { 158 return breakpad_nlist_common(name, list, symbolNames, cpu_type); 159 } 160 161 int breakpad_nlist(const char *name, 162 struct nlist_64 *list, 163 const char **symbolNames, 164 cpu_type_t cpu_type) { 165 return breakpad_nlist_common(name, list, symbolNames, cpu_type); 166 } 167 168 /* Note: __fdnlist() is called from kvm_nlist in libkvm's kvm.c */ 169 170 template<typename nlist_type> 171 int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, 172 cpu_type_t cpu_type) { 173 typedef typename MachBits<nlist_type>::mach_header_type mach_header_type; 174 typedef typename MachBits<nlist_type>::word_type word_type; 175 176 const uint32_t magic = MachBits<nlist_type>::magic; 177 178 int maxlen = 500; 179 int nreq = 0; 180 for (nlist_type* q = list; 181 symbolNames[q-list] && symbolNames[q-list][0]; 182 q++, nreq++) { 183 184 q->n_type = 0; 185 q->n_value = 0; 186 q->n_desc = 0; 187 q->n_sect = 0; 188 q->n_un.n_strx = 0; 189 } 190 191 struct exec buf; 192 if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf) || 193 (N_BADMAG(buf) && *((uint32_t *)&buf) != magic && 194 CFSwapInt32BigToHost(*((uint32_t *)&buf)) != FAT_MAGIC && 195 /* The following is the big-endian ppc64 check */ 196 (*((uint32_t*)&buf)) != FAT_MAGIC)) { 197 return -1; 198 } 199 200 /* Deal with fat file if necessary */ 201 unsigned arch_offset = 0; 202 if (CFSwapInt32BigToHost(*((uint32_t *)&buf)) == FAT_MAGIC || 203 /* The following is the big-endian ppc64 check */ 204 *((unsigned int *)&buf) == FAT_MAGIC) { 205 /* Read in the fat header */ 206 struct fat_header fh; 207 if (lseek(fd, 0, SEEK_SET) == -1) { 208 return -1; 209 } 210 if (read(fd, (char *)&fh, sizeof(fh)) != sizeof(fh)) { 211 return -1; 212 } 213 214 /* Convert fat_narchs to host byte order */ 215 fh.nfat_arch = CFSwapInt32BigToHost(fh.nfat_arch); 216 217 /* Read in the fat archs */ 218 struct fat_arch *fat_archs = 219 (struct fat_arch *)malloc(fh.nfat_arch * sizeof(struct fat_arch)); 220 if (fat_archs == NULL) { 221 return -1; 222 } 223 if (read(fd, (char *)fat_archs, 224 sizeof(struct fat_arch) * fh.nfat_arch) != 225 (ssize_t)(sizeof(struct fat_arch) * fh.nfat_arch)) { 226 free(fat_archs); 227 return -1; 228 } 229 230 /* 231 * Convert archs to host byte ordering (a constraint of 232 * cpusubtype_getbestarch() 233 */ 234 for (unsigned i = 0; i < fh.nfat_arch; i++) { 235 fat_archs[i].cputype = 236 CFSwapInt32BigToHost(fat_archs[i].cputype); 237 fat_archs[i].cpusubtype = 238 CFSwapInt32BigToHost(fat_archs[i].cpusubtype); 239 fat_archs[i].offset = 240 CFSwapInt32BigToHost(fat_archs[i].offset); 241 fat_archs[i].size = 242 CFSwapInt32BigToHost(fat_archs[i].size); 243 fat_archs[i].align = 244 CFSwapInt32BigToHost(fat_archs[i].align); 245 } 246 247 struct fat_arch *fap = NULL; 248 for (unsigned i = 0; i < fh.nfat_arch; i++) { 249 if (fat_archs[i].cputype == cpu_type) { 250 fap = &fat_archs[i]; 251 break; 252 } 253 } 254 255 if (!fap) { 256 free(fat_archs); 257 return -1; 258 } 259 arch_offset = fap->offset; 260 free(fat_archs); 261 262 /* Read in the beginning of the architecture-specific file */ 263 if (lseek(fd, arch_offset, SEEK_SET) == -1) { 264 return -1; 265 } 266 if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf)) { 267 return -1; 268 } 269 } 270 271 off_t sa; /* symbol address */ 272 off_t ss; /* start of strings */ 273 register_t n; 274 if (*((unsigned int *)&buf) == magic) { 275 if (lseek(fd, arch_offset, SEEK_SET) == -1) { 276 return -1; 277 } 278 mach_header_type mh; 279 if (read(fd, (char *)&mh, sizeof(mh)) != sizeof(mh)) { 280 return -1; 281 } 282 283 struct load_command *load_commands = 284 (struct load_command *)malloc(mh.sizeofcmds); 285 if (load_commands == NULL) { 286 return -1; 287 } 288 if (read(fd, (char *)load_commands, mh.sizeofcmds) != 289 (ssize_t)mh.sizeofcmds) { 290 free(load_commands); 291 return -1; 292 } 293 struct symtab_command *stp = NULL; 294 struct load_command *lcp = load_commands; 295 // iterate through all load commands, looking for 296 // LC_SYMTAB load command 297 for (uint32_t i = 0; i < mh.ncmds; i++) { 298 if (lcp->cmdsize % sizeof(word_type) != 0 || 299 lcp->cmdsize <= 0 || 300 (char *)lcp + lcp->cmdsize > 301 (char *)load_commands + mh.sizeofcmds) { 302 free(load_commands); 303 return -1; 304 } 305 if (lcp->cmd == LC_SYMTAB) { 306 if (lcp->cmdsize != 307 sizeof(struct symtab_command)) { 308 free(load_commands); 309 return -1; 310 } 311 stp = (struct symtab_command *)lcp; 312 break; 313 } 314 lcp = (struct load_command *) 315 ((char *)lcp + lcp->cmdsize); 316 } 317 if (stp == NULL) { 318 free(load_commands); 319 return -1; 320 } 321 // sa points to the beginning of the symbol table 322 sa = stp->symoff + arch_offset; 323 // ss points to the beginning of the string table 324 ss = stp->stroff + arch_offset; 325 // n is the number of bytes in the symbol table 326 // each symbol table entry is an nlist structure 327 n = stp->nsyms * sizeof(nlist_type); 328 free(load_commands); 329 } else { 330 sa = N_SYMOFF(buf) + arch_offset; 331 ss = sa + buf.a_syms + arch_offset; 332 n = buf.a_syms; 333 } 334 335 if (lseek(fd, sa, SEEK_SET) == -1) { 336 return -1; 337 } 338 339 // the algorithm here is to read the nlist entries in m-sized 340 // chunks into q. q is then iterated over. for each entry in q, 341 // use the string table index(q->n_un.n_strx) to read the symbol 342 // name, then scan the nlist entries passed in by the user(via p), 343 // and look for a match 344 while (n) { 345 nlist_type space[BUFSIZ/sizeof (nlist_type)]; 346 register_t m = sizeof (space); 347 348 if (n < m) 349 m = n; 350 if (read(fd, (char *)space, m) != m) 351 break; 352 n -= m; 353 off_t savpos = lseek(fd, 0, SEEK_CUR); 354 if (savpos == -1) { 355 return -1; 356 } 357 for (nlist_type* q = space; (m -= sizeof(nlist_type)) >= 0; q++) { 358 char nambuf[BUFSIZ]; 359 360 if (q->n_un.n_strx == 0 || q->n_type & N_STAB) 361 continue; 362 363 // seek to the location in the binary where the symbol 364 // name is stored & read it into memory 365 if (lseek(fd, ss+q->n_un.n_strx, SEEK_SET) == -1) { 366 return -1; 367 } 368 if (read(fd, nambuf, maxlen+1) == -1) { 369 return -1; 370 } 371 const char *s2 = nambuf; 372 for (nlist_type *p = list; 373 symbolNames[p-list] && symbolNames[p-list][0]; 374 p++) { 375 // get the symbol name the user has passed in that 376 // corresponds to the nlist entry that we're looking at 377 const char *s1 = symbolNames[p - list]; 378 while (*s1) { 379 if (*s1++ != *s2++) 380 goto cont; 381 } 382 if (*s2) 383 goto cont; 384 385 p->n_value = q->n_value; 386 p->n_type = q->n_type; 387 p->n_desc = q->n_desc; 388 p->n_sect = q->n_sect; 389 p->n_un.n_strx = q->n_un.n_strx; 390 if (--nreq == 0) 391 return nreq; 392 393 break; 394 cont: ; 395 } 396 } 397 if (lseek(fd, savpos, SEEK_SET) == -1) { 398 return -1; 399 } 400 } 401 return nreq; 402 } 403