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