/thirdparty/breakpad/client/mac/handler/breakpad_nlist_64.cc

http://github.com/tomahawk-player/tomahawk · C++ · 413 lines · 273 code · 39 blank · 101 comment · 76 complexity · d608acb4097418f3d80d970d556d395c MD5 · raw file

  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. * This file was copied from libc/gen/nlist.c from Darwin's source code
  57. * The version of nlist used as a base is from 10.5.2, libc-498
  58. * http://www.opensource.apple.com/darwinsource/10.5.2/Libc-498/gen/nlist.c
  59. *
  60. * The full tarball is at:
  61. * http://www.opensource.apple.com/darwinsource/tarballs/apsl/Libc-498.tar.gz
  62. *
  63. * I've modified it to be compatible with 64-bit images.
  64. */
  65. #include "breakpad_nlist_64.h"
  66. #include <CoreFoundation/CoreFoundation.h>
  67. #include <fcntl.h>
  68. #include <mach-o/nlist.h>
  69. #include <mach-o/loader.h>
  70. #include <mach-o/fat.h>
  71. #include <mach/mach.h>
  72. #include <stdio.h>
  73. #include <stdlib.h>
  74. #include <sys/types.h>
  75. #include <sys/uio.h>
  76. #include <TargetConditionals.h>
  77. #include <unistd.h>
  78. /* Stuff lifted from <a.out.h> and <sys/exec.h> since they are gone */
  79. /*
  80. * Header prepended to each a.out file.
  81. */
  82. struct exec {
  83. unsigned short a_machtype; /* machine type */
  84. unsigned short a_magic; /* magic number */
  85. unsigned long a_text; /* size of text segment */
  86. unsigned long a_data; /* size of initialized data */
  87. unsigned long a_bss; /* size of uninitialized data */
  88. unsigned long a_syms; /* size of symbol table */
  89. unsigned long a_entry; /* entry point */
  90. unsigned long a_trsize; /* size of text relocation */
  91. unsigned long a_drsize; /* size of data relocation */
  92. };
  93. #define OMAGIC 0407 /* old impure format */
  94. #define NMAGIC 0410 /* read-only text */
  95. #define ZMAGIC 0413 /* demand load format */
  96. #define N_BADMAG(x) \
  97. (((x).a_magic)!=OMAGIC && ((x).a_magic)!=NMAGIC && ((x).a_magic)!=ZMAGIC)
  98. #define N_TXTOFF(x) \
  99. ((x).a_magic==ZMAGIC ? 0 : sizeof (struct exec))
  100. #define N_SYMOFF(x) \
  101. (N_TXTOFF(x) + (x).a_text+(x).a_data + (x).a_trsize+(x).a_drsize)
  102. // Traits structs for specializing function templates to handle
  103. // 32-bit/64-bit Mach-O files.
  104. template<typename T>
  105. struct MachBits {};
  106. typedef struct nlist nlist32;
  107. typedef struct nlist_64 nlist64;
  108. template<>
  109. struct MachBits<nlist32> {
  110. typedef mach_header mach_header_type;
  111. typedef uint32_t word_type;
  112. static const uint32_t magic = MH_MAGIC;
  113. };
  114. template<>
  115. struct MachBits<nlist64> {
  116. typedef mach_header_64 mach_header_type;
  117. typedef uint64_t word_type;
  118. static const uint32_t magic = MH_MAGIC_64;
  119. };
  120. template<typename nlist_type>
  121. int
  122. __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
  123. cpu_type_t cpu_type);
  124. /*
  125. * nlist - retreive attributes from name list (string table version)
  126. */
  127. template <typename nlist_type>
  128. int breakpad_nlist_common(const char *name,
  129. nlist_type *list,
  130. const char **symbolNames,
  131. cpu_type_t cpu_type) {
  132. int fd = open(name, O_RDONLY, 0);
  133. if (fd < 0)
  134. return -1;
  135. int n = __breakpad_fdnlist(fd, list, symbolNames, cpu_type);
  136. close(fd);
  137. return n;
  138. }
  139. int breakpad_nlist(const char *name,
  140. struct nlist *list,
  141. const char **symbolNames,
  142. cpu_type_t cpu_type) {
  143. return breakpad_nlist_common(name, list, symbolNames, cpu_type);
  144. }
  145. int breakpad_nlist(const char *name,
  146. struct nlist_64 *list,
  147. const char **symbolNames,
  148. cpu_type_t cpu_type) {
  149. return breakpad_nlist_common(name, list, symbolNames, cpu_type);
  150. }
  151. /* Note: __fdnlist() is called from kvm_nlist in libkvm's kvm.c */
  152. template<typename nlist_type>
  153. int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
  154. cpu_type_t cpu_type) {
  155. typedef typename MachBits<nlist_type>::mach_header_type mach_header_type;
  156. typedef typename MachBits<nlist_type>::word_type word_type;
  157. const uint32_t magic = MachBits<nlist_type>::magic;
  158. int maxlen = 500;
  159. int nreq = 0;
  160. for (nlist_type* q = list;
  161. symbolNames[q-list] && symbolNames[q-list][0];
  162. q++, nreq++) {
  163. q->n_type = 0;
  164. q->n_value = 0;
  165. q->n_desc = 0;
  166. q->n_sect = 0;
  167. q->n_un.n_strx = 0;
  168. }
  169. struct exec buf;
  170. if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf) ||
  171. (N_BADMAG(buf) && *((uint32_t *)&buf) != magic &&
  172. CFSwapInt32BigToHost(*((uint32_t *)&buf)) != FAT_MAGIC &&
  173. /* The following is the big-endian ppc64 check */
  174. (*((uint32_t*)&buf)) != FAT_MAGIC)) {
  175. return -1;
  176. }
  177. /* Deal with fat file if necessary */
  178. unsigned arch_offset = 0;
  179. if (CFSwapInt32BigToHost(*((uint32_t *)&buf)) == FAT_MAGIC ||
  180. /* The following is the big-endian ppc64 check */
  181. *((unsigned int *)&buf) == FAT_MAGIC) {
  182. /* Get host info */
  183. host_t host = mach_host_self();
  184. unsigned i = HOST_BASIC_INFO_COUNT;
  185. struct host_basic_info hbi;
  186. kern_return_t kr;
  187. if ((kr = host_info(host, HOST_BASIC_INFO,
  188. (host_info_t)(&hbi), &i)) != KERN_SUCCESS) {
  189. return -1;
  190. }
  191. mach_port_deallocate(mach_task_self(), host);
  192. /* Read in the fat header */
  193. struct fat_header fh;
  194. if (lseek(fd, 0, SEEK_SET) == -1) {
  195. return -1;
  196. }
  197. if (read(fd, (char *)&fh, sizeof(fh)) != sizeof(fh)) {
  198. return -1;
  199. }
  200. /* Convert fat_narchs to host byte order */
  201. fh.nfat_arch = CFSwapInt32BigToHost(fh.nfat_arch);
  202. /* Read in the fat archs */
  203. struct fat_arch *fat_archs =
  204. (struct fat_arch *)malloc(fh.nfat_arch * sizeof(struct fat_arch));
  205. if (fat_archs == NULL) {
  206. return -1;
  207. }
  208. if (read(fd, (char *)fat_archs,
  209. sizeof(struct fat_arch) * fh.nfat_arch) !=
  210. (ssize_t)(sizeof(struct fat_arch) * fh.nfat_arch)) {
  211. free(fat_archs);
  212. return -1;
  213. }
  214. /*
  215. * Convert archs to host byte ordering (a constraint of
  216. * cpusubtype_getbestarch()
  217. */
  218. for (unsigned i = 0; i < fh.nfat_arch; i++) {
  219. fat_archs[i].cputype =
  220. CFSwapInt32BigToHost(fat_archs[i].cputype);
  221. fat_archs[i].cpusubtype =
  222. CFSwapInt32BigToHost(fat_archs[i].cpusubtype);
  223. fat_archs[i].offset =
  224. CFSwapInt32BigToHost(fat_archs[i].offset);
  225. fat_archs[i].size =
  226. CFSwapInt32BigToHost(fat_archs[i].size);
  227. fat_archs[i].align =
  228. CFSwapInt32BigToHost(fat_archs[i].align);
  229. }
  230. struct fat_arch *fap = NULL;
  231. for (unsigned i = 0; i < fh.nfat_arch; i++) {
  232. if (fat_archs[i].cputype == cpu_type) {
  233. fap = &fat_archs[i];
  234. break;
  235. }
  236. }
  237. if (!fap) {
  238. free(fat_archs);
  239. return -1;
  240. }
  241. arch_offset = fap->offset;
  242. free(fat_archs);
  243. /* Read in the beginning of the architecture-specific file */
  244. if (lseek(fd, arch_offset, SEEK_SET) == -1) {
  245. return -1;
  246. }
  247. if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf)) {
  248. return -1;
  249. }
  250. }
  251. off_t sa; /* symbol address */
  252. off_t ss; /* start of strings */
  253. register register_t n;
  254. if (*((unsigned int *)&buf) == magic) {
  255. if (lseek(fd, arch_offset, SEEK_SET) == -1) {
  256. return -1;
  257. }
  258. mach_header_type mh;
  259. if (read(fd, (char *)&mh, sizeof(mh)) != sizeof(mh)) {
  260. return -1;
  261. }
  262. struct load_command *load_commands =
  263. (struct load_command *)malloc(mh.sizeofcmds);
  264. if (load_commands == NULL) {
  265. return -1;
  266. }
  267. if (read(fd, (char *)load_commands, mh.sizeofcmds) !=
  268. (ssize_t)mh.sizeofcmds) {
  269. free(load_commands);
  270. return -1;
  271. }
  272. struct symtab_command *stp = NULL;
  273. struct load_command *lcp = load_commands;
  274. // iterate through all load commands, looking for
  275. // LC_SYMTAB load command
  276. for (uint32_t i = 0; i < mh.ncmds; i++) {
  277. if (lcp->cmdsize % sizeof(word_type) != 0 ||
  278. lcp->cmdsize <= 0 ||
  279. (char *)lcp + lcp->cmdsize >
  280. (char *)load_commands + mh.sizeofcmds) {
  281. free(load_commands);
  282. return -1;
  283. }
  284. if (lcp->cmd == LC_SYMTAB) {
  285. if (lcp->cmdsize !=
  286. sizeof(struct symtab_command)) {
  287. free(load_commands);
  288. return -1;
  289. }
  290. stp = (struct symtab_command *)lcp;
  291. break;
  292. }
  293. lcp = (struct load_command *)
  294. ((char *)lcp + lcp->cmdsize);
  295. }
  296. if (stp == NULL) {
  297. free(load_commands);
  298. return -1;
  299. }
  300. // sa points to the beginning of the symbol table
  301. sa = stp->symoff + arch_offset;
  302. // ss points to the beginning of the string table
  303. ss = stp->stroff + arch_offset;
  304. // n is the number of bytes in the symbol table
  305. // each symbol table entry is an nlist structure
  306. n = stp->nsyms * sizeof(nlist_type);
  307. free(load_commands);
  308. } else {
  309. sa = N_SYMOFF(buf) + arch_offset;
  310. ss = sa + buf.a_syms + arch_offset;
  311. n = buf.a_syms;
  312. }
  313. if (lseek(fd, sa, SEEK_SET) == -1) {
  314. return -1;
  315. }
  316. // the algorithm here is to read the nlist entries in m-sized
  317. // chunks into q. q is then iterated over. for each entry in q,
  318. // use the string table index(q->n_un.n_strx) to read the symbol
  319. // name, then scan the nlist entries passed in by the user(via p),
  320. // and look for a match
  321. while (n) {
  322. nlist_type space[BUFSIZ/sizeof (nlist_type)];
  323. register register_t m = sizeof (space);
  324. if (n < m)
  325. m = n;
  326. if (read(fd, (char *)space, m) != m)
  327. break;
  328. n -= m;
  329. long savpos = lseek(fd, 0, SEEK_CUR);
  330. if (savpos == -1) {
  331. return -1;
  332. }
  333. for (nlist_type* q = space; (m -= sizeof(nlist_type)) >= 0; q++) {
  334. char nambuf[BUFSIZ];
  335. if (q->n_un.n_strx == 0 || q->n_type & N_STAB)
  336. continue;
  337. // seek to the location in the binary where the symbol
  338. // name is stored & read it into memory
  339. if (lseek(fd, ss+q->n_un.n_strx, SEEK_SET) == -1) {
  340. return -1;
  341. }
  342. if (read(fd, nambuf, maxlen+1) == -1) {
  343. return -1;
  344. }
  345. const char *s2 = nambuf;
  346. for (nlist_type *p = list;
  347. symbolNames[p-list] && symbolNames[p-list][0];
  348. p++) {
  349. // get the symbol name the user has passed in that
  350. // corresponds to the nlist entry that we're looking at
  351. const char *s1 = symbolNames[p - list];
  352. while (*s1) {
  353. if (*s1++ != *s2++)
  354. goto cont;
  355. }
  356. if (*s2)
  357. goto cont;
  358. p->n_value = q->n_value;
  359. p->n_type = q->n_type;
  360. p->n_desc = q->n_desc;
  361. p->n_sect = q->n_sect;
  362. p->n_un.n_strx = q->n_un.n_strx;
  363. if (--nreq == 0)
  364. return nreq;
  365. break;
  366. cont: ;
  367. }
  368. }
  369. if (lseek(fd, savpos, SEEK_SET) == -1) {
  370. return -1;
  371. }
  372. }
  373. return nreq;
  374. }