diff options
Diffstat (limited to 'src/client/mac/handler/breakpad_nlist_64.cc')
-rw-r--r-- | src/client/mac/handler/breakpad_nlist_64.cc | 411 |
1 files changed, 221 insertions, 190 deletions
diff --git a/src/client/mac/handler/breakpad_nlist_64.cc b/src/client/mac/handler/breakpad_nlist_64.cc index 4b655c79..709e8546 100644 --- a/src/client/mac/handler/breakpad_nlist_64.cc +++ b/src/client/mac/handler/breakpad_nlist_64.cc @@ -54,7 +54,7 @@ */ -/* nealsid: +/* * This file was copied from libc/gen/nlist.c from Darwin's source code * The version of nlist used as a base is from 10.5.2, libc-498 * http://www.opensource.apple.com/darwinsource/10.5.2/Libc-498/gen/nlist.c @@ -62,24 +62,22 @@ * The full tarball is at: * http://www.opensource.apple.com/darwinsource/tarballs/apsl/Libc-498.tar.gz * - * I've modified it to be compatible with 64-bit images. However, - * 32-bit compatibility has not been retained. + * I've modified it to be compatible with 64-bit images. */ -#ifdef __LP64__ +#include "breakpad_nlist_64.h" +#include <fcntl.h> #include <mach-o/nlist.h> #include <mach-o/loader.h> #include <mach-o/fat.h> +#include <mach/mach.h> +#include <stdio.h> #include <stdlib.h> -#include <fcntl.h> #include <sys/types.h> #include <sys/uio.h> -#include <unistd.h> -#include "breakpad_nlist_64.h" #include <TargetConditionals.h> -#include <stdio.h> -#include <mach/mach.h> +#include <unistd.h> /* Stuff lifted from <a.out.h> and <sys/exec.h> since they are gone */ /* @@ -108,44 +106,77 @@ struct exec { #define N_SYMOFF(x) \ (N_TXTOFF(x) + (x).a_text+(x).a_data + (x).a_trsize+(x).a_drsize) +// Traits structs for specializing function templates to handle +// 32-bit/64-bit Mach-O files. +template<typename T> +struct MachBits {}; + +typedef struct nlist nlist32; +typedef struct nlist_64 nlist64; + +template<> +struct MachBits<nlist32> { + typedef mach_header mach_header_type; + typedef uint32_t word_type; + static const uint32_t magic = MH_MAGIC; +}; + +template<> +struct MachBits<nlist64> { + typedef mach_header_64 mach_header_type; + typedef uint64_t word_type; + static const uint32_t magic = MH_MAGIC_64; +}; + +template<typename nlist_type> int -__breakpad_fdnlist_64(int fd, breakpad_nlist *list, const char **symbolNames); +__breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, + cpu_type_t cpu_type); /* * nlist - retreive attributes from name list (string table version) */ -int -breakpad_nlist_64(const char *name, - breakpad_nlist *list, - const char **symbolNames) { - int fd, n; - - fd = open(name, O_RDONLY, 0); +template <typename nlist_type> +int breakpad_nlist_common(const char *name, + nlist_type *list, + const char **symbolNames, + cpu_type_t cpu_type) { + int fd = open(name, O_RDONLY, 0); if (fd < 0) - return (-1); - n = __breakpad_fdnlist_64(fd, list, symbolNames); - (void)close(fd); - return (n); + return -1; + int n = __breakpad_fdnlist(fd, list, symbolNames, cpu_type); + close(fd); + return n; +} + +int breakpad_nlist(const char *name, + struct nlist *list, + const char **symbolNames, + cpu_type_t cpu_type) { + return breakpad_nlist_common(name, list, symbolNames, cpu_type); +} + +int breakpad_nlist(const char *name, + struct nlist_64 *list, + const char **symbolNames, + cpu_type_t cpu_type) { + return breakpad_nlist_common(name, list, symbolNames, cpu_type); } /* Note: __fdnlist() is called from kvm_nlist in libkvm's kvm.c */ -int -__breakpad_fdnlist_64(int fd, breakpad_nlist *list, const char **symbolNames) { - register breakpad_nlist *p, *q; - breakpad_nlist space[BUFSIZ/sizeof (breakpad_nlist)]; - - const register char *s1, *s2; - register register_t n, m; - int maxlen, nreq; - off_t sa; /* symbol address */ - off_t ss; /* start of strings */ - struct exec buf; - unsigned arch_offset = 0; +template<typename nlist_type> +int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, + cpu_type_t cpu_type) { + typedef typename MachBits<nlist_type>::mach_header_type mach_header_type; + typedef typename MachBits<nlist_type>::word_type word_type; - maxlen = 500; - for (q = list, nreq = 0; + const uint32_t magic = MachBits<nlist_type>::magic; + + int maxlen = 500; + int nreq = 0; + for (nlist_type* q = list; symbolNames[q-list] && symbolNames[q-list][0]; q++, nreq++) { @@ -156,61 +187,61 @@ __breakpad_fdnlist_64(int fd, breakpad_nlist *list, const char **symbolNames) { q->n_un.n_strx = 0; } + struct exec buf; if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf) || - (N_BADMAG(buf) && *((long *)&buf) != MH_MAGIC && + (N_BADMAG(buf) && *((long *)&buf) != magic && NXSwapBigLongToHost(*((long *)&buf)) != FAT_MAGIC) && - /* nealsid: The following is the big-endian ppc64 check */ + /* The following is the big-endian ppc64 check */ (*((long*)&buf)) != FAT_MAGIC) { - return (-1); + return -1; } /* Deal with fat file if necessary */ + unsigned arch_offset = 0; if (NXSwapBigLongToHost(*((long *)&buf)) == FAT_MAGIC || - /* nealsid: The following is the big-endian ppc64 check */ + /* The following is the big-endian ppc64 check */ *((unsigned int *)&buf) == FAT_MAGIC) { + /* Get host info */ + host_t host = mach_host_self(); + unsigned i = HOST_BASIC_INFO_COUNT; struct host_basic_info hbi; - struct fat_header fh; - struct fat_arch *fat_archs, *fap; - unsigned i; - host_t host; - - /* Get our host info */ - host = mach_host_self(); - i = HOST_BASIC_INFO_COUNT; kern_return_t kr; - if ((kr=host_info(host, HOST_BASIC_INFO, - (host_info_t)(&hbi), &i)) != KERN_SUCCESS) { - return (-1); + if ((kr = host_info(host, HOST_BASIC_INFO, + (host_info_t)(&hbi), &i)) != KERN_SUCCESS) { + return -1; } mach_port_deallocate(mach_task_self(), host); /* Read in the fat header */ - lseek(fd, 0, SEEK_SET); + struct fat_header fh; + if (lseek(fd, 0, SEEK_SET) == -1) { + return -1; + } if (read(fd, (char *)&fh, sizeof(fh)) != sizeof(fh)) { - return (-1); + return -1; } /* Convert fat_narchs to host byte order */ fh.nfat_arch = NXSwapBigIntToHost(fh.nfat_arch); /* Read in the fat archs */ - fat_archs = (struct fat_arch *)malloc(fh.nfat_arch * - sizeof(struct fat_arch)); + struct fat_arch *fat_archs = + (struct fat_arch *)malloc(fh.nfat_arch * sizeof(struct fat_arch)); if (fat_archs == NULL) { - return (-1); + return -1; } if (read(fd, (char *)fat_archs, sizeof(struct fat_arch) * fh.nfat_arch) != (ssize_t)sizeof(struct fat_arch) * fh.nfat_arch) { free(fat_archs); - return (-1); + return -1; } /* * Convert archs to host byte ordering (a constraint of * cpusubtype_getbestarch() */ - for (i = 0; i < fh.nfat_arch; i++) { + for (unsigned i = 0; i < fh.nfat_arch; i++) { fat_archs[i].cputype = NXSwapBigIntToHost(fat_archs[i].cputype); fat_archs[i].cpusubtype = @@ -223,159 +254,159 @@ __breakpad_fdnlist_64(int fd, breakpad_nlist *list, const char **symbolNames) { NXSwapBigIntToHost(fat_archs[i].align); } - fap = NULL; - for (i = 0; i < fh.nfat_arch; i++) { - /* nealsid: Although the original Apple code uses host_info */ - /* to retrieve the CPU type, the host_info will still return */ - /* CPU_TYPE_X86 even if running as an x86_64 binary. Given that */ - /* this code isn't necessary on i386, I've decided to hardcode */ - /* looking for a 64-bit binary */ -#if TARGET_CPU_X86_64 - if (fat_archs[i].cputype == CPU_TYPE_X86_64) { -#elif TARGET_CPU_PPC64 - if (fat_archs[i].cputype == CPU_TYPE_POWERPC64) { -#else -#error undefined cpu! - { -#endif - fap = &fat_archs[i]; - break; - } + struct fat_arch *fap = NULL; + for (unsigned i = 0; i < fh.nfat_arch; i++) { + if (fat_archs[i].cputype == cpu_type) { + fap = &fat_archs[i]; + break; } + } - if (!fap) { - free(fat_archs); - return (-1); - } - arch_offset = fap->offset; + if (!fap) { free(fat_archs); + return -1; + } + arch_offset = fap->offset; + free(fat_archs); - /* Read in the beginning of the architecture-specific file */ - lseek(fd, arch_offset, SEEK_SET); - if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf)) { - return (-1); - } + /* Read in the beginning of the architecture-specific file */ + if (lseek(fd, arch_offset, SEEK_SET) == -1) { + return -1; } + if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf)) { + return -1; + } + } - if (*((unsigned int *)&buf) == MH_MAGIC_64) { - struct mach_header_64 mh; - struct load_command *load_commands, *lcp; - struct symtab_command *stp; - long i; + off_t sa; /* symbol address */ + off_t ss; /* start of strings */ + register register_t n; + if (*((unsigned int *)&buf) == magic) { + if (lseek(fd, arch_offset, SEEK_SET) == -1) { + return -1; + } + mach_header_type mh; + if (read(fd, (char *)&mh, sizeof(mh)) != sizeof(mh)) { + return -1; + } - lseek(fd, arch_offset, SEEK_SET); - if (read(fd, (char *)&mh, sizeof(mh)) != sizeof(mh)) { - return (-1); - } - load_commands = (struct load_command *)malloc(mh.sizeofcmds); - if (load_commands == NULL) { - return (-1); - } - if (read(fd, (char *)load_commands, mh.sizeofcmds) != - mh.sizeofcmds) { + struct load_command *load_commands = + (struct load_command *)malloc(mh.sizeofcmds); + if (load_commands == NULL) { + return -1; + } + if (read(fd, (char *)load_commands, mh.sizeofcmds) != + mh.sizeofcmds) { + free(load_commands); + return -1; + } + struct symtab_command *stp = NULL; + struct load_command *lcp = load_commands; + // iterate through all load commands, looking for + // LC_SYMTAB load command + for (long i = 0; i < mh.ncmds; i++) { + if (lcp->cmdsize % sizeof(word_type) != 0 || + lcp->cmdsize <= 0 || + (char *)lcp + lcp->cmdsize > + (char *)load_commands + mh.sizeofcmds) { free(load_commands); - return (-1); + return -1; } - stp = NULL; - lcp = load_commands; - // nealsid:iterate through all load commands, looking for - // LC_SYMTAB load command - for (i = 0; i < mh.ncmds; i++) { - if (lcp->cmdsize % sizeof(long) != 0 || - lcp->cmdsize <= 0 || - (char *)lcp + lcp->cmdsize > - (char *)load_commands + mh.sizeofcmds) { + if (lcp->cmd == LC_SYMTAB) { + if (lcp->cmdsize != + sizeof(struct symtab_command)) { free(load_commands); - return (-1); - } - if (lcp->cmd == LC_SYMTAB) { - if (lcp->cmdsize != - sizeof(struct symtab_command)) { - free(load_commands); - return (-1); - } - stp = (struct symtab_command *)lcp; - break; + return -1; } - lcp = (struct load_command *) - ((char *)lcp + lcp->cmdsize); - } - if (stp == NULL) { - free(load_commands); - return (-1); + stp = (struct symtab_command *)lcp; + break; } - // sa points to the beginning of the symbol table - sa = stp->symoff + arch_offset; - // ss points to the beginning of the string table - ss = stp->stroff + arch_offset; - // n is the number of bytes in the symbol table - // each symbol table entry is an nlist structure - n = stp->nsyms * sizeof(breakpad_nlist); - free(load_commands); + lcp = (struct load_command *) + ((char *)lcp + lcp->cmdsize); } - else { - sa = N_SYMOFF(buf) + arch_offset; - ss = sa + buf.a_syms + arch_offset; - n = buf.a_syms; + if (stp == NULL) { + free(load_commands); + return -1; } + // sa points to the beginning of the symbol table + sa = stp->symoff + arch_offset; + // ss points to the beginning of the string table + ss = stp->stroff + arch_offset; + // n is the number of bytes in the symbol table + // each symbol table entry is an nlist structure + n = stp->nsyms * sizeof(nlist_type); + free(load_commands); + } else { + sa = N_SYMOFF(buf) + arch_offset; + ss = sa + buf.a_syms + arch_offset; + n = buf.a_syms; + } - lseek(fd, sa, SEEK_SET); + if (lseek(fd, sa, SEEK_SET) == -1) { + return -1; + } + + // the algorithm here is to read the nlist entries in m-sized + // chunks into q. q is then iterated over. for each entry in q, + // use the string table index(q->n_un.n_strx) to read the symbol + // name, then scan the nlist entries passed in by the user(via p), + // and look for a match + while (n) { + nlist_type space[BUFSIZ/sizeof (nlist_type)]; + register register_t m = sizeof (space); + + if (n < m) + m = n; + if (read(fd, (char *)space, m) != m) + break; + n -= m; + long savpos = lseek(fd, 0, SEEK_CUR); + if (savpos == -1) { + return -1; + } + for (nlist_type* q = space; (m -= sizeof(nlist_type)) >= 0; q++) { + char nambuf[BUFSIZ]; - // the algorithm here is to read the nlist entries in m-sized - // chunks into q. q is then iterated over. for each entry in q, - // use the string table index(q->n_un.n_strx) to read the symbol - // name, then scan the nlist entries passed in by the user(via p), - // and look for a match - while (n) { - long savpos; + if (q->n_un.n_strx == 0 || q->n_type & N_STAB) + continue; - m = sizeof (space); - if (n < m) - m = n; - if (read(fd, (char *)space, m) != m) - break; - n -= m; - savpos = lseek(fd, 0, SEEK_CUR); - for (q = space; (m -= sizeof(breakpad_nlist)) >= 0; q++) { - char nambuf[BUFSIZ]; - - if (q->n_un.n_strx == 0 || q->n_type & N_STAB) - continue; - - // seek to the location in the binary where the symbol - // name is stored & read it into memory - lseek(fd, ss+q->n_un.n_strx, SEEK_SET); - read(fd, nambuf, maxlen+1); - s2 = nambuf; - for (p = list; - symbolNames[p-list] && - symbolNames[p-list][0]; - p++) { - // get the symbol name the user has passed in that - // corresponds to the nlist entry that we're looking at - s1 = symbolNames[p - list]; - while (*s1) { - if (*s1++ != *s2++) - goto cont; - } - if (*s2) + // seek to the location in the binary where the symbol + // name is stored & read it into memory + if (lseek(fd, ss+q->n_un.n_strx, SEEK_SET) == -1) { + return -1; + } + if (read(fd, nambuf, maxlen+1) == -1) { + return -1; + } + const char *s2 = nambuf; + for (nlist_type *p = list; + symbolNames[p-list] && symbolNames[p-list][0]; + p++) { + // get the symbol name the user has passed in that + // corresponds to the nlist entry that we're looking at + const char *s1 = symbolNames[p - list]; + while (*s1) { + if (*s1++ != *s2++) goto cont; + } + if (*s2) + goto cont; - p->n_value = q->n_value; - p->n_type = q->n_type; - p->n_desc = q->n_desc; - p->n_sect = q->n_sect; - p->n_un.n_strx = q->n_un.n_strx; - if (--nreq == 0) - return (nreq); + p->n_value = q->n_value; + p->n_type = q->n_type; + p->n_desc = q->n_desc; + p->n_sect = q->n_sect; + p->n_un.n_strx = q->n_un.n_strx; + if (--nreq == 0) + return nreq; - break; - cont: ; - } + break; + cont: ; } - lseek(fd, savpos, SEEK_SET); } - return (nreq); + if (lseek(fd, savpos, SEEK_SET) == -1) { + return -1; + } } - -#endif /* __LP64__ */ + return nreq; +} |