Home | History | Annotate | Download | only in handler
      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