]>
Commit | Line | Data |
---|---|---|
6d2010ae A |
1 | /* |
2 | * Copyright (c) 2006 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 | #include <libc.h> | |
24 | #include <errno.h> | |
25 | #include <ctype.h> | |
26 | ||
27 | #include <sys/stat.h> | |
28 | #include <sys/file.h> | |
29 | #include <sys/mman.h> | |
30 | ||
31 | #include <mach-o/arch.h> | |
32 | #include <mach-o/fat.h> | |
33 | #include <mach-o/loader.h> | |
34 | #include <mach-o/nlist.h> | |
35 | #include <mach-o/swap.h> | |
36 | ||
37 | #include <uuid/uuid.h> | |
38 | ||
39 | #include <IOKit/IOTypes.h> | |
40 | ||
41 | #pragma mark Typedefs, Enums, Constants | |
42 | /********************************************************************* | |
43 | * Typedefs, Enums, Constants | |
44 | *********************************************************************/ | |
45 | typedef enum { | |
46 | kErrorNone = 0, | |
47 | kError, | |
48 | kErrorFileAccess, | |
49 | kErrorDiskFull, | |
50 | kErrorDuplicate | |
51 | } ToolError; | |
52 | ||
53 | #pragma mark Function Protos | |
54 | /********************************************************************* | |
55 | * Function Protos | |
56 | *********************************************************************/ | |
57 | __private_extern__ ToolError | |
58 | readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize); | |
59 | ||
60 | __private_extern__ ToolError | |
61 | writeFile(int fd, const void * data, size_t length); | |
62 | ||
63 | extern char* __cxa_demangle (const char* mangled_name, | |
64 | char* buf, | |
65 | size_t* n, | |
66 | int* status); | |
67 | ||
68 | #pragma mark Functions | |
69 | /********************************************************************* | |
70 | *********************************************************************/ | |
71 | __private_extern__ ToolError | |
72 | writeFile(int fd, const void * data, size_t length) | |
73 | { | |
74 | ToolError err; | |
75 | ||
76 | if (length != (size_t)write(fd, data, length)) | |
77 | err = kErrorDiskFull; | |
78 | else | |
79 | err = kErrorNone; | |
80 | ||
81 | if (kErrorNone != err) | |
82 | perror("couldn't write output"); | |
83 | ||
84 | return( err ); | |
85 | } | |
86 | ||
87 | /********************************************************************* | |
88 | *********************************************************************/ | |
89 | __private_extern__ ToolError | |
90 | readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize) | |
91 | { | |
92 | ToolError err = kErrorFileAccess; | |
93 | int fd; | |
94 | struct stat stat_buf; | |
95 | ||
96 | *objAddr = 0; | |
97 | *objSize = 0; | |
98 | ||
99 | do | |
100 | { | |
101 | if((fd = open(path, O_RDONLY)) == -1) | |
102 | continue; | |
103 | ||
104 | if(fstat(fd, &stat_buf) == -1) | |
105 | continue; | |
106 | ||
107 | if (0 == (stat_buf.st_mode & S_IFREG)) | |
108 | continue; | |
109 | ||
110 | /* Don't try to map an empty file, it fails now due to conformance | |
111 | * stuff (PR 4611502). | |
112 | */ | |
113 | if (0 == stat_buf.st_size) { | |
114 | err = kErrorNone; | |
115 | continue; | |
116 | } | |
117 | ||
118 | *objSize = stat_buf.st_size; | |
119 | ||
120 | *objAddr = (vm_offset_t)mmap(NULL /* address */, *objSize, | |
121 | PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE /* flags */, | |
122 | fd, 0 /* offset */); | |
123 | ||
124 | if ((void *)*objAddr == MAP_FAILED) { | |
125 | *objAddr = 0; | |
126 | *objSize = 0; | |
127 | continue; | |
128 | } | |
129 | ||
130 | err = kErrorNone; | |
131 | ||
132 | } while( false ); | |
133 | ||
134 | if (-1 != fd) | |
135 | { | |
136 | close(fd); | |
137 | } | |
138 | if (kErrorNone != err) | |
139 | { | |
140 | fprintf(stderr, "couldn't read %s: %s\n", path, strerror(errno)); | |
141 | } | |
142 | ||
143 | return( err ); | |
144 | } | |
145 | ||
146 | ||
147 | enum { kExported = 0x00000001, kObsolete = 0x00000002 }; | |
148 | ||
149 | struct symbol { | |
150 | char * name; | |
151 | unsigned int name_len; | |
152 | char * indirect; | |
153 | unsigned int indirect_len; | |
154 | unsigned int flags; | |
155 | struct symbol * list; | |
156 | unsigned int list_count; | |
157 | }; | |
158 | ||
159 | static bool issymchar( char c ) | |
160 | { | |
161 | return ((c > ' ') && (c <= '~') && (c != ':') && (c != '#')); | |
162 | } | |
163 | ||
164 | static bool iswhitespace( char c ) | |
165 | { | |
166 | return ((c == ' ') || (c == '\t')); | |
167 | } | |
168 | ||
169 | /* | |
170 | * Function for qsort for comparing symbol list names. | |
171 | */ | |
172 | static int | |
173 | qsort_cmp(const void * _left, const void * _right) | |
174 | { | |
175 | struct symbol * left = (struct symbol *) _left; | |
176 | struct symbol * right = (struct symbol *) _right; | |
177 | ||
178 | return (strcmp(left->name, right->name)); | |
179 | } | |
180 | ||
181 | /* | |
182 | * Function for bsearch for finding a symbol name. | |
183 | */ | |
184 | ||
185 | static int | |
186 | bsearch_cmp( const void * _key, const void * _cmp) | |
187 | { | |
188 | char * key = (char *)_key; | |
189 | struct symbol * cmp = (struct symbol *) _cmp; | |
190 | ||
191 | return(strcmp(key, cmp->name)); | |
192 | } | |
193 | ||
194 | struct bsearch_key | |
195 | { | |
196 | char * name; | |
197 | unsigned int name_len; | |
198 | }; | |
199 | ||
200 | static int | |
201 | bsearch_cmp_prefix( const void * _key, const void * _cmp) | |
202 | { | |
203 | struct bsearch_key * key = (struct bsearch_key *)_key; | |
204 | struct symbol * cmp = (struct symbol *) _cmp; | |
205 | ||
206 | return(strncmp(key->name, cmp->name, key->name_len)); | |
207 | } | |
208 | ||
209 | static uint32_t | |
210 | count_symbols(char * file, vm_size_t file_size) | |
211 | { | |
212 | uint32_t nsyms = 0; | |
213 | char * scan; | |
214 | char * eol; | |
215 | char * next; | |
216 | ||
217 | for (scan = file; true; scan = next) { | |
218 | ||
219 | eol = memchr(scan, '\n', file_size - (scan - file)); | |
220 | if (eol == NULL) { | |
221 | break; | |
222 | } | |
223 | next = eol + 1; | |
224 | ||
225 | /* Skip empty lines. | |
226 | */ | |
227 | if (eol == scan) { | |
228 | continue; | |
229 | } | |
230 | ||
231 | /* Skip comment lines. | |
232 | */ | |
233 | if (scan[0] == '#') { | |
234 | continue; | |
235 | } | |
236 | ||
237 | /* Scan past any non-symbol characters at the beginning of the line. */ | |
238 | while ((scan < eol) && !issymchar(*scan)) { | |
239 | scan++; | |
240 | } | |
241 | ||
242 | /* No symbol on line? Move along. | |
243 | */ | |
244 | if (scan == eol) { | |
245 | continue; | |
246 | } | |
247 | ||
248 | /* Skip symbols starting with '.'. | |
249 | */ | |
250 | if (scan[0] == '.') { | |
251 | continue; | |
252 | } | |
253 | nsyms++; | |
254 | } | |
255 | ||
256 | return nsyms; | |
257 | } | |
258 | ||
259 | static uint32_t | |
260 | store_symbols(char * file, vm_size_t file_size, struct symbol * symbols, uint32_t idx, uint32_t max_symbols) | |
261 | { | |
262 | char * scan; | |
263 | char * line; | |
264 | char * eol; | |
265 | char * next; | |
266 | ||
267 | uint32_t strtabsize; | |
268 | ||
269 | strtabsize = 0; | |
270 | ||
271 | for (scan = file, line = file; true; scan = next, line = next) { | |
272 | ||
273 | char * name = NULL; | |
274 | char * name_term = NULL; | |
275 | unsigned int name_len = 0; | |
276 | char * indirect = NULL; | |
277 | char * indirect_term = NULL; | |
278 | unsigned int indirect_len = 0; | |
279 | char * option = NULL; | |
280 | char * option_term = NULL; | |
281 | unsigned int option_len = 0; | |
282 | char optionstr[256]; | |
283 | boolean_t obsolete = 0; | |
284 | ||
285 | eol = memchr(scan, '\n', file_size - (scan - file)); | |
286 | if (eol == NULL) { | |
287 | break; | |
288 | } | |
289 | next = eol + 1; | |
290 | ||
291 | /* Skip empty lines. | |
292 | */ | |
293 | if (eol == scan) { | |
294 | continue; | |
295 | } | |
296 | ||
297 | *eol = '\0'; | |
298 | ||
299 | /* Skip comment lines. | |
300 | */ | |
301 | if (scan[0] == '#') { | |
302 | continue; | |
303 | } | |
304 | ||
305 | /* Scan past any non-symbol characters at the beginning of the line. */ | |
306 | while ((scan < eol) && !issymchar(*scan)) { | |
307 | scan++; | |
308 | } | |
309 | ||
310 | /* No symbol on line? Move along. | |
311 | */ | |
312 | if (scan == eol) { | |
313 | continue; | |
314 | } | |
315 | ||
316 | /* Skip symbols starting with '.'. | |
317 | */ | |
318 | if (scan[0] == '.') { | |
319 | continue; | |
320 | } | |
321 | ||
322 | name = scan; | |
323 | ||
324 | /* Find the end of the symbol. | |
325 | */ | |
326 | while ((*scan != '\0') && issymchar(*scan)) { | |
327 | scan++; | |
328 | } | |
329 | ||
330 | /* Note char past end of symbol. | |
331 | */ | |
332 | name_term = scan; | |
333 | ||
334 | /* Stored length must include the terminating nul char. | |
335 | */ | |
336 | name_len = name_term - name + 1; | |
337 | ||
338 | /* Now look for an indirect. | |
339 | */ | |
340 | if (*scan != '\0') { | |
341 | while ((*scan != '\0') && iswhitespace(*scan)) { | |
342 | scan++; | |
343 | } | |
344 | if (*scan == ':') { | |
345 | scan++; | |
346 | while ((*scan != '\0') && iswhitespace(*scan)) { | |
347 | scan++; | |
348 | } | |
349 | if (issymchar(*scan)) { | |
350 | indirect = scan; | |
351 | ||
352 | /* Find the end of the symbol. | |
353 | */ | |
354 | while ((*scan != '\0') && issymchar(*scan)) { | |
355 | scan++; | |
356 | } | |
357 | ||
358 | /* Note char past end of symbol. | |
359 | */ | |
360 | indirect_term = scan; | |
361 | ||
362 | /* Stored length must include the terminating nul char. | |
363 | */ | |
364 | indirect_len = indirect_term - indirect + 1; | |
365 | ||
366 | } else if (*scan == '\0') { | |
367 | fprintf(stderr, "bad format in symbol line: %s\n", line); | |
368 | exit(1); | |
369 | } | |
370 | } else if (*scan != '\0' && *scan != '-') { | |
371 | fprintf(stderr, "bad format in symbol line: %s\n", line); | |
372 | exit(1); | |
373 | } | |
374 | } | |
375 | ||
376 | /* Look for options. | |
377 | */ | |
378 | if (*scan != '\0') { | |
379 | while ((*scan != '\0') && iswhitespace(*scan)) { | |
380 | scan++; | |
381 | } | |
382 | ||
383 | if (*scan == '-') { | |
384 | scan++; | |
385 | ||
386 | if (isalpha(*scan)) { | |
387 | option = scan; | |
388 | ||
389 | /* Find the end of the option. | |
390 | */ | |
391 | while ((*scan != '\0') && isalpha(*scan)) { | |
392 | scan++; | |
393 | } | |
394 | ||
395 | /* Note char past end of option. | |
396 | */ | |
397 | option_term = scan; | |
398 | option_len = option_term - option; | |
399 | ||
400 | if (option_len >= sizeof(optionstr)) { | |
401 | fprintf(stderr, "option too long in symbol line: %s\n", line); | |
402 | exit(1); | |
403 | } | |
404 | memcpy(optionstr, option, option_len); | |
405 | optionstr[option_len] = '\0'; | |
406 | ||
407 | /* Find the option. | |
408 | */ | |
409 | if (!strncmp(optionstr, "obsolete", option_len)) { | |
410 | obsolete = TRUE; | |
411 | } | |
412 | ||
413 | } else if (*scan == '\0') { | |
414 | fprintf(stderr, "bad format in symbol line: %s\n", line); | |
415 | exit(1); | |
416 | } | |
417 | ||
418 | } | |
419 | ||
420 | } | |
421 | ||
422 | if(idx >= max_symbols) { | |
423 | fprintf(stderr, "symbol[%d/%d] overflow: %s\n", idx, max_symbols, line); | |
424 | exit(1); | |
425 | } | |
426 | ||
427 | *name_term = '\0'; | |
428 | if (indirect_term) { | |
429 | *indirect_term = '\0'; | |
430 | } | |
431 | ||
432 | symbols[idx].name = name; | |
433 | symbols[idx].name_len = name_len; | |
434 | symbols[idx].indirect = indirect; | |
435 | symbols[idx].indirect_len = indirect_len; | |
436 | symbols[idx].flags = (obsolete) ? kObsolete : 0; | |
437 | ||
438 | strtabsize += symbols[idx].name_len + symbols[idx].indirect_len; | |
439 | idx++; | |
440 | } | |
441 | ||
442 | return strtabsize; | |
443 | } | |
444 | ||
445 | /********************************************************************* | |
446 | *********************************************************************/ | |
447 | int main(int argc, char * argv[]) | |
448 | { | |
449 | ToolError err; | |
450 | int i, fd; | |
451 | const char * output_name = NULL; | |
452 | uint32_t zero = 0, num_files = 0; | |
453 | uint32_t filenum; | |
454 | uint32_t strx, strtabsize, strtabpad; | |
455 | struct symbol * import_symbols; | |
456 | struct symbol * export_symbols; | |
457 | uint32_t num_import_syms, num_export_syms; | |
458 | uint32_t result_count, num_removed_syms; | |
459 | uint32_t import_idx, export_idx; | |
460 | const NXArchInfo * host_arch; | |
461 | const NXArchInfo * target_arch; | |
462 | boolean_t require_imports = true; | |
463 | boolean_t diff = false; | |
464 | ||
465 | ||
466 | struct file { | |
467 | vm_offset_t mapped; | |
468 | vm_size_t mapped_size; | |
469 | uint32_t nsyms; | |
470 | boolean_t import; | |
471 | const char * path; | |
472 | }; | |
473 | struct file files[64]; | |
474 | ||
475 | host_arch = NXGetLocalArchInfo(); | |
476 | target_arch = host_arch; | |
477 | ||
478 | for( i = 1; i < argc; i += 2) | |
479 | { | |
480 | boolean_t import; | |
481 | ||
482 | if (!strcmp("-sect", argv[i])) | |
483 | { | |
484 | require_imports = false; | |
485 | i--; | |
486 | continue; | |
487 | } | |
488 | if (!strcmp("-diff", argv[i])) | |
489 | { | |
490 | require_imports = false; | |
491 | diff = true; | |
492 | i--; | |
493 | continue; | |
494 | } | |
495 | ||
496 | if (i == (argc - 1)) | |
497 | { | |
498 | fprintf(stderr, "bad arguments: %s\n", argv[i]); | |
499 | exit(1); | |
500 | } | |
501 | ||
502 | if (!strcmp("-arch", argv[i])) | |
503 | { | |
504 | target_arch = NXGetArchInfoFromName(argv[i + 1]); | |
505 | if (!target_arch) | |
506 | { | |
507 | fprintf(stderr, "unknown architecture name: %s\n", argv[i+1]); | |
508 | exit(1); | |
509 | } | |
510 | continue; | |
511 | } | |
512 | if (!strcmp("-output", argv[i])) | |
513 | { | |
514 | output_name = argv[i+1]; | |
515 | continue; | |
516 | } | |
517 | ||
518 | if (!strcmp("-import", argv[i])) | |
519 | import = true; | |
520 | else if (!strcmp("-export", argv[i])) | |
521 | import = false; | |
522 | else | |
523 | { | |
524 | fprintf(stderr, "unknown option: %s\n", argv[i]); | |
525 | exit(1); | |
526 | } | |
527 | ||
528 | err = readFile(argv[i+1], &files[num_files].mapped, &files[num_files].mapped_size); | |
529 | if (kErrorNone != err) | |
530 | exit(1); | |
531 | ||
532 | if (files[num_files].mapped && files[num_files].mapped_size) | |
533 | { | |
534 | files[num_files].import = import; | |
535 | files[num_files].path = argv[i+1]; | |
536 | num_files++; | |
537 | } | |
538 | } | |
539 | ||
540 | if (!output_name) | |
541 | { | |
542 | fprintf(stderr, "no output file\n"); | |
543 | exit(1); | |
544 | } | |
545 | ||
546 | num_import_syms = 0; | |
547 | num_export_syms = 0; | |
548 | for (filenum = 0; filenum < num_files; filenum++) | |
549 | { | |
550 | files[filenum].nsyms = count_symbols((char *) files[filenum].mapped, files[filenum].mapped_size); | |
551 | if (files[filenum].import) | |
552 | num_import_syms += files[filenum].nsyms; | |
553 | else | |
554 | num_export_syms += files[filenum].nsyms; | |
555 | } | |
556 | if (!num_export_syms) | |
557 | { | |
558 | fprintf(stderr, "no export names\n"); | |
559 | exit(1); | |
560 | } | |
561 | ||
562 | import_symbols = calloc(num_import_syms, sizeof(struct symbol)); | |
563 | export_symbols = calloc(num_export_syms, sizeof(struct symbol)); | |
564 | ||
565 | import_idx = 0; | |
566 | export_idx = 0; | |
567 | ||
568 | for (filenum = 0; filenum < num_files; filenum++) | |
569 | { | |
570 | if (files[filenum].import) | |
571 | { | |
572 | store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size, | |
573 | import_symbols, import_idx, num_import_syms); | |
574 | import_idx += files[filenum].nsyms; | |
575 | } | |
576 | else | |
577 | { | |
578 | store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size, | |
579 | export_symbols, export_idx, num_export_syms); | |
580 | export_idx += files[filenum].nsyms; | |
581 | } | |
582 | if (false && !files[filenum].nsyms) | |
583 | { | |
584 | fprintf(stderr, "warning: file %s contains no names\n", files[filenum].path); | |
585 | } | |
586 | } | |
587 | ||
588 | ||
589 | qsort(import_symbols, num_import_syms, sizeof(struct symbol), &qsort_cmp); | |
590 | qsort(export_symbols, num_export_syms, sizeof(struct symbol), &qsort_cmp); | |
591 | ||
592 | result_count = 0; | |
593 | num_removed_syms = 0; | |
594 | strtabsize = 4; | |
595 | if (num_import_syms) | |
596 | { | |
597 | for (export_idx = 0; export_idx < num_export_syms; export_idx++) | |
598 | { | |
599 | struct symbol * result; | |
600 | char * name; | |
601 | size_t len; | |
602 | boolean_t wild; | |
603 | ||
604 | name = export_symbols[export_idx].indirect; | |
605 | len = export_symbols[export_idx].indirect_len; | |
606 | if (!name) | |
607 | { | |
608 | name = export_symbols[export_idx].name; | |
609 | len = export_symbols[export_idx].name_len; | |
610 | } | |
611 | wild = ((len > 2) && ('*' == name[len-=2])); | |
612 | if (wild) | |
613 | { | |
614 | struct bsearch_key key; | |
615 | key.name = name; | |
616 | key.name_len = len; | |
617 | result = bsearch(&key, import_symbols, | |
618 | num_import_syms, sizeof(struct symbol), &bsearch_cmp_prefix); | |
619 | ||
620 | if (result) | |
621 | { | |
622 | struct symbol * first; | |
623 | struct symbol * last; | |
624 | ||
625 | strtabsize += (result->name_len + result->indirect_len); | |
626 | ||
627 | first = result; | |
628 | while (--first >= &import_symbols[0]) | |
629 | { | |
630 | if (bsearch_cmp_prefix(&key, first)) | |
631 | break; | |
632 | strtabsize += (first->name_len + first->indirect_len); | |
633 | } | |
634 | first++; | |
635 | ||
636 | last = result; | |
637 | while (++last < (&import_symbols[0] + num_import_syms)) | |
638 | { | |
639 | if (bsearch_cmp_prefix(&key, last)) | |
640 | break; | |
641 | strtabsize += (last->name_len + last->indirect_len); | |
642 | } | |
643 | result_count += last - first; | |
644 | result = first; | |
645 | export_symbols[export_idx].list = first; | |
646 | export_symbols[export_idx].list_count = last - first; | |
647 | export_symbols[export_idx].flags |= kExported; | |
648 | } | |
649 | } | |
650 | else | |
651 | result = bsearch(name, import_symbols, | |
652 | num_import_syms, sizeof(struct symbol), &bsearch_cmp); | |
653 | ||
654 | if (!result && require_imports) | |
655 | { | |
656 | int status; | |
657 | char * demangled_result = | |
658 | __cxa_demangle(export_symbols[export_idx].name + 1, NULL, NULL, &status); | |
659 | fprintf(stderr, "exported name not in import list: %s\n", | |
660 | demangled_result ? demangled_result : export_symbols[export_idx].name); | |
661 | // fprintf(stderr, " : %s\n", export_symbols[export_idx].name); | |
662 | if (demangled_result) { | |
663 | free(demangled_result); | |
664 | } | |
665 | num_removed_syms++; | |
666 | } | |
667 | if (diff) | |
668 | { | |
669 | if (!result) | |
670 | result = &export_symbols[export_idx]; | |
671 | else | |
672 | result = NULL; | |
673 | } | |
674 | if (result && !wild) | |
675 | { | |
676 | export_symbols[export_idx].flags |= kExported; | |
677 | strtabsize += (export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len); | |
678 | result_count++; | |
679 | export_symbols[export_idx].list = &export_symbols[export_idx]; | |
680 | export_symbols[export_idx].list_count = 1; | |
681 | } | |
682 | } | |
683 | } | |
684 | strtabpad = (strtabsize + 3) & ~3; | |
685 | ||
686 | if (require_imports && num_removed_syms) | |
687 | { | |
688 | err = kError; | |
689 | goto finish; | |
690 | } | |
691 | ||
692 | fd = open(output_name, O_WRONLY|O_CREAT|O_TRUNC, 0755); | |
693 | if (-1 == fd) | |
694 | { | |
695 | perror("couldn't write output"); | |
696 | err = kErrorFileAccess; | |
697 | goto finish; | |
698 | } | |
699 | ||
700 | struct symtab_command symcmd; | |
701 | struct uuid_command uuidcmd; | |
702 | ||
703 | symcmd.cmd = LC_SYMTAB; | |
704 | symcmd.cmdsize = sizeof(symcmd); | |
705 | symcmd.symoff = sizeof(symcmd) + sizeof(uuidcmd); | |
706 | symcmd.nsyms = result_count; | |
707 | symcmd.strsize = strtabpad; | |
708 | ||
709 | uuidcmd.cmd = LC_UUID; | |
710 | uuidcmd.cmdsize = sizeof(uuidcmd); | |
711 | uuid_generate(uuidcmd.uuid); | |
712 | ||
713 | if (CPU_ARCH_ABI64 & target_arch->cputype) | |
714 | { | |
715 | struct mach_header_64 hdr; | |
716 | hdr.magic = MH_MAGIC_64; | |
717 | hdr.cputype = target_arch->cputype; | |
718 | hdr.cpusubtype = target_arch->cpusubtype; | |
719 | hdr.filetype = MH_KEXT_BUNDLE; | |
720 | hdr.ncmds = 2; | |
721 | hdr.sizeofcmds = sizeof(symcmd) + sizeof(uuidcmd); | |
722 | hdr.flags = MH_INCRLINK; | |
723 | ||
724 | symcmd.symoff += sizeof(hdr); | |
725 | symcmd.stroff = result_count * sizeof(struct nlist_64) | |
726 | + symcmd.symoff; | |
727 | ||
728 | if (target_arch->byteorder != host_arch->byteorder) | |
729 | swap_mach_header_64(&hdr, target_arch->byteorder); | |
730 | err = writeFile(fd, &hdr, sizeof(hdr)); | |
731 | } | |
732 | else | |
733 | { | |
734 | struct mach_header hdr; | |
735 | hdr.magic = MH_MAGIC; | |
736 | hdr.cputype = target_arch->cputype; | |
737 | hdr.cpusubtype = target_arch->cpusubtype; | |
738 | hdr.filetype = (target_arch->cputype == CPU_TYPE_I386) ? MH_OBJECT : MH_KEXT_BUNDLE; | |
739 | hdr.ncmds = 2; | |
740 | hdr.sizeofcmds = sizeof(symcmd) + sizeof(uuidcmd); | |
741 | hdr.flags = MH_INCRLINK; | |
742 | ||
743 | symcmd.symoff += sizeof(hdr); | |
744 | symcmd.stroff = result_count * sizeof(struct nlist) | |
745 | + symcmd.symoff; | |
746 | ||
747 | if (target_arch->byteorder != host_arch->byteorder) | |
748 | swap_mach_header(&hdr, target_arch->byteorder); | |
749 | err = writeFile(fd, &hdr, sizeof(hdr)); | |
750 | } | |
751 | ||
752 | if (kErrorNone != err) | |
753 | goto finish; | |
754 | ||
755 | if (target_arch->byteorder != host_arch->byteorder) { | |
756 | swap_symtab_command(&symcmd, target_arch->byteorder); | |
757 | swap_uuid_command(&uuidcmd, target_arch->byteorder); | |
758 | } | |
759 | err = writeFile(fd, &symcmd, sizeof(symcmd)); | |
760 | if (kErrorNone != err) | |
761 | goto finish; | |
762 | err = writeFile(fd, &uuidcmd, sizeof(uuidcmd)); | |
763 | if (kErrorNone != err) | |
764 | goto finish; | |
765 | ||
766 | strx = 4; | |
767 | for (export_idx = 0; export_idx < num_export_syms; export_idx++) | |
768 | { | |
769 | if (!export_symbols[export_idx].name) | |
770 | continue; | |
771 | if (!(kExported & export_symbols[export_idx].flags)) | |
772 | continue; | |
773 | ||
774 | if (export_idx | |
775 | && export_symbols[export_idx - 1].name | |
776 | && !strcmp(export_symbols[export_idx - 1].name, export_symbols[export_idx].name)) | |
777 | { | |
778 | fprintf(stderr, "duplicate export: %s\n", export_symbols[export_idx - 1].name); | |
779 | err = kErrorDuplicate; | |
780 | goto finish; | |
781 | } | |
782 | ||
783 | for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++) | |
784 | { | |
785 | ||
786 | if (export_symbols[export_idx].list != &export_symbols[export_idx]) | |
787 | { | |
788 | printf("wild: %s, %s\n", export_symbols[export_idx].name, | |
789 | export_symbols[export_idx].list[import_idx].name); | |
790 | } | |
791 | if (CPU_ARCH_ABI64 & target_arch->cputype) | |
792 | { | |
793 | struct nlist_64 nl; | |
794 | ||
795 | nl.n_sect = 0; | |
796 | nl.n_desc = 0; | |
797 | nl.n_un.n_strx = strx; | |
798 | strx += export_symbols[export_idx].list[import_idx].name_len; | |
799 | ||
800 | if (export_symbols[export_idx].flags & kObsolete) { | |
801 | nl.n_desc |= N_DESC_DISCARDED; | |
802 | } | |
803 | ||
804 | if (export_symbols[export_idx].list[import_idx].indirect) | |
805 | { | |
806 | nl.n_type = N_INDR | N_EXT; | |
807 | nl.n_value = strx; | |
808 | strx += export_symbols[export_idx].list[import_idx].indirect_len; | |
809 | } | |
810 | else | |
811 | { | |
812 | nl.n_type = N_UNDF | N_EXT; | |
813 | nl.n_value = 0; | |
814 | } | |
815 | ||
816 | if (target_arch->byteorder != host_arch->byteorder) | |
817 | swap_nlist_64(&nl, 1, target_arch->byteorder); | |
818 | ||
819 | err = writeFile(fd, &nl, sizeof(nl)); | |
820 | } | |
821 | else | |
822 | { | |
823 | struct nlist nl; | |
824 | ||
825 | nl.n_sect = 0; | |
826 | nl.n_desc = 0; | |
827 | nl.n_un.n_strx = strx; | |
828 | strx += export_symbols[export_idx].list[import_idx].name_len; | |
829 | ||
830 | if (export_symbols[export_idx].flags & kObsolete) { | |
831 | nl.n_desc |= N_DESC_DISCARDED; | |
832 | } | |
833 | ||
834 | if (export_symbols[export_idx].list[import_idx].indirect) | |
835 | { | |
836 | nl.n_type = N_INDR | N_EXT; | |
837 | nl.n_value = strx; | |
838 | strx += export_symbols[export_idx].list[import_idx].indirect_len; | |
839 | } | |
840 | else | |
841 | { | |
842 | nl.n_type = N_UNDF | N_EXT; | |
843 | nl.n_value = 0; | |
844 | } | |
845 | ||
846 | if (target_arch->byteorder != host_arch->byteorder) | |
847 | swap_nlist(&nl, 1, target_arch->byteorder); | |
848 | ||
849 | err = writeFile(fd, &nl, sizeof(nl)); | |
850 | } | |
851 | } | |
852 | ||
853 | if (kErrorNone != err) | |
854 | goto finish; | |
855 | } | |
856 | ||
857 | strx = sizeof(uint32_t); | |
858 | err = writeFile(fd, &zero, strx); | |
859 | if (kErrorNone != err) | |
860 | goto finish; | |
861 | ||
862 | for (export_idx = 0; export_idx < num_export_syms; export_idx++) | |
863 | { | |
864 | if (!export_symbols[export_idx].name) | |
865 | continue; | |
866 | ||
867 | for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++) | |
868 | { | |
869 | err = writeFile(fd, export_symbols[export_idx].list[import_idx].name, | |
870 | export_symbols[export_idx].list[import_idx].name_len); | |
871 | if (kErrorNone != err) | |
872 | goto finish; | |
873 | if (export_symbols[export_idx].list[import_idx].indirect) | |
874 | { | |
875 | err = writeFile(fd, export_symbols[export_idx].list[import_idx].indirect, | |
876 | export_symbols[export_idx].list[import_idx].indirect_len); | |
877 | if (kErrorNone != err) | |
878 | goto finish; | |
879 | } | |
880 | } | |
881 | } | |
882 | ||
883 | err = writeFile(fd, &zero, strtabpad - strtabsize); | |
884 | if (kErrorNone != err) | |
885 | goto finish; | |
886 | ||
887 | close(fd); | |
888 | ||
889 | ||
890 | finish: | |
891 | for (filenum = 0; filenum < num_files; filenum++) { | |
892 | // unmap file | |
893 | if (files[filenum].mapped_size) | |
894 | { | |
895 | munmap((caddr_t)files[filenum].mapped, files[filenum].mapped_size); | |
896 | files[filenum].mapped = 0; | |
897 | files[filenum].mapped_size = 0; | |
898 | } | |
899 | ||
900 | } | |
901 | ||
902 | if (kErrorNone != err) | |
903 | { | |
904 | if (output_name) | |
905 | unlink(output_name); | |
906 | exit(1); | |
907 | } | |
908 | else | |
909 | exit(0); | |
910 | return(0); | |
911 | } | |
912 |