]> git.saurik.com Git - apple/xnu.git/blob - libsa/kld_patch.c
xnu-792.25.20.tar.gz
[apple/xnu.git] / libsa / kld_patch.c
1 /*
2 * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * History:
26 * 2001-05-30 gvdl Initial implementation of the vtable patcher.
27 */
28 // 45678901234567890123456789012345678901234567890123456789012345678901234567890
29
30 #include <mach-o/fat.h>
31 #include <mach-o/loader.h>
32 #include <mach-o/nlist.h>
33 #include <mach-o/reloc.h>
34 #if !KERNEL
35 #include <mach-o/swap.h>
36 #include <libkern/OSByteOrder.h>
37 #endif
38
39 #if KERNEL
40
41 #include <stdarg.h>
42 //#include <string.h>
43
44 #include <sys/systm.h>
45
46 #include <libkern/OSTypes.h>
47
48 #include <libsa/stdlib.h>
49 #include <libsa/mach/mach.h>
50
51 #include "mach_loader.h"
52
53 #include <vm/vm_kern.h>
54
55 enum { false = 0, true = 1 };
56
57 #define vm_page_size page_size
58
59 extern void kld_error_vprintf(const char *format, va_list ap);
60
61 __private_extern__ char *strstr(const char *in, const char *str);
62 extern struct mach_header _mh_execute_header;
63 extern struct segment_command *getsegbyname(char *seg_name); // 32 bit only
64
65 #else /* !KERNEL */
66
67 #include <unistd.h>
68
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <string.h>
72
73 #include <sys/errno.h>
74 #include <sys/fcntl.h>
75 #include <sys/stat.h>
76 #include <sys/mman.h>
77 #include <sys/vm.h>
78
79 #include <mach/mach.h>
80 #include <mach/mach_error.h>
81
82 #include <mach-o/arch.h>
83
84 #include <CoreFoundation/CoreFoundation.h>
85
86 #define PAGE_SIZE vm_page_size
87 #define PAGE_MASK (PAGE_SIZE - 1)
88
89 #endif /* KERNEL */
90
91 #include "kld_patch.h"
92 #include "c++rem3.h"
93
94 #if 0
95 #define DIE() do { for (;;) ; } while(0)
96
97 #if KERNEL
98 # define LOG_DELAY() /* IODelay(200000) */
99 # define DEBUG_LOG(x) do { IOLog x; LOG_DELAY(); } while(0)
100 #else
101 # define LOG_DELAY()
102 # define DEBUG_LOG(x) do { printf x; } while(0)
103 #endif
104
105 #else
106
107 #define DIE()
108 #define LOG_DELAY()
109 #define DEBUG_LOG(x)
110
111 #endif
112
113 // OSObject symbol prefixes and suffixes
114 #define kCPPSymbolPrefix "_Z"
115 #define kVTablePrefix "_" kCPPSymbolPrefix "TV"
116 #define kOSObjPrefix "_" kCPPSymbolPrefix "N"
117 #define kReservedNamePrefix "_RESERVED"
118 #define k29SuperClassSuffix "superClass"
119 #define k31SuperClassSuffix "10superClassE"
120 #define kGMetaSuffix "10gMetaClassE"
121 #define kLinkEditSegName SEG_LINKEDIT
122
123 // GCC 2.95 drops 2 leading constants in the vtable
124 #define kVTablePreambleLen 2
125
126 // Last address that I'm willing to try find vm in
127 #define kTopAddr ((unsigned char *) (1024 * 1024 * 1024))
128
129 // Size in bytes that Data Ref object's get increased in size
130 // Must be a power of 2
131 #define kDataCapacityIncrement 128
132
133 // My usual set of helper macros. I personally find these macros
134 // easier to read in the code rather than an explicit error condition
135 // check. If I don't make it easy then I may get lazy ond not check
136 // everything. I'm sorry if you find this code harder to read.
137
138 // break_if will evaluate the expression and if it is true
139 // then it will print the msg, which is enclosed in parens
140 // and then break. Usually used in loops are do { } while (0)
141 #define break_if(expr, msg) \
142 if (expr) { \
143 errprintf msg; \
144 break; \
145 }
146
147 // return_if will evaluate expr and if true it will log the
148 // msg, which is enclosed in parens, and then it will return
149 // with the return code of ret.
150 #define return_if(expr, ret, msg) do { \
151 if (expr) { \
152 errprintf msg; \
153 return ret; \
154 } \
155 } while (0)
156
157 #ifndef MIN
158 #define MIN(a,b) (((a)<(b))?(a):(b))
159 #endif /* MIN */
160 #ifndef MAX
161 #define MAX(a,b) (((a)>(b))?(a):(b))
162 #endif /* MAX */
163
164 typedef struct Data {
165 unsigned long fLength, fCapacity;
166 unsigned char *fData;
167 } Data, *DataRef;
168
169 struct sectionRecord {
170 const struct section *fSection; // 32 bit mach object section
171 DataRef fRelocCache;
172 };
173
174 enum patchState {
175 kSymbolIdentical,
176 kSymbolLocal,
177 kSymbolPadUpdate,
178 kSymbolSuperUpdate,
179 kSymbolMismatch
180 };
181
182 struct patchRecord {
183 struct nlist *fSymbol;
184 const struct fileRecord *fFile;
185 enum patchState fType;
186 };
187
188 struct relocRecord {
189 void *fValue;
190 const struct nlist *fSymbol;
191 struct relocation_info *fRInfo;
192 void *reserved;
193 };
194
195 struct metaClassRecord {
196 char *fSuperName;
197 struct fileRecord *fFile;
198 const struct nlist *fVTableSym;
199 struct patchRecord *fPatchedVTable;
200 char fClassName[1];
201 };
202
203 struct fileRecord {
204 size_t fMapSize, fMachOSize;
205 unsigned char *fMap, *fMachO, *fPadEnd;
206 DataRef fClassList;
207 DataRef fSectData;
208 DataRef fNewSymbols, fNewStringBlocks;
209 DataRef fSym2Strings;
210 struct symtab_command *fSymtab;
211 struct sectionRecord *fSections;
212 vm_offset_t fVMAddr, fVMEnd;
213 struct segment_command *fLinkEditSeg;
214 const char **fSymbToStringTable;
215 char *fStringBase;
216 struct nlist *fSymbolBase;
217 const struct nlist *fLocalSyms;
218 unsigned int fNSects;
219 int fNLocal;
220 Boolean fIsKernel, fIsReloc, fIsIncrLink, fNoKernelExecutable, fIsKmem;
221 Boolean fImageDirty, fSymbolsDirty;
222 Boolean fRemangled, fFoundOSObject;
223 Boolean fIgnoreFile;
224 #if !KERNEL
225 Boolean fSwapped;
226 #endif
227 const char fPath[1];
228 };
229
230 static DataRef sFilesTable;
231 static struct fileRecord *sKernelFile;
232
233 static DataRef sMergedFiles;
234 static DataRef sMergeMetaClasses;
235 static Boolean sMergedKernel;
236 #if !KERNEL
237 static const NXArchInfo * sPreferArchInfo;
238 #endif
239 static const struct nlist *
240 findSymbolByName(struct fileRecord *file, const char *symname);
241
242 static void errprintf(const char *fmt, ...)
243 {
244 va_list ap;
245
246 va_start(ap, fmt);
247 kld_error_vprintf(fmt, ap);
248 va_end(ap);
249
250 DIE();
251 }
252
253 static __inline__ unsigned long DataGetLength(DataRef data)
254 {
255 return data->fLength;
256 }
257
258 static __inline__ unsigned char *DataGetPtr(DataRef data)
259 {
260 return data->fData;
261 }
262
263 static __inline__ unsigned char *DataGetEndPtr(DataRef data)
264 {
265 return data->fData + data->fLength;
266 }
267
268 static __inline__ unsigned long DataRemaining(DataRef data)
269 {
270 return data->fCapacity - data->fLength;
271 }
272
273 static __inline__ Boolean DataContainsAddr(DataRef data, void *vAddr)
274 {
275 vm_offset_t offset = (vm_address_t) vAddr;
276
277 if (!data)
278 return false;
279
280 offset = (vm_address_t) vAddr - (vm_address_t) data->fData;
281 return (offset < data->fLength);
282 }
283
284 static Boolean DataEnsureCapacity(DataRef data, unsigned long capacity)
285 {
286 // Don't bother to ever shrink a data object.
287 if (capacity > data->fCapacity) {
288 unsigned char *newData;
289
290 capacity += kDataCapacityIncrement - 1;
291 capacity &= ~(kDataCapacityIncrement - 1);
292 newData = (unsigned char *) realloc(data->fData, capacity);
293 if (!newData)
294 return false;
295
296 bzero(newData + data->fCapacity, capacity - data->fCapacity);
297 data->fData = newData;
298 data->fCapacity = capacity;
299 }
300
301 return true;
302 }
303
304 static __inline__ Boolean DataSetLength(DataRef data, unsigned long length)
305 {
306 if (DataEnsureCapacity(data, length)) {
307 data->fLength = length;
308 return true;
309 }
310 else
311 return false;
312 }
313
314 static __inline__ Boolean DataAddLength(DataRef data, unsigned long length)
315 {
316 return DataSetLength(data, data->fLength + length);
317 }
318
319 static __inline__ Boolean
320 DataAppendBytes(DataRef data, const void *addr, unsigned int len)
321 {
322 unsigned long size = DataGetLength(data);
323
324 if (!DataAddLength(data, len))
325 return false;
326
327 bcopy(addr, DataGetPtr(data) + size, len);
328 return true;
329 }
330
331 static __inline__ Boolean DataAppendData(DataRef dst, DataRef src)
332 {
333 return DataAppendBytes(dst, DataGetPtr(src), DataGetLength(src));
334 }
335
336 static DataRef DataCreate(unsigned long capacity)
337 {
338 DataRef data = (DataRef) malloc(sizeof(Data));
339
340 if (data) {
341 if (!capacity)
342 data->fCapacity = kDataCapacityIncrement;
343 else {
344 data->fCapacity = capacity + kDataCapacityIncrement - 1;
345 data->fCapacity &= ~(kDataCapacityIncrement - 1);
346 }
347
348 data->fData = (unsigned char *) malloc(data->fCapacity);
349 if (!data->fData) {
350 free(data);
351 return NULL;
352 }
353
354 bzero(data->fData, data->fCapacity);
355 data->fLength = 0;
356 }
357 return data;
358 }
359
360 static void DataRelease(DataRef data)
361 {
362 if (data) {
363 if (data->fData)
364 free(data->fData);
365 data->fData = 0;
366 free(data);
367 }
368 }
369
370 static __inline__ const char *
371 symNameByIndex(const struct fileRecord *file, unsigned int symInd)
372 {
373 return file->fSymbToStringTable[symInd];
374 }
375
376 static __inline__ const char *
377 symbolname(const struct fileRecord *file, const struct nlist *sym)
378 {
379 unsigned int index;
380
381 index = sym - file->fSymbolBase;
382
383 if (index && !sym->n_un.n_strx)
384 return file->fStringBase + sym->n_value;
385
386 if (index < file->fSymtab->nsyms)
387 return symNameByIndex(file, index);
388
389 if (-1 == sym->n_un.n_strx)
390 return (const char *) sym->n_value;
391
392 // If the preceding tests fail then we have a getNewSymbol patch and
393 // the file it refers to has already been patched as the n_strx is set
394 // to -1 temporarily while we are still processing a file.
395 // Once we have finished with a file then we repair the 'strx' offset
396 // to be valid for the repaired file's string table.
397 return file->fStringBase + sym->n_un.n_strx;
398 }
399
400 static struct fileRecord *
401 getFile(const char *path)
402 {
403 if (sFilesTable) {
404 int i, nfiles;
405 struct fileRecord **files;
406
407 // Check to see if we have already merged this file
408 nfiles = DataGetLength(sFilesTable) / sizeof(struct fileRecord *);
409 files = (struct fileRecord **) DataGetPtr(sFilesTable);
410 for (i = 0; i < nfiles; i++) {
411 if (!strcmp(path, files[i]->fPath))
412 return files[i];
413 }
414 }
415
416 return NULL;
417 }
418
419 static struct fileRecord *
420 addFile(struct fileRecord *file, const char *path)
421 {
422 struct fileRecord *newFile;
423
424 if (!sFilesTable) {
425 sFilesTable = DataCreate(0);
426 if (!sFilesTable)
427 return NULL;
428 }
429
430 newFile = (struct fileRecord *)
431 malloc(sizeof(struct fileRecord) + strlen(path));
432 if (!newFile)
433 return NULL;
434
435 if (!DataAppendBytes(sFilesTable, &newFile, sizeof(newFile))) {
436 free(newFile);
437 return NULL;
438 }
439
440 bcopy(file, newFile, sizeof(struct fileRecord) - 1);
441 strcpy((char *) newFile->fPath, path);
442
443 return newFile;
444 }
445
446 // @@@ gvdl: need to clean up the sMergeMetaClasses
447 // @@@ gvdl: I had better fix the object file up again
448 static void unmapFile(struct fileRecord *file)
449 {
450 if (file->fSectData) {
451 struct sectionRecord *section;
452 unsigned int i, nsect;
453
454 nsect = file->fNSects;
455 section = file->fSections;
456 for (i = 0; i < nsect; i++, section++) {
457 if (section->fRelocCache) {
458 DataRelease(section->fRelocCache);
459 section->fRelocCache = 0;
460 }
461 }
462
463 DataRelease(file->fSectData);
464 file->fSectData = 0;
465 file->fSections = 0;
466 file->fNSects = 0;
467 }
468
469 if (file->fSym2Strings) {
470 DataRelease(file->fSym2Strings);
471 file->fSym2Strings = 0;
472 }
473
474 if (file->fMap) {
475 #if KERNEL
476 if (file->fIsKmem)
477 kmem_free(kernel_map, (vm_address_t) file->fMap, file->fMapSize);
478 #else /* !KERNEL */
479 if (file->fPadEnd) {
480 vm_address_t padVM;
481 vm_size_t padSize;
482
483 padVM = round_page((vm_address_t) file->fMap + file->fMapSize);
484 padSize = (vm_size_t) ((vm_address_t) file->fPadEnd - padVM);
485 (void) vm_deallocate(mach_task_self(), padVM, padSize);
486 file->fPadEnd = 0;
487 }
488
489 (void) munmap((caddr_t) file->fMap, file->fMapSize);
490 #endif /* !KERNEL */
491 file->fMap = 0;
492 }
493 }
494
495 static void removeFile(struct fileRecord *file)
496 {
497 if (file->fClassList) {
498 DataRelease(file->fClassList);
499 file->fClassList = 0;
500 }
501
502 unmapFile(file);
503
504 free(file);
505 }
506
507 #if !KERNEL
508 static Boolean
509 mapObjectFile(struct fileRecord *file, const char *pathName)
510 {
511 Boolean result = false;
512 static unsigned char *sFileMapBaseAddr = 0;
513
514 int fd = 0;
515
516 if (!sFileMapBaseAddr) {
517 kern_return_t ret;
518 vm_address_t probeAddr;
519
520 // If we don't already have a base addr find any random chunk
521 // of 32 meg of VM and to use the 16 meg boundrary as a base.
522 ret = vm_allocate(mach_task_self(), &probeAddr,
523 32 * 1024 * 1024, VM_FLAGS_ANYWHERE);
524 return_if(KERN_SUCCESS != ret, false,
525 ("Unable to allocate base memory %s\n", mach_error_string(ret)));
526 (void) vm_deallocate(mach_task_self(), probeAddr, 32 * 1024 * 1024);
527
528 // Now round to the next 16 Meg boundrary
529 probeAddr = (probeAddr + (16 * 1024 * 1024 - 1))
530 & ~(16 * 1024 * 1024 - 1);
531 sFileMapBaseAddr = (unsigned char *) probeAddr;
532 }
533
534 fd = open(pathName, O_RDONLY, 0);
535 return_if(fd == -1, false, ("Can't open %s for reading - %s\n",
536 pathName, strerror(errno)));
537
538 do {
539 kern_return_t ret;
540 struct stat sb;
541 int retaddr = -1;
542
543 break_if(fstat(fd, &sb) == -1,
544 ("Can't stat %s - %s\n", file->fPath, strerror(errno)));
545
546 file->fMapSize = sb.st_size;
547 file->fMap = sFileMapBaseAddr;
548 ret = KERN_SUCCESS;
549 while (file->fMap < kTopAddr) {
550 vm_address_t padVM;
551 vm_address_t padVMEnd;
552 vm_size_t padSize;
553
554 padVM = round_page((vm_address_t) file->fMap + file->fMapSize);
555 retaddr = (int) mmap(file->fMap, file->fMapSize,
556 PROT_READ|PROT_WRITE,
557 MAP_FIXED|MAP_FILE|MAP_PRIVATE,
558 fd, 0);
559 if (-1 == retaddr) {
560 break_if(ENOMEM != errno,
561 ("mmap failed %d - %s\n", errno, strerror(errno)));
562
563 file->fMap = (unsigned char *) padVM;
564 continue;
565 }
566
567
568 // Round up padVM to the next page after the file and assign at
569 // least another fMapSize more room rounded up to the next page
570 // boundary.
571 padVMEnd = round_page(padVM + file->fMapSize);
572 padSize = padVMEnd - padVM;
573 ret = vm_allocate(
574 mach_task_self(), &padVM, padSize, VM_FLAGS_FIXED);
575 if (KERN_SUCCESS == ret) {
576 file->fPadEnd = (unsigned char *) padVMEnd;
577 break;
578 }
579 else {
580 munmap(file->fMap, file->fMapSize);
581 break_if(KERN_INVALID_ADDRESS != ret,
582 ("Unable to allocate pad vm for %s - %s\n",
583 pathName, mach_error_string(ret)));
584
585 file->fMap = (unsigned char *) padVMEnd;
586 continue; // try again wherever the vm system wants
587 }
588 }
589
590 if (-1 == retaddr || KERN_SUCCESS != ret)
591 break;
592
593 break_if(file->fMap >= kTopAddr,
594 ("Unable to map memory %s\n", file->fPath));
595
596 sFileMapBaseAddr = file->fPadEnd;
597 result = true;
598 } while(0);
599
600 close(fd);
601 return result;
602 }
603
604 void
605 kld_set_architecture(const NXArchInfo * arch)
606 {
607 sPreferArchInfo = arch;
608 }
609
610 // This function can only operate on 32 bit mach-o files
611 Boolean
612 kld_macho_swap(struct mach_header * mh)
613 {
614 struct segment_command * seg;
615 struct section * section;
616 CFIndex ncmds, cmd, sect;
617 enum NXByteOrder hostOrder = NXHostByteOrder();
618
619 if (MH_CIGAM != mh->magic)
620 return (false);
621
622 swap_mach_header(mh, hostOrder);
623
624 ncmds = mh->ncmds;
625 seg = (struct segment_command *)(mh + 1);
626 for (cmd = 0;
627 cmd < ncmds;
628 cmd++, seg = (struct segment_command *)(((vm_offset_t)seg) + seg->cmdsize))
629 {
630 if (OSSwapConstInt32(LC_SYMTAB) == seg->cmd) {
631 swap_symtab_command((struct symtab_command *) seg, hostOrder);
632 swap_nlist((struct nlist *) (((vm_offset_t) mh) + ((struct symtab_command *) seg)->symoff),
633 ((struct symtab_command *) seg)->nsyms, hostOrder);
634 continue;
635 }
636 if (OSSwapConstInt32(LC_SEGMENT) != seg->cmd) {
637 swap_load_command((struct load_command *) seg, hostOrder);
638 continue;
639 }
640 swap_segment_command(seg, hostOrder);
641 swap_section((struct section *) (seg + 1), seg->nsects, hostOrder);
642
643 section = (struct section *) (seg + 1);
644 for (sect = 0; sect < seg->nsects; sect++, section++) {
645 if (section->nreloc)
646 swap_relocation_info((struct relocation_info *) (((vm_offset_t) mh) + section->reloff),
647 section->nreloc, hostOrder);
648 }
649 }
650
651 return (true);
652 }
653
654 // This function can only operate on 32 bit mach-o files
655 void
656 kld_macho_unswap(struct mach_header * mh, Boolean didSwap, int symbols)
657 {
658 // symbols == 0 => everything
659 // symbols == 1 => just nlists
660 // symbols == -1 => everything but nlists
661
662 struct segment_command * seg;
663 struct section * section;
664 unsigned long cmdsize;
665 CFIndex ncmds, cmd, sect;
666 enum NXByteOrder hostOrder = (NXHostByteOrder() == NX_LittleEndian)
667 ? NX_BigEndian : NX_LittleEndian;
668 if (!didSwap)
669 return;
670
671 ncmds = mh->ncmds;
672 seg = (struct segment_command *)(mh + 1);
673 for (cmd = 0;
674 cmd < ncmds;
675 cmd++, seg = (struct segment_command *)(((vm_offset_t)seg) + cmdsize))
676 {
677 cmdsize = seg->cmdsize;
678 if (LC_SYMTAB == seg->cmd) {
679 if (symbols >= 0)
680 swap_nlist((struct nlist *) (((vm_offset_t) mh) + ((struct symtab_command *) seg)->symoff),
681 ((struct symtab_command *) seg)->nsyms, hostOrder);
682 if (symbols > 0)
683 break;
684 swap_symtab_command((struct symtab_command *) seg, hostOrder);
685 continue;
686 }
687 if (symbols > 0)
688 continue;
689 if (LC_SEGMENT != seg->cmd) {
690 swap_load_command((struct load_command *) seg, hostOrder);
691 continue;
692 }
693
694 section = (struct section *) (seg + 1);
695 for (sect = 0; sect < seg->nsects; sect++, section++) {
696 if (section->nreloc)
697 swap_relocation_info((struct relocation_info *) (((vm_offset_t) mh) + section->reloff),
698 section->nreloc, hostOrder);
699 }
700 swap_section((struct section *) (seg + 1), seg->nsects, hostOrder);
701 swap_segment_command(seg, hostOrder);
702 }
703 if (symbols <= 0)
704 swap_mach_header(mh, hostOrder);
705 }
706
707 #endif /* !KERNEL */
708
709 // Note: This functions is only called from kld_file_map()
710 // This function can only operate on 32 bit mach-o files
711 static Boolean findBestArch(struct fileRecord *file, const char *pathName)
712 {
713 unsigned long magic;
714 struct fat_header *fat;
715
716
717 file->fMachOSize = file->fMapSize;
718 file->fMachO = file->fMap;
719 magic = ((const struct mach_header *) file->fMachO)->magic;
720 fat = (struct fat_header *) file->fMachO;
721
722 // Try to figure out what type of file this is
723 return_if(file->fMapSize < sizeof(unsigned long), false,
724 ("%s isn't a valid object file - no magic\n", pathName));
725
726 #if KERNEL
727
728 // CIGAM is byte-swapped MAGIC
729 if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
730
731 load_return_t load_return;
732 struct fat_arch fatinfo;
733
734 load_return = fatfile_getarch(NULL, (vm_address_t) fat, &fatinfo);
735 return_if(load_return != LOAD_SUCCESS, false,
736 ("Extension \"%s\": has no code for this computer\n", pathName));
737
738 file->fMachO = file->fMap + fatinfo.offset;
739 file->fMachOSize = fatinfo.size;
740 magic = ((const struct mach_header *) file->fMachO)->magic;
741 }
742
743 #else /* !KERNEL */
744
745 // Do we need to in-place swap the endianness of the fat header?
746 if (magic == FAT_CIGAM) {
747 unsigned long i;
748 struct fat_arch *arch;
749
750 fat->nfat_arch = OSSwapBigToHostInt32(fat->nfat_arch);
751 return_if(file->fMapSize < sizeof(struct fat_header)
752 + fat->nfat_arch * sizeof(struct fat_arch),
753 false, ("%s is too fat\n", file->fPath));
754
755 arch = (struct fat_arch *) &fat[1];
756 for (i = 0; i < fat->nfat_arch; i++) {
757 arch[i].cputype = OSSwapBigToHostInt32(arch[i].cputype);
758 arch[i].cpusubtype = OSSwapBigToHostInt32(arch[i].cpusubtype);
759 arch[i].offset = OSSwapBigToHostInt32(arch[i].offset);
760 arch[i].size = OSSwapBigToHostInt32(arch[i].size);
761 arch[i].align = OSSwapBigToHostInt32(arch[i].align);
762 }
763
764 magic = OSSwapBigToHostInt32(fat->magic);
765 }
766
767 // Now see if we can find any valid architectures
768 if (magic == FAT_MAGIC) {
769 const NXArchInfo *myArch;
770 unsigned long fatsize;
771 struct fat_arch *arch;
772
773 fatsize = sizeof(struct fat_header)
774 + fat->nfat_arch * sizeof(struct fat_arch);
775 return_if(file->fMapSize < fatsize,
776 false, ("%s isn't a valid fat file\n", pathName));
777
778 if (sPreferArchInfo)
779 myArch = sPreferArchInfo;
780 else
781 myArch = NXGetLocalArchInfo();
782
783 arch = NXFindBestFatArch(myArch->cputype, myArch->cpusubtype,
784 (struct fat_arch *) &fat[1], fat->nfat_arch);
785 return_if(!arch,
786 false, ("%s hasn't got arch for %s\n", pathName, myArch->name));
787 return_if(arch->offset + arch->size > file->fMapSize,
788 false, ("%s's %s arch is incomplete\n", pathName, myArch->name));
789 file->fMachO = file->fMap + arch->offset;
790 file->fMachOSize = arch->size;
791 magic = ((const struct mach_header *) file->fMachO)->magic;
792 }
793
794 file->fSwapped = kld_macho_swap((struct mach_header *) file->fMachO);
795 if (file->fSwapped)
796 magic = ((const struct mach_header *) file->fMachO)->magic;
797
798 #endif /* KERNEL */
799
800 return_if(magic != MH_MAGIC,
801 false, ("%s isn't a valid mach-o\n", pathName));
802
803 return true;
804 }
805
806 // This function can only operate on segments from 32 bit mach-o files
807 static Boolean
808 parseSegments(struct fileRecord *file, struct segment_command *seg)
809 {
810 struct sectionRecord *sections;
811 int i, nsects = seg->nsects;
812 const struct segmentMap {
813 struct segment_command seg;
814 const struct section sect[1];
815 } *segMap;
816
817 if (!file->fSectData) {
818 file->fSectData = DataCreate(0);
819 if (!file->fSectData)
820 return false;
821 }
822
823 // Increase length of section DataRef and cache data pointer
824 if (!DataAddLength(file->fSectData, nsects * sizeof(struct sectionRecord)))
825 return false;
826 file->fSections = (struct sectionRecord *) DataGetPtr(file->fSectData);
827
828 // Initialise the new sections
829 sections = &file->fSections[file->fNSects];
830 file->fNSects += nsects;
831 for (i = 0, segMap = (struct segmentMap *) seg; i < nsects; i++)
832 {
833 sections[i].fSection = &segMap->sect[i];
834 file->fIsReloc |= (0 != segMap->sect[i].nreloc);
835 }
836
837 return true;
838 }
839
840 static Boolean
841 remangleExternSymbols(struct fileRecord *file, const char *pathName)
842 {
843 const struct nlist *sym;
844 int i, nsyms, len;
845 DataRef strings = NULL;
846
847 DEBUG_LOG(("Remangling %s\n", pathName));
848
849 file->fNewStringBlocks = DataCreate(0);
850 return_if(!file->fNewStringBlocks, false,
851 ("Unable to allocate new string table for %s\n", pathName));
852
853 nsyms = file->fSymtab->nsyms;
854 for (i = 0, sym = file->fSymbolBase; i < nsyms; i++, sym++) {
855 Rem3Return ret;
856 const char *symname;
857 char *newname;
858 unsigned char n_type = sym->n_type;
859
860 // Not an external symbol or it is a stab in any case don't bother
861 if ((n_type ^ N_EXT) & (N_STAB | N_EXT))
862 continue;
863
864 symname = symNameByIndex(file, i);
865
866 tryRemangleAgain:
867 if (!strings) {
868 strings = DataCreate(16 * 1024); // Arbitrary block size
869 return_if(!strings, false,
870 ("Unable to allocate new string block for %s\n", pathName));
871 }
872
873 len = DataRemaining(strings);
874 newname = DataGetEndPtr(strings);
875 ret = rem3_remangle_name(newname, &len, symname);
876 switch (ret) {
877 case kR3InternalNotRemangled:
878 errprintf("Remangler fails on %s in %s\n", symname, pathName);
879 /* No break */
880 case kR3NotRemangled:
881 break;
882
883 case kR3Remangled:
884 file->fSymbToStringTable[i] = newname;
885 file->fRemangled = file->fSymbolsDirty = true;
886 DataAddLength(strings, len + 1); // returns strlen
887 break;
888
889 case kR3BufferTooSmallRemangled:
890 return_if(!DataAppendBytes
891 (file->fNewStringBlocks, &strings, sizeof(strings)),
892 false, ("Unable to allocate string table for %s\n", pathName));
893 strings = NULL;
894 goto tryRemangleAgain;
895
896 case kR3BadArgument:
897 default:
898 return_if(true, false,
899 ("Internal error - remangle of %s\n", pathName));
900 }
901 }
902
903 if (strings) {
904 return_if(!DataAppendBytes
905 (file->fNewStringBlocks, &strings, sizeof(strings)),
906 false, ("Unable to allocate string table for %s\n", pathName));
907 }
908
909 return true;
910 }
911
912 // This function can only operate on symbol table files from 32 bit
913 // mach-o files
914 static Boolean parseSymtab(struct fileRecord *file, const char *pathName)
915 {
916 const struct nlist *sym;
917 unsigned int i, firstlocal, nsyms;
918 unsigned long strsize;
919 const char *strbase;
920 Boolean foundOSObject, found295CPP, havelocal;
921
922 // we found a link edit segment so recompute the bases
923 if (file->fLinkEditSeg) {
924 struct segment_command *link = file->fLinkEditSeg;
925
926 file->fSymbolBase = (struct nlist *)
927 (link->vmaddr + (file->fSymtab->symoff - link->fileoff));
928 file->fStringBase = (char *)
929 (link->vmaddr + (file->fSymtab->stroff - link->fileoff));
930 return_if( ( (caddr_t) file->fStringBase + file->fSymtab->strsize
931 > (caddr_t) link->vmaddr + link->vmsize ), false,
932 ("%s isn't a valid mach-o le, bad symbols\n", pathName));
933 }
934 else {
935 file->fSymbolBase = (struct nlist *)
936 (file->fMachO + file->fSymtab->symoff);
937 file->fStringBase = (char *)
938 (file->fMachO + file->fSymtab->stroff);
939 return_if( ( file->fSymtab->stroff + file->fSymtab->strsize
940 > file->fMachOSize ), false,
941 ("%s isn't a valid mach-o, bad symbols\n", pathName));
942 }
943
944 nsyms = file->fSymtab->nsyms;
945
946 // If this file the kernel and do we have an executable image
947 file->fNoKernelExecutable = (vm_page_size == file->fSymtab->symoff)
948 && (file->fSections[0].fSection->size == 0);
949
950 // Generate a table of pointers to strings indexed by the symbol number
951
952 file->fSym2Strings = DataCreate(nsyms * sizeof(const char *));
953 DataSetLength(file->fSym2Strings, nsyms * sizeof(const char *));
954 return_if(!file->fSym2Strings, false,
955 ("Unable to allocate memory - symbol string trans\n", pathName));
956 file->fSymbToStringTable = (const char **) DataGetPtr(file->fSym2Strings);
957
958 // Search for the first non-stab symbol in table
959 strsize = file->fSymtab->strsize;
960 strbase = file->fStringBase;
961 firstlocal = 0;
962 havelocal = false;
963 found295CPP = foundOSObject = false;
964 for (i = 0, sym = file->fSymbolBase; i < nsyms; i++, sym++) {
965 long strx = sym->n_un.n_strx;
966 const char *symname = strbase + strx;
967 unsigned char n_type;
968
969 return_if(((unsigned long) strx > strsize), false,
970 ("%s has an illegal string offset in symbol %d\n", pathName, i));
971 #if 0
972 // Make all syms abs
973 if (file->fIsIncrLink) {
974 if ( (sym->n_type & N_TYPE) == N_SECT) {
975 sym->n_sect = NO_SECT;
976 sym->n_type = (sym->n_type & ~N_TYPE) | N_ABS;
977 }
978 }
979 #endif
980
981 if (file->fIsIncrLink && !file->fNSects)
982 {
983 // symbol set
984 struct nlist *patchsym = (struct nlist *) sym;
985 const char * lookname;
986 const struct nlist * realsym;
987
988 if ( (patchsym->n_type & N_TYPE) == N_INDR)
989 lookname = strbase + patchsym->n_value;
990 else
991 lookname = symname;
992 realsym = findSymbolByName(sKernelFile, lookname);
993
994 patchsym->n_sect = NO_SECT;
995 if (realsym)
996 {
997 patchsym->n_type = realsym->n_type;
998 patchsym->n_desc = realsym->n_desc;
999 patchsym->n_value = realsym->n_value;
1000 if ((patchsym->n_type & N_TYPE) == N_SECT)
1001 patchsym->n_type = (patchsym->n_type & ~N_TYPE) | N_ABS;
1002 }
1003 else
1004 {
1005 errprintf("%s: Undefined in symbol set: %s\n", pathName, symname);
1006 patchsym->n_type = N_ABS;
1007 patchsym->n_desc = 0;
1008 patchsym->n_value = patchsym->n_un.n_strx;
1009 patchsym->n_un.n_strx = 0;
1010 }
1011
1012 if (!havelocal && (patchsym->n_type & N_EXT)) {
1013 firstlocal = i;
1014 havelocal = true;
1015 file->fLocalSyms = patchsym;
1016 }
1017 continue;
1018 } /* symbol set */
1019
1020 // Load up lookup symbol look table with sym names
1021 file->fSymbToStringTable[i] = symname;
1022
1023 n_type = sym->n_type & (N_TYPE | N_EXT);
1024
1025 // Find the first exported symbol
1026 if ( !firstlocal && (n_type & N_EXT) ) {
1027 firstlocal = i;
1028 havelocal = true;
1029 file->fLocalSyms = sym;
1030 }
1031
1032 // Find the a OSObject based subclass by searching for symbols
1033 // that have a suffix of '10superClassE'
1034 symname++; // Skip leading '_'
1035
1036 if (!foundOSObject
1037 && (n_type == (N_SECT | N_EXT) || n_type == (N_ABS | N_EXT))
1038 && strx) {
1039 const char *suffix, *endSym;
1040
1041 endSym = symname + strlen(symname);
1042
1043 // Find out if this symbol has the superclass suffix.
1044 if (symname[0] == kCPPSymbolPrefix[0]
1045 && symname[1] == kCPPSymbolPrefix[1]) {
1046
1047 suffix = endSym - sizeof(k31SuperClassSuffix) + 1;
1048
1049 // Check for a gcc3 OSObject subclass
1050 if (suffix > symname
1051 && !strcmp(suffix, k31SuperClassSuffix))
1052 foundOSObject = true;
1053 }
1054 else {
1055 suffix = endSym - sizeof(k29SuperClassSuffix);
1056
1057 // Check for a gcc295 OSObject subclass
1058 if (suffix > symname
1059 && ('.' == *suffix || '$' == *suffix)
1060 && !strcmp(suffix+1, k29SuperClassSuffix)) {
1061 found295CPP = foundOSObject = true;
1062 }
1063 else if (!found295CPP) {
1064 // Finally just check if we need to remangle
1065 symname++; // skip leading '__'
1066 while (*symname) {
1067 if ('_' == symname[0] && '_' == symname[1]) {
1068 found295CPP = true;
1069 break;
1070 }
1071 symname++;
1072 }
1073 }
1074 }
1075 }
1076 else if (sym->n_type == (N_EXT | N_UNDF)) {
1077 if ( !file->fNLocal) // Find the last local symbol
1078 file->fNLocal = i - firstlocal;
1079 if (!found295CPP) {
1080 symname++; // Skip possible second '_' at start.
1081 while (*symname) {
1082 if ('_' == symname[0] && '_' == symname[1]) {
1083 found295CPP = true;
1084 break;
1085 }
1086 symname++;
1087 }
1088 }
1089 }
1090 // Note symname is trashed at this point
1091 }
1092 return_if(i < nsyms, false,
1093 ("%s isn't a valid mach-o, bad symbol strings\n", pathName));
1094
1095 return_if(!file->fLocalSyms, false, ("%s has no symbols?\n", pathName));
1096
1097 // If we don't have any undefined symbols then all symbols
1098 // must be local so just compute it now if necessary.
1099 if ( !file->fNLocal )
1100 file->fNLocal = i - firstlocal;
1101
1102 file->fFoundOSObject = foundOSObject;
1103
1104 if (found295CPP && !remangleExternSymbols(file, pathName))
1105 return false;
1106
1107 return true;
1108 }
1109
1110 // @@@ gvdl: These functions need to be hashed they are
1111 // going to be way too slow for production code.
1112 static const struct nlist *
1113 findSymbolByAddress(const struct fileRecord *file, void *entry)
1114 {
1115 // not quite so dumb linear search of all symbols
1116 const struct nlist *sym;
1117 int i, nsyms;
1118
1119 // First try to find the symbol in the most likely place which is the
1120 // extern symbols
1121 sym = file->fLocalSyms;
1122 for (i = 0, nsyms = file->fNLocal; i < nsyms; i++, sym++) {
1123 if (sym->n_value == (unsigned long) entry && !(sym->n_type & N_STAB) )
1124 return sym;
1125 }
1126
1127 // Didn't find it in the external symbols so try to local symbols before
1128 // giving up.
1129 sym = file->fSymbolBase;
1130 for (i = 0, nsyms = file->fSymtab->nsyms; i < nsyms; i++, sym++) {
1131 if ( (sym->n_type & N_EXT) )
1132 return NULL;
1133 if ( sym->n_value == (unsigned long) entry && !(sym->n_type & N_STAB) )
1134 return sym;
1135 }
1136
1137 return NULL;
1138 }
1139
1140 static const struct nlist *
1141 findSymbolByAddressInAllFiles(__unused const struct fileRecord * fromFile,
1142 void *entry, const struct fileRecord **resultFile)
1143 {
1144 int i, nfiles = 0;
1145 struct fileRecord **files;
1146
1147 if (sFilesTable) {
1148
1149 // Check to see if we have already merged this file
1150 nfiles = DataGetLength(sFilesTable) / sizeof(struct fileRecord *);
1151 files = (struct fileRecord **) DataGetPtr(sFilesTable);
1152 for (i = 0; i < nfiles; i++) {
1153 if ((((vm_offset_t)entry) >= files[i]->fVMAddr)
1154 && (((vm_offset_t)entry) < files[i]->fVMEnd))
1155 {
1156 const struct nlist * result;
1157 if (resultFile)
1158 *resultFile = files[i];
1159 result = findSymbolByAddress(files[i], entry);
1160 return result;
1161 }
1162 }
1163 }
1164
1165 return NULL;
1166 }
1167
1168 struct searchContext {
1169 const char *fSymname;
1170 const struct fileRecord *fFile;
1171 };
1172
1173 static int symbolSearch(const void *vKey, const void *vSym)
1174 {
1175 const struct searchContext *key = (const struct searchContext *) vKey;
1176 const struct nlist *sym = (const struct nlist *) vSym;
1177
1178 return strcmp(key->fSymname, symbolname(key->fFile, sym));
1179 }
1180
1181 static const struct nlist *
1182 findSymbolByName(struct fileRecord *file, const char *symname)
1183 {
1184 if (file->fRemangled) {
1185 // @@@ gvdl: Performance problem
1186 // Linear search as we don't sort after remangling
1187 const struct nlist *sym;
1188 int i = file->fLocalSyms - file->fSymbolBase;
1189 int nLocal = file->fNLocal + i;
1190
1191 for (sym = file->fLocalSyms; i < nLocal; i++, sym++)
1192 if (!strcmp(symNameByIndex(file, i), symname))
1193 return sym;
1194 return NULL;
1195 }
1196 else {
1197 struct searchContext context;
1198
1199 context.fSymname = symname;
1200 context.fFile = file;
1201 return (struct nlist *)
1202 bsearch(&context,
1203 file->fLocalSyms, file->fNLocal, sizeof(struct nlist),
1204 symbolSearch);
1205 }
1206 }
1207
1208 static Boolean
1209 relocateSection(const struct fileRecord *file, struct sectionRecord *sectionRec)
1210 {
1211 const struct nlist *symbol;
1212 const struct section *section;
1213 struct relocRecord *rec;
1214 struct relocation_info *rinfo;
1215 unsigned long i;
1216 unsigned long r_address, r_symbolnum, r_length;
1217 enum reloc_type_generic r_type;
1218 UInt8 *sectionBase;
1219 void **entry;
1220
1221 sectionRec->fRelocCache = DataCreate(
1222 sectionRec->fSection->nreloc * sizeof(struct relocRecord));
1223 if (!sectionRec->fRelocCache)
1224 return false;
1225
1226 section = sectionRec->fSection;
1227 sectionBase = file->fMachO + section->offset;
1228
1229 rec = (struct relocRecord *) DataGetPtr(sectionRec->fRelocCache);
1230 rinfo = (struct relocation_info *) (file->fMachO + section->reloff);
1231 for (i = 0; i < section->nreloc; i++, rec++, rinfo++) {
1232
1233 // Totally uninterested in scattered relocation entries
1234 if ( (rinfo->r_address & R_SCATTERED) )
1235 continue;
1236
1237 r_address = rinfo->r_address;
1238 entry = (void **) (sectionBase + r_address);
1239
1240 /*
1241 * The r_address field is really an offset into the contents of the
1242 * section and must reference something inside the section (Note
1243 * that this is not the case for PPC_RELOC_PAIR entries but this
1244 * can't be one with the above checks).
1245 */
1246 return_if(r_address >= section->size, false,
1247 ("Invalid relocation entry in %s - not in section\n", file->fPath));
1248
1249 // If we don't have a VANILLA entry or the Vanilla entry isn't
1250 // a 'long' then ignore the entry and try the next.
1251 r_type = (enum reloc_type_generic) rinfo->r_type;
1252 r_length = rinfo->r_length;
1253 if (r_type != GENERIC_RELOC_VANILLA || r_length != 2)
1254 continue;
1255
1256 r_symbolnum = rinfo->r_symbolnum;
1257
1258 /*
1259 * If rinfo->r_extern is set this relocation entry is an external entry
1260 * else it is a local entry.
1261 */
1262 if (rinfo->r_extern) {
1263 /*
1264 * This is an external relocation entry.
1265 * r_symbolnum is an index into the input file's symbol table
1266 * of the symbol being refered to. The symbol must be
1267 * undefined to be used in an external relocation entry.
1268 */
1269 return_if(r_symbolnum >= file->fSymtab->nsyms, false,
1270 ("Invalid relocation entry in %s - no symbol\n", file->fPath));
1271
1272 /*
1273 * If this is an indirect symbol resolve indirection (all chains
1274 * of indirect symbols have been resolved so that they point at
1275 * a symbol that is not an indirect symbol).
1276 */
1277 symbol = file->fSymbolBase;
1278 if ((symbol[r_symbolnum].n_type & N_TYPE) == N_INDR)
1279 r_symbolnum = symbol[r_symbolnum].n_value;
1280 symbol = &symbol[r_symbolnum];
1281
1282 return_if(symbol->n_type != (N_EXT | N_UNDF), false,
1283 ("Invalid relocation entry in %s - extern\n", file->fPath));
1284 }
1285 else {
1286 /*
1287 * If the symbol is not in any section then it can't be a
1288 * pointer to a local segment and I don't care about it.
1289 */
1290 if (r_symbolnum == R_ABS)
1291 continue;
1292
1293 // Note segment references are offset by 1 from 0.
1294 return_if(r_symbolnum > file->fNSects, false,
1295 ("Invalid relocation entry in %s - local\n", file->fPath));
1296
1297 // Find the symbol, if any, that backs this entry
1298 void * addr = *entry;
1299 #if !KERNEL
1300 if (file->fSwapped)
1301 addr = (void *) OSSwapInt32((uint32_t) addr);
1302 #endif
1303 symbol = findSymbolByAddress(file, addr);
1304 }
1305
1306 rec->fValue = *entry; // Save the previous value
1307 rec->fRInfo = rinfo; // Save a pointer to the reloc
1308 rec->fSymbol = symbol; // Record the current symbol
1309
1310 *entry = (void *) rec; // Save pointer to record in object image
1311 }
1312
1313 DataSetLength(sectionRec->fRelocCache, i * sizeof(struct relocRecord));
1314 ((struct fileRecord *) file)->fImageDirty = true;
1315
1316 return true;
1317 }
1318
1319 static const struct nlist *
1320 findSymbolRefAtLocation(const struct fileRecord *file,
1321 struct sectionRecord *sctn, void **loc, const struct fileRecord **foundInFile)
1322 {
1323 const struct nlist * result;
1324
1325 *foundInFile = file;
1326
1327 if (!file->fIsReloc) {
1328 if (*loc) {
1329 void * addr = *loc;
1330 #if !KERNEL
1331 if (file->fSwapped)
1332 addr = (void *) OSSwapInt32((uint32_t) addr);
1333 #endif
1334 result = findSymbolByAddress(file, addr);
1335 if (!result)
1336 result = findSymbolByAddressInAllFiles(file, addr, foundInFile);
1337 return result;
1338 }
1339 }
1340 else if (sctn->fRelocCache || relocateSection(file, sctn)) {
1341 struct relocRecord *reloc = (struct relocRecord *) *loc;
1342
1343 if (DataContainsAddr(sctn->fRelocCache, reloc))
1344 return reloc->fSymbol;
1345 }
1346
1347 return NULL;
1348 }
1349
1350 static Boolean
1351 addClass(struct fileRecord *file,
1352 struct metaClassRecord *inClass,
1353 const char *cname)
1354 {
1355 Boolean result = false;
1356 struct metaClassRecord *newClass = NULL;
1357 struct metaClassRecord **fileClasses = NULL;
1358 int len;
1359
1360 if (!file->fClassList) {
1361 file->fClassList = DataCreate(0);
1362 if (!file->fClassList)
1363 return false;
1364 }
1365
1366 do {
1367 // Attempt to allocate all necessary resource first
1368 len = strlen(cname) + 1
1369 + (int) (&((struct metaClassRecord *) 0)->fClassName);
1370 newClass = (struct metaClassRecord *) malloc(len);
1371 if (!newClass)
1372 break;
1373
1374 if (!DataAddLength(file->fClassList, sizeof(struct metaClassRecord *)))
1375 break;
1376 fileClasses = (struct metaClassRecord **)
1377 (DataGetPtr(file->fClassList) + DataGetLength(file->fClassList));
1378
1379 // Copy the meta Class structure and string name into newClass and
1380 // insert object at end of the file->fClassList and sMergeMetaClasses
1381 *newClass = *inClass;
1382 strcpy(newClass->fClassName, cname);
1383 fileClasses[-1] = newClass;
1384
1385 return true;
1386 } while (0);
1387
1388 if (fileClasses)
1389 DataAddLength(file->fClassList, -sizeof(struct metaClassRecord *));
1390
1391 if (newClass)
1392 free(newClass);
1393
1394 return result;
1395 }
1396
1397 static struct metaClassRecord *getClass(DataRef classList, const char *cname)
1398 {
1399 if (classList) {
1400 int i, nclass;
1401 struct metaClassRecord **classes, *thisClass;
1402
1403 nclass = DataGetLength(classList) / sizeof(struct metaClassRecord *);
1404 classes = (struct metaClassRecord **) DataGetPtr(classList);
1405 for (i = 0; i < nclass; i++) {
1406 thisClass = classes[i];
1407 if (!strcmp(thisClass->fClassName, cname))
1408 return thisClass;
1409 }
1410 }
1411
1412 return NULL;
1413 }
1414
1415 // Add the class 'cname' to the list of known OSObject based classes
1416 // Note 'sym' is the <cname>10superClassE symbol.
1417 static Boolean
1418 recordClass(struct fileRecord *file, const char *cname, const struct nlist *sym)
1419 {
1420 Boolean result = false;
1421 char *supername = NULL;
1422 const char *classname = NULL;
1423 struct metaClassRecord newClass;
1424 char strbuffer[1024];
1425
1426 // Only do the work to find the super class if we are
1427 // not currently working on the kernel. The kernel is the end
1428 // of all superclass chains by definition as the kernel must be binary
1429 // compatible with itself.
1430 if (file->fIsReloc) {
1431 const char *suffix;
1432 const struct fileRecord *superfile;
1433 const struct nlist *supersym;
1434 const struct section *section;
1435 struct sectionRecord *sectionRec;
1436 unsigned char sectind = sym->n_sect;
1437 const char *superstr;
1438 void **location;
1439 int snamelen;
1440
1441 // We can't resolve anything that isn't in a real section
1442 // Note that the sectind is starts at one to make room for the
1443 // NO_SECT flag but the fNSects field isn't offset so we have a
1444 // '>' test. Which means this isn't an OSObject based class
1445 if (sectind == NO_SECT || sectind > file->fNSects) {
1446 result = true;
1447 goto finish;
1448 }
1449 sectionRec = file->fSections + sectind - 1;
1450 section = sectionRec->fSection;
1451 location = (void **) ( file->fMachO + section->offset
1452 + sym->n_value - section->addr );
1453
1454 supersym = findSymbolRefAtLocation(file, sectionRec, location, &superfile);
1455 if (!supersym) {
1456 result = true; // No superclass symbol then it isn't an OSObject.
1457 goto finish;
1458 }
1459
1460 // Find string in file and skip leading '_' and then find the suffix
1461 superstr = symbolname(superfile, supersym) + 1;
1462 suffix = superstr + strlen(superstr) - sizeof(kGMetaSuffix) + 1;
1463 if (suffix <= superstr || strcmp(suffix, kGMetaSuffix)) {
1464 result = true; // Not an OSObject superclass so ignore it..
1465 goto finish;
1466 }
1467
1468 // Got a candidate so hand it over for class processing.
1469 snamelen = suffix - superstr - sizeof(kOSObjPrefix) + 2;
1470 supername = (char *) malloc(snamelen + 1);
1471 bcopy(superstr + sizeof(kOSObjPrefix) - 2, supername, snamelen);
1472 supername[snamelen] = '\0';
1473 }
1474
1475 do {
1476 break_if(getClass(file->fClassList, cname),
1477 ("Duplicate class %s in %s\n", cname, file->fPath));
1478
1479 snprintf(strbuffer, sizeof(strbuffer), "%s%s", kVTablePrefix, cname);
1480 newClass.fVTableSym = findSymbolByName(file, strbuffer);
1481 break_if(!newClass.fVTableSym,
1482 ("Can't find vtable %s in %s\n", cname, file->fPath));
1483
1484 newClass.fFile = file;
1485 newClass.fSuperName = supername;
1486 newClass.fPatchedVTable = NULL;
1487
1488 // Can't use cname as it may be a stack variable
1489 // However the vtable's string has the class name as a suffix
1490 // so why don't we use that rather than mallocing a string.
1491 classname = symbolname(file, newClass.fVTableSym)
1492 + sizeof(kVTablePrefix) - 1;
1493 break_if(!addClass(file, &newClass, classname),
1494 ("recordClass - no memory?\n"));
1495
1496 supername = NULL;
1497 result = true;
1498 } while (0);
1499
1500 finish:
1501 if (supername)
1502 free(supername);
1503
1504 return result;
1505 }
1506
1507
1508 static Boolean getMetaClassGraph(struct fileRecord *file)
1509 {
1510 const struct nlist *sym;
1511 int i, nsyms;
1512
1513 // Search the symbol table for the local symbols that are generated
1514 // by the metaclass system. There are three metaclass variables
1515 // that are relevant.
1516 //
1517 // <ClassName>.metaClass A pointer to the meta class structure.
1518 // <ClassName>.superClass A pointer to the super class's meta class.
1519 // <ClassName>.gMetaClass The meta class structure itself.
1520 // ___vt<ClassName> The VTable for the class <ClassName>.
1521 //
1522 // In this code I'm going to search for any symbols that
1523 // ends in k31SuperClassSuffix as this indicates this class is a conforming
1524 // OSObject subclass and will need to be patched, and it also
1525 // contains a pointer to the super class's meta class structure.
1526 sym = file->fLocalSyms;
1527 for (i = 0, nsyms = file->fNLocal; i < nsyms; i++, sym++) {
1528 const char *symname;
1529 const char *suffix;
1530 char classname[1024];
1531 unsigned char n_type = sym->n_type & (N_TYPE | N_EXT);
1532 int cnamelen;
1533
1534 // Check that the symbols is a global and that it has a name.
1535 if (((N_SECT | N_EXT) != n_type && (N_ABS | N_EXT) != n_type)
1536 || !sym->n_un.n_strx)
1537 continue;
1538
1539 // Only search from the last *sep* in the symbol.
1540 // but skip the leading '_' in all symbols first.
1541 symname = symbolname(file, sym) + 1;
1542 if (symname[0] != kCPPSymbolPrefix[0]
1543 || symname[1] != kCPPSymbolPrefix[1])
1544 continue;
1545
1546 suffix = symname + strlen(symname) - sizeof(k31SuperClassSuffix) + 1;
1547 if (suffix <= symname || strcmp(suffix, k31SuperClassSuffix))
1548 continue;
1549
1550 // Got a candidate so hand it over for class processing.
1551 cnamelen = suffix - symname - sizeof(kOSObjPrefix) + 2;
1552 return_if(cnamelen + 1 >= (int) sizeof(classname),
1553 false, ("Symbol %s is too long", symname));
1554
1555 bcopy(symname + sizeof(kOSObjPrefix) - 2, classname, cnamelen);
1556 classname[cnamelen] = '\0';
1557 if (!recordClass(file, classname, sym))
1558 return false;
1559 }
1560
1561 return_if(!file->fClassList, false, ("Internal error, "
1562 "getMetaClassGraph(%s) found no classes", file->fPath));
1563
1564 DEBUG_LOG(("Found %ld classes in %p for %s\n",
1565 DataGetLength(file->fClassList)/sizeof(void*),
1566 file->fClassList, file->fPath));
1567
1568 return true;
1569 }
1570
1571 static Boolean mergeOSObjectsForFile(const struct fileRecord *file)
1572 {
1573 int i, nmerged;
1574 Boolean foundDuplicates = false;
1575
1576 DEBUG_LOG(("Merging file %s\n", file->fPath)); // @@@ gvdl:
1577
1578 if (!file->fClassList)
1579 return true;
1580
1581 if (!sMergedFiles) {
1582 sMergedFiles = DataCreate(0);
1583 return_if(!sMergedFiles, false,
1584 ("Unable to allocate memory metaclass list\n", file->fPath));
1585 }
1586
1587 // Check to see if we have already merged this file
1588 nmerged = DataGetLength(sMergedFiles) / sizeof(struct fileRecord *);
1589 for (i = 0; i < nmerged; i++) {
1590 if (file == ((void **) DataGetPtr(sMergedFiles))[i])
1591 return true;
1592 }
1593
1594 if (!sMergeMetaClasses) {
1595 sMergeMetaClasses = DataCreate(0);
1596 return_if(!sMergeMetaClasses, false,
1597 ("Unable to allocate memory metaclass list\n", file->fPath));
1598 }
1599 else { /* perform a duplicate check */
1600 int k, j, cnt1, cnt2;
1601 struct metaClassRecord **list1, **list2;
1602
1603 list1 = (struct metaClassRecord **) DataGetPtr(file->fClassList);
1604 cnt1 = DataGetLength(file->fClassList) / sizeof(*list1);
1605 list2 = (struct metaClassRecord **) DataGetPtr(sMergeMetaClasses);
1606 cnt2 = DataGetLength(sMergeMetaClasses) / sizeof(*list2);
1607
1608 for (k = 0; k < cnt1; k++) {
1609 for (j = 0; j < cnt2; j++) {
1610 if (!strcmp(list1[k]->fClassName, list2[j]->fClassName)) {
1611 errprintf("duplicate class %s in %s & %s\n",
1612 list1[k]->fClassName,
1613 file->fPath, list2[j]->fFile->fPath);
1614 }
1615 }
1616 }
1617 }
1618 if (foundDuplicates)
1619 return false;
1620
1621 return_if(!DataAppendBytes(sMergedFiles, &file, sizeof(file)), false,
1622 ("Unable to allocate memory to merge %s\n", file->fPath));
1623
1624 return_if(!DataAppendData(sMergeMetaClasses, file->fClassList), false,
1625 ("Unable to allocate memory to merge %s\n", file->fPath));
1626
1627 if (file == sKernelFile)
1628 sMergedKernel = true;
1629
1630 return true;
1631 }
1632
1633 // Returns a pointer to the base of the section offset by the sections
1634 // base address. The offset is so that we can add nlist::n_values directly
1635 // to this address and get a valid pointer in our memory.
1636 static unsigned char *
1637 getSectionForSymbol(const struct fileRecord *file, const struct nlist *symb,
1638 void ***endP)
1639 {
1640 const struct section *section;
1641 unsigned char sectind;
1642 unsigned char *base;
1643
1644 sectind = symb->n_sect; // Default to symbols section
1645 if ((symb->n_type & N_TYPE) == N_ABS && !file->fIsReloc) {
1646 // Absolute symbol so we have to iterate over our sections
1647 for (sectind = 1; sectind <= file->fNSects; sectind++) {
1648 unsigned long start, end;
1649
1650 section = file->fSections[sectind - 1].fSection;
1651 start = section->addr;
1652 end = start + section->size;
1653 if (start <= symb->n_value && symb->n_value < end) {
1654 // Found the relevant section
1655 break;
1656 }
1657 }
1658 }
1659
1660 // Is the vtable in a valid section?
1661 return_if(sectind == NO_SECT || sectind > file->fNSects,
1662 (unsigned char *) -1,
1663 ("%s isn't a valid kext, bad section reference\n", file->fPath));
1664
1665 section = file->fSections[sectind - 1].fSection;
1666
1667 // for when we start walking the vtable so compute offset's now.
1668 base = file->fMachO + section->offset;
1669 *endP = (void **) (base + section->size);
1670
1671 return base - section->addr; // return with addr offset
1672 }
1673
1674 static Boolean resolveKernelVTable(struct metaClassRecord *metaClass)
1675 {
1676 const struct fileRecord *file;
1677 struct patchRecord *patchedVTable;
1678 void **curEntry, **vtableEntries, **endSection;
1679 unsigned char *sectionBase;
1680 struct patchRecord *curPatch;
1681 int classSize;
1682
1683 // Should never occur but it doesn't cost us anything to check.
1684 if (metaClass->fPatchedVTable)
1685 return true;
1686
1687 DEBUG_LOG(("Kernel vtable %s\n", metaClass->fClassName)); // @@@ gvdl:
1688
1689 // Do we have a valid vtable to patch?
1690 return_if(!metaClass->fVTableSym,
1691 false, ("Internal error - no class vtable symbol?\n"));
1692
1693 file = metaClass->fFile;
1694
1695 // If the metaClass we are being to ask is in the kernel then we
1696 // need to do a quick scan to grab the fPatchList in a reliable format
1697 // however we don't need to check the superclass in the kernel
1698 // as the kernel vtables are always correct wrt themselves.
1699 // Note this ends the superclass chain recursion.
1700 return_if(file->fIsReloc,
1701 false, ("Internal error - resolveKernelVTable is relocateable\n"));
1702
1703 if (file->fNoKernelExecutable) {
1704 // Oh dear attempt to map the kernel's VM into my memory space
1705 return_if(file->fNoKernelExecutable, false,
1706 ("Internal error - fNoKernelExecutable not implemented yet\n"));
1707 }
1708
1709 // We are going to need the base and the end
1710 sectionBase = getSectionForSymbol(file, metaClass->fVTableSym, &endSection);
1711 if (-1 == (long) sectionBase)
1712 return false;
1713
1714 vtableEntries = (void **) (sectionBase + metaClass->fVTableSym->n_value);
1715 curEntry = vtableEntries + kVTablePreambleLen;
1716 for (classSize = 0; curEntry < endSection && *curEntry; classSize++)
1717 curEntry++;
1718
1719 return_if(*curEntry, false, ("Bad kernel image, short section\n"));
1720
1721 patchedVTable = (struct patchRecord *)
1722 malloc((classSize + 1) * sizeof(struct patchRecord));
1723 return_if(!patchedVTable, false, ("resolveKernelVTable - no memory\n"));
1724
1725 // Copy the vtable of this class into the patch table
1726 curPatch = patchedVTable;
1727 curEntry = vtableEntries + kVTablePreambleLen;
1728 for (; *curEntry; curEntry++, curPatch++) {
1729 void * addr = *curEntry;
1730 #if !KERNEL
1731 if (file->fSwapped)
1732 addr = (void *) OSSwapInt32((uint32_t) addr);
1733 #endif
1734 curPatch->fSymbol = (struct nlist *)
1735 findSymbolByAddress(file, addr);
1736 if (curPatch->fSymbol)
1737 {
1738 curPatch->fType = kSymbolLocal;
1739 curPatch->fFile = file;
1740 }
1741 else
1742 {
1743 curPatch->fSymbol = (struct nlist *)
1744 findSymbolByAddressInAllFiles(file, addr, &curPatch->fFile);
1745 if (!curPatch->fSymbol) {
1746 errprintf("%s: !findSymbolByAddressInAllFiles(%p)\n",
1747 file->fPath, addr);
1748 return false;
1749 }
1750 curPatch->fType = kSymbolLocal;
1751 }
1752 }
1753
1754 // Tag the end of the patch vtable
1755 curPatch->fSymbol = NULL;
1756 metaClass->fPatchedVTable = patchedVTable;
1757
1758 return true;
1759 }
1760
1761 static const char *addNewString(struct fileRecord *file,
1762 const char *strname, int namelen)
1763 {
1764 DataRef strings = 0;
1765 const char *newStr;
1766
1767 namelen++; // Include terminating '\0';
1768
1769 // Make sure we have a string table as well for this symbol
1770 if (file->fNewStringBlocks) {
1771 DataRef *blockTable = (DataRef *) DataGetPtr(file->fNewStringBlocks);
1772 int index = DataGetLength(file->fNewStringBlocks) / sizeof(DataRef*);
1773 strings = blockTable[index - 1];
1774 if (DataRemaining(strings) < namelen)
1775 strings = 0;
1776 }
1777 else
1778 {
1779 file->fNewStringBlocks = DataCreate(0);
1780 return_if(!file->fNewStringBlocks, NULL,
1781 ("Unable to allocate new string table %s\n", file->fPath));
1782 }
1783
1784 if (!strings) {
1785 int size = (namelen + 1023) & ~1023;
1786 if (size < 16 * 1024)
1787 size = 16 * 1024;
1788 strings = DataCreate(size);
1789 return_if(!strings, NULL,
1790 ("Unable to allocate new string block %s\n", file->fPath));
1791 return_if(
1792 !DataAppendBytes(file->fNewStringBlocks, &strings, sizeof(strings)),
1793 false, ("Unable to allocate string table for %s\n", file->fPath));
1794 }
1795
1796 newStr = DataGetEndPtr(strings);
1797 DataAppendBytes(strings, strname, namelen);
1798 return newStr;
1799 }
1800
1801 // reloc->fPatch must contain a valid pointer
1802 static struct nlist *
1803 getNewSymbol(struct fileRecord *file,
1804 const struct relocRecord *reloc, const char *supername)
1805 {
1806 unsigned int size, i;
1807 struct nlist **sym;
1808 struct nlist *msym;
1809 struct relocation_info *rinfo;
1810 const char *newStr;
1811
1812 if (!file->fNewSymbols) {
1813 file->fNewSymbols = DataCreate(0);
1814 return_if(!file->fNewSymbols, NULL,
1815 ("Unable to allocate new symbol table for %s\n", file->fPath));
1816 }
1817
1818 rinfo = (struct relocation_info *) reloc->fRInfo;
1819 size = DataGetLength(file->fNewSymbols) / sizeof(struct nlist *);
1820 sym = (struct nlist **) DataGetPtr(file->fNewSymbols);
1821 for (i = 0; i < size; i++, sym++) {
1822 int symnum = i + file->fSymtab->nsyms;
1823 newStr = symNameByIndex(file, symnum);
1824 if (!strcmp(newStr, supername)) {
1825 rinfo->r_symbolnum = symnum;
1826 file->fSymbolsDirty = true;
1827 return *sym;
1828 }
1829 }
1830
1831 if (reloc->fSymbol->n_un.n_strx >= 0) {
1832 // This symbol has not been previously processed, so assert that it
1833 // is a valid non-local symbol. I need this condition to be true for
1834 // the later code to set to -1. Now, being the first time through,
1835 // I'd better make sure that n_sect is NO_SECT.
1836
1837 return_if(reloc->fSymbol->n_sect != NO_SECT, NULL,
1838 ("Undefined symbol entry with non-zero section %s:%s\n",
1839 file->fPath, symbolname(file, reloc->fSymbol)));
1840
1841 // Mark the original symbol entry as having been processed.
1842 // This means that we wont attempt to create the symbol again
1843 // in the future if we come through a different path.
1844 ((struct nlist *) reloc->fSymbol)->n_un.n_strx =
1845 -reloc->fSymbol->n_un.n_strx;
1846
1847 // Mark the old symbol as being potentially deletable I can use the
1848 // n_sect field as the input symbol must be of type N_UNDF which means
1849 // that the n_sect field must be set to NO_SECT otherwise it is an
1850 // invalid input file.
1851 ((struct nlist *) reloc->fSymbol)->n_sect = (unsigned char) -1;
1852 }
1853
1854 // If we are here we didn't find the symbol so create a new one now
1855 msym = (struct nlist *) malloc(sizeof(struct nlist));
1856 return_if(!msym,
1857 NULL, ("Unable to create symbol table entry for %s", file->fPath));
1858 return_if(!DataAppendBytes(file->fNewSymbols, &msym, sizeof(msym)),
1859 NULL, ("Unable to grow symbol table for %s\n", file->fPath));
1860
1861 newStr = addNewString(file, supername, strlen(supername));
1862 if (!newStr)
1863 return NULL;
1864
1865 // If we are here we didn't find the symbol so create a new one now
1866 return_if(!DataAppendBytes(file->fSym2Strings, &newStr, sizeof(newStr)),
1867 NULL, ("Unable to grow symbol table for %s\n", file->fPath));
1868 file->fSymbToStringTable = (const char **) DataGetPtr(file->fSym2Strings);
1869
1870 // Offset the string index by the original string table size
1871 // and negate the address to indicate that this is a 'new' symbol
1872 msym->n_un.n_strx = -1;
1873 msym->n_type = (N_EXT | N_UNDF);
1874 msym->n_sect = NO_SECT;
1875 msym->n_desc = 0;
1876 msym->n_value = (unsigned long) newStr;
1877
1878 rinfo->r_symbolnum = i + file->fSymtab->nsyms;
1879 file->fSymbolsDirty = true;
1880 return msym;
1881 }
1882
1883 static struct nlist *
1884 fixOldSymbol(struct fileRecord *file,
1885 const struct relocRecord *reloc, const char *supername)
1886 {
1887 unsigned int namelen;
1888 struct nlist *sym = (struct nlist *) reloc->fSymbol;
1889 const char *oldname = symbolname(file, sym);
1890
1891 // assert(sym->n_un.n_strx >= 0);
1892
1893 namelen = strlen(supername);
1894
1895 sym->n_un.n_strx = -sym->n_un.n_strx;
1896 if (oldname && namelen < strlen(oldname))
1897 {
1898 // Overwrite old string in string table
1899 strcpy((char *) oldname, supername);
1900 file->fSymbolsDirty = true;
1901 return sym;
1902 }
1903
1904 oldname = addNewString(file, supername, namelen);
1905 if (!oldname)
1906 return NULL;
1907
1908 file->fSymbToStringTable[sym - file->fSymbolBase] = oldname;
1909 file->fSymbolsDirty = true;
1910 return sym;
1911 }
1912
1913 static enum patchState
1914 symbolCompare(const struct fileRecord *file,
1915 const struct nlist *classsym,
1916 const char *supername)
1917 {
1918 const char *classname;
1919
1920
1921 // Check to see if the target function is locally defined
1922 // if it is then we can assume this is a local vtable override
1923 if ((classsym->n_type & N_TYPE) != N_UNDF)
1924 return kSymbolLocal;
1925
1926 // Check to see if both symbols point to the same symbol name
1927 // if so then we are still identical.
1928 classname = symbolname(file, classsym);
1929 if (!strcmp(classname, supername))
1930 return kSymbolIdentical;
1931
1932 // We know that the target's vtable entry is different from the
1933 // superclass' vtable entry. This means that we will have to apply a
1934 // patch to the current entry, however before returning lets check to
1935 // see if we have a _RESERVEDnnn field 'cause we can use this as a
1936 // registration point that must align between vtables.
1937 if (strstr(supername, kReservedNamePrefix))
1938 return kSymbolMismatch;
1939
1940 // OK, we have a superclass difference where the superclass doesn't
1941 // reference a pad function so assume that the superclass is correct.
1942 if (strstr(classname, kReservedNamePrefix))
1943 return kSymbolPadUpdate;
1944 else
1945 return kSymbolSuperUpdate;
1946 }
1947
1948 static Boolean patchVTable(struct metaClassRecord *metaClass)
1949 {
1950 struct metaClassRecord *super = NULL;
1951 struct fileRecord *file;
1952 struct patchRecord *patchedVTable;
1953 struct relocRecord **curReloc, **vtableRelocs, **endSection;
1954 unsigned char *sectionBase;
1955 int classSize;
1956
1957 // Should never occur but it doesn't cost us anything to check.
1958 if (metaClass->fPatchedVTable)
1959 return true;
1960
1961 // Do we have a valid vtable to patch?
1962 return_if(!metaClass->fVTableSym,
1963 false, ("Internal error - no class vtable symbol?\n"));
1964
1965 file = metaClass->fFile;
1966
1967 if (!file->fIsReloc)
1968 {
1969 // If the metaClass we are being to ask is already relocated then we
1970 // need to do a quick scan to grab the fPatchList in a reliable format
1971 // however we don't need to check the superclass in the already linked
1972 // modules as the vtables are always correct wrt themselves.
1973 // Note this ends the superclass chain recursion.
1974 Boolean res;
1975 res = resolveKernelVTable(metaClass);
1976 return res;
1977 }
1978
1979 if (!metaClass->fSuperName)
1980 return false;
1981
1982 // The class isn't in the kernel so make sure that the super class
1983 // is patched before patching ouselves.
1984 super = getClass(sMergeMetaClasses, metaClass->fSuperName);
1985 return_if(!super, false, ("Can't find superclass for %s : %s\n",
1986 metaClass->fClassName, metaClass->fSuperName));
1987
1988 // Superclass recursion if necessary
1989 if (!super->fPatchedVTable) {
1990 Boolean res;
1991 res = patchVTable(super);
1992 if (!res)
1993 return false;
1994 }
1995
1996 DEBUG_LOG(("Patching %s\n", metaClass->fClassName)); // @@@ gvdl:
1997
1998 // We are going to need the base and the end
1999
2000 sectionBase = getSectionForSymbol(file,
2001 metaClass->fVTableSym, (void ***) &endSection);
2002 if (-1 == (long) sectionBase)
2003 return false;
2004
2005 vtableRelocs = (struct relocRecord **)
2006 (sectionBase + metaClass->fVTableSym->n_value);
2007 curReloc = vtableRelocs + kVTablePreambleLen;
2008 for (classSize = 0; curReloc < endSection && *curReloc; classSize++)
2009 curReloc++;
2010
2011 return_if(*curReloc, false,
2012 ("%s isn't a valid kext, short section\n", file->fPath));
2013
2014 patchedVTable = (struct patchRecord *)
2015 malloc((classSize + 1) * sizeof(struct patchRecord));
2016 return_if(!patchedVTable, false, ("patchedVTable - no memory\n"));
2017
2018 do {
2019 struct patchRecord *curPatch;
2020 struct nlist *symbol;
2021
2022 curPatch = patchedVTable;
2023 curReloc = vtableRelocs + kVTablePreambleLen;
2024
2025 // Grab the super table patches if necessary
2026 // Can't be patching a kernel table as we don't walk super
2027 // class chains in the kernel symbol space.
2028 if (super && super->fPatchedVTable) {
2029 const struct patchRecord *spp;
2030
2031 spp = super->fPatchedVTable;
2032
2033 for ( ; spp->fSymbol; curReloc++, spp++, curPatch++) {
2034 const char *supername =
2035 symbolname(spp->fFile, spp->fSymbol);
2036
2037 symbol = (struct nlist *) (*curReloc)->fSymbol;
2038
2039 curPatch->fType = symbolCompare(file, symbol, supername);
2040 switch (curPatch->fType) {
2041 case kSymbolIdentical:
2042 case kSymbolLocal:
2043 break;
2044
2045 case kSymbolSuperUpdate:
2046 symbol = getNewSymbol(file, (*curReloc), supername);
2047 break;
2048
2049 case kSymbolPadUpdate:
2050 symbol = fixOldSymbol(file, (*curReloc), supername);
2051 break;
2052
2053 case kSymbolMismatch:
2054 errprintf("%s is not compatible with its superclass, "
2055 "%s superclass changed?\n",
2056 metaClass->fClassName, super->fClassName);
2057 goto abortPatch;
2058
2059 default:
2060 errprintf("Internal error - unknown patch type\n");
2061 goto abortPatch;
2062 }
2063 if (symbol) {
2064 curPatch->fSymbol = symbol;
2065 (*curReloc)->fSymbol = symbol;
2066 curPatch->fFile = file;
2067 }
2068 else
2069 goto abortPatch;
2070 }
2071 }
2072
2073 // Copy the remainder of this class' vtable into the patch table
2074 for (; *curReloc; curReloc++, curPatch++) {
2075 // Local reloc symbols
2076 curPatch->fType = kSymbolLocal;
2077 curPatch->fSymbol = (struct nlist *) (*curReloc)->fSymbol;
2078 curPatch->fFile = file;
2079 }
2080
2081 // Tag the end of the patch vtable
2082 curPatch->fSymbol = NULL;
2083
2084 metaClass->fPatchedVTable = patchedVTable;
2085 return true;
2086 } while(0);
2087
2088 abortPatch:
2089 if (patchedVTable)
2090 free(patchedVTable);
2091
2092 return false;
2093 }
2094
2095 static Boolean growImage(struct fileRecord *file, vm_size_t delta)
2096 {
2097 #if !KERNEL
2098 file->fMachOSize += delta;
2099 return (file->fMachO + file->fMachOSize <= file->fPadEnd);
2100 #else /* KERNEL */
2101 vm_address_t startMachO, endMachO, endMap;
2102 vm_offset_t newMachO;
2103 vm_size_t newsize;
2104 unsigned long i, last = 0;
2105 struct metaClassRecord **classes = NULL;
2106 struct sectionRecord *section;
2107 kern_return_t ret;
2108
2109 startMachO = (vm_address_t) file->fMachO;
2110 endMachO = startMachO + file->fMachOSize + delta;
2111 endMap = (vm_address_t) file->fMap + file->fMapSize;
2112
2113 // Do we have room in the current mapped image
2114 if (endMachO < round_page_32(endMap)) {
2115 file->fMachOSize += delta;
2116 return true;
2117 }
2118
2119 newsize = endMachO - startMachO;
2120 if (newsize < round_page_32(file->fMapSize)) {
2121 DEBUG_LOG(("Growing image %s by moving\n", file->fPath));
2122
2123 // We have room in the map if we shift the macho image within the
2124 // current map. We will have to patch up pointers into the object.
2125 newMachO = (vm_offset_t) file->fMap;
2126 bcopy((char *) startMachO, (char *) newMachO, file->fMachOSize);
2127 }
2128 else if (file->fIsKmem) {
2129 // kmem_alloced mapping so we can try a kmem_realloc
2130 ret = kmem_realloc(kernel_map,
2131 (vm_address_t) file->fMap,
2132 (vm_size_t) file->fMapSize,
2133 &newMachO,
2134 newsize);
2135 if (KERN_SUCCESS != ret)
2136 return false;
2137
2138 // If the mapping didn't move then just return
2139 if ((vm_address_t) file->fMap == newMachO) {
2140 file->fMachOSize = file->fMapSize = newsize;
2141 return true;
2142 }
2143
2144 DEBUG_LOG(("Growing image %s by reallocing\n", file->fPath));
2145 // We have relocated the kmem image so we are going to have to
2146 // move all of the pointers into the image around.
2147 }
2148 else {
2149 DEBUG_LOG(("Growing image %s by allocating\n", file->fPath));
2150 // The image doesn't have room for us and I can't kmem_realloc
2151 // then I just have to bite the bullet and copy the object code
2152 // into a bigger memory segment
2153 ret = kmem_alloc(kernel_map, &newMachO, newsize);
2154
2155 if (KERN_SUCCESS != ret)
2156 return false;
2157 bcopy((char *) startMachO, (void *) newMachO, file->fMachOSize);
2158 file->fIsKmem = true;
2159 }
2160
2161
2162 file->fMap = file->fMachO = (unsigned char *) newMachO;
2163 file->fMapSize = newsize;
2164 file->fMachOSize += delta; // Increment the image size
2165
2166 // If we are here then we have shifted the object image in memory
2167 // I really should change all of my pointers into the image to machO offsets
2168 // but I have run out of time. So I'm going to very quickly go over the
2169 // cached data structures and add adjustments to the addresses that are
2170 // affected. I wonder how long it will take me to get them all.
2171 //
2172 // For every pointer into the MachO I need to add an adjustment satisfying
2173 // the following simultanous equations
2174 // addr_old = macho_old + fixed_offset
2175 // addr_new = macho_new + fixed_offset therefore:
2176 // addr_new = addr_old + (macho_new - macho_old)
2177 #define REBASE(addr, delta) ( ((vm_address_t) (addr)) += (delta) )
2178 delta = newMachO - startMachO;
2179
2180 // Rebase the cached-in object 'struct symtab_command' pointer
2181 REBASE(file->fSymtab, delta);
2182
2183 // Rebase the cached-in object 'struct nlist' pointer for all symbols
2184 REBASE(file->fSymbolBase, delta);
2185
2186 // Rebase the cached-in object 'struct nlist' pointer for local symbols
2187 REBASE(file->fLocalSyms, delta);
2188
2189 // Rebase the cached-in object 'char' pointer for the string table
2190 REBASE(file->fStringBase, delta);
2191
2192 // Ok now we have to go over all of the relocs one last time
2193 // to clean up the pad updates which had their string index negated
2194 // to indicate that we have finished with them.
2195 section = file->fSections;
2196 for (i = 0, last = file->fNSects; i < last; i++, section++)
2197 REBASE(section->fSection, delta);
2198
2199 // We only ever grow images that contain class lists so dont bother
2200 // the check if file->fClassList is non-zero 'cause it can't be
2201 // assert(file->fClassList);
2202 last = DataGetLength(file->fClassList)
2203 / sizeof(struct metaClassRecord *);
2204 classes = (struct metaClassRecord **) DataGetPtr(file->fClassList);
2205 for (i = 0; i < last; i++) {
2206 struct patchRecord *patch;
2207
2208 for (patch = classes[i]->fPatchedVTable; patch->fSymbol; patch++) {
2209 vm_address_t symAddr = (vm_address_t) patch->fSymbol;
2210
2211 // Only need to rebase if the symbol is part of the image
2212 // If this is a new symbol then it was independantly allocated
2213 if (symAddr >= startMachO && symAddr < endMachO)
2214 REBASE(patch->fSymbol, delta);
2215 }
2216 }
2217
2218 // Finally rebase all of the string table pointers
2219 last = file->fSymtab->nsyms;
2220 for (i = 0; i < last; i++)
2221 REBASE(file->fSymbToStringTable[i], delta);
2222
2223 #undef REBASE
2224
2225 return true;
2226
2227 #endif /* KERNEL */
2228 }
2229
2230 // Note: This function is only called from kld_file_prepare_for_link()
2231 // This function can only operate on 32 bit mach-o files
2232 static Boolean
2233 prepareFileForLink(struct fileRecord *file)
2234 {
2235 unsigned long i, last, numnewsyms, newsymsize, newstrsize;
2236 struct sectionRecord *section;
2237 struct nlist **symp, *sym;
2238 DataRef newStrings, *stringBlocks;
2239
2240 // If we didn't even do a pseudo 'relocate' and dirty the image
2241 // then we can just return now.
2242 if (!file->fImageDirty) {
2243 #if !KERNEL
2244 if (file->fSwapped) {
2245 kld_macho_unswap((struct mach_header *) file->fMachO, file->fSwapped, false);
2246 file->fSwapped = false;
2247 }
2248 #endif
2249 return true;
2250 }
2251
2252 DEBUG_LOG(("Linking 2 %s\n", file->fPath)); // @@@ gvdl:
2253
2254 // We have to go over all of the relocs to repair the damage
2255 // that we have done to the image when we did our 'relocation'
2256 section = file->fSections;
2257 for (i = 0, last = file->fNSects; i < last; i++, section++) {
2258 unsigned char *sectionBase;
2259 struct relocRecord *rec;
2260 unsigned long j, nreloc;
2261
2262 if (section->fRelocCache) {
2263 sectionBase = file->fMachO + section->fSection->offset;
2264 nreloc = section->fSection->nreloc;
2265 rec = (struct relocRecord *) DataGetPtr(section->fRelocCache);
2266
2267 // We will need to repair the reloc list
2268 for (j = 0; j < nreloc; j++, rec++) {
2269 void **entry;
2270 struct nlist *repairSym;
2271
2272 // Repair Damage to object image
2273 entry = (void **) (sectionBase + rec->fRInfo->r_address);
2274 *entry = rec->fValue;
2275
2276 // Check if the symbol that this relocation entry points
2277 // to is marked as erasable
2278 repairSym = (struct nlist *) rec->fSymbol;
2279 if (repairSym && repairSym->n_type == (N_EXT | N_UNDF)
2280 && repairSym->n_sect == (unsigned char) -1) {
2281 // It is in use so we better clear the mark
2282 repairSym->n_un.n_strx = -repairSym->n_un.n_strx;
2283 repairSym->n_sect = NO_SECT;
2284 }
2285 }
2286
2287 // Clean up the fRelocCache we don't need it any more.
2288 DataRelease(section->fRelocCache);
2289 section->fRelocCache = 0;
2290 }
2291 }
2292 file->fImageDirty = false; // Image is clean
2293
2294 // If we didn't dirty the symbol table then just return
2295 if (!file->fSymbolsDirty) {
2296 #if !KERNEL
2297 if (file->fSwapped) {
2298 kld_macho_unswap((struct mach_header *) file->fMachO, file->fSwapped, false);
2299 file->fSwapped = false;
2300 }
2301 #endif
2302 return true;
2303 }
2304
2305 // calculate total file size increase and check against padding
2306 if (file->fNewSymbols) {
2307 numnewsyms = DataGetLength(file->fNewSymbols);
2308 symp = (struct nlist **) DataGetPtr(file->fNewSymbols);
2309 }
2310 else {
2311 numnewsyms = 0;
2312 symp = 0;
2313 }
2314 numnewsyms /= sizeof(struct nlist *);
2315 file->fSymtab->nsyms += numnewsyms;
2316
2317 // old sting size + 30% rounded up to nearest page
2318 newstrsize = file->fSymtab->strsize * 21 / 16;
2319 newstrsize = (newstrsize + PAGE_MASK) & ~PAGE_MASK;
2320 newStrings = DataCreate(newstrsize);
2321 return_if(!newStrings, false,
2322 ("Unable to allocate a copy aside buffer, no memory\n"));
2323
2324 newsymsize = numnewsyms * sizeof(struct nlist);
2325 file->fStringBase += newsymsize;
2326 file->fSymtab->stroff += newsymsize;
2327
2328 last = file->fSymtab->nsyms - numnewsyms;
2329 newstrsize = 0;
2330 DataAppendBytes(newStrings, &newstrsize, 4); // Leading nuls
2331 sym = file->fSymbolBase;
2332
2333 // Pre-compute an already offset new symbol pointer. The offset is the
2334 // orignal symbol table.
2335 symp -= last;
2336 for (i = 0; i < file->fSymtab->nsyms; i++, sym++) {
2337 const char *str = symNameByIndex(file, i);
2338 int len = strlen(str) + 1;
2339 unsigned int strx;
2340
2341 // Rebase sym in the new symbol region
2342 if (i >= last)
2343 sym = symp[i];
2344
2345 if (sym->n_un.n_strx < 0 && sym->n_type == (N_EXT | N_UNDF)
2346 && (unsigned char) -1 == sym->n_sect) {
2347 // after patching we find that this symbol is no longer in
2348 // use. So invalidate it by converting it into an N_ABS
2349 // symbol, remove the external bit and null out the name.
2350 bzero(sym, sizeof(*sym));
2351 sym->n_type = N_ABS;
2352 }
2353 else {
2354 // Repair the symbol for the getNewSymbol case.
2355 if (-1 == sym->n_un.n_strx)
2356 sym->n_value = 0;
2357
2358 // Record the offset of the string in the new table
2359 strx = DataGetLength(newStrings);
2360 return_if(!DataAppendBytes(newStrings, str, len), false,
2361 ("Unable to append string, no memory\n"));
2362
2363 sym->n_un.n_strx = strx;
2364 file->fSymbToStringTable[i] = file->fStringBase + strx;
2365 }
2366 }
2367
2368 // Don't need the new strings any more
2369
2370 if (file->fNewStringBlocks){
2371 last = DataGetLength(file->fNewStringBlocks) / sizeof(DataRef);
2372 stringBlocks = (DataRef *) DataGetPtr(file->fNewStringBlocks);
2373 }
2374 else{
2375 last =0;
2376 stringBlocks=0;
2377 }
2378
2379 for (i = 0; i < last; i++)
2380 DataRelease(stringBlocks[i]);
2381
2382 DataRelease(file->fNewStringBlocks);
2383 file->fNewStringBlocks = 0;
2384
2385 newstrsize = DataGetLength(newStrings);
2386 newstrsize = (newstrsize + 3) & ~3; // Round to nearest word
2387 return_if(
2388 !growImage(file, newsymsize + newstrsize - file->fSymtab->strsize),
2389 false, ("Unable to patch the extension, no memory\n", file->fPath));
2390
2391 // Push out the new symbol table if necessary
2392 if (numnewsyms) {
2393 caddr_t base;
2394
2395 // Append the new symbols to the original symbol table.
2396 base = (caddr_t) file->fSymbolBase
2397 + (file->fSymtab->nsyms - numnewsyms) * sizeof(struct nlist);
2398 symp = (struct nlist **) DataGetPtr(file->fNewSymbols);
2399 for (i = 0; i < numnewsyms; i++, base += sizeof(struct nlist), symp++)
2400 bcopy(*symp, base, sizeof(struct nlist));
2401
2402 DataRelease(file->fNewSymbols);
2403 file->fNewSymbols = 0;
2404 }
2405
2406 // Push out the new string table if necessary
2407 if (newStrings) {
2408 unsigned long *base = (unsigned long *) file->fStringBase;
2409 unsigned long actuallen = DataGetLength(newStrings);
2410
2411 // Set the last word in string table to zero before copying data
2412 base[(newstrsize / sizeof(unsigned long)) - 1] = 0;
2413
2414 // Now copy the new strings back to the end of the file
2415 bcopy((caddr_t) DataGetPtr(newStrings), file->fStringBase, actuallen);
2416
2417 file->fSymtab->strsize = newstrsize;
2418
2419 DataRelease(newStrings);
2420 }
2421
2422 file->fSymbolsDirty = false;
2423 #if !KERNEL
2424 if (file->fSwapped) {
2425 kld_macho_unswap((struct mach_header *) file->fMachO, file->fSwapped, false);
2426 file->fSwapped = false;
2427 }
2428 #endif
2429 return true;
2430 }
2431
2432 // This function can only operate on 32 bit mach-o files
2433 Boolean
2434 #if KERNEL
2435 kld_file_map(const char *pathName,
2436 unsigned char *map,
2437 size_t mapSize,
2438 Boolean isKmem)
2439 #else
2440 kld_file_map(const char *pathName)
2441 #endif /* KERNEL */
2442 {
2443 struct fileRecord file, *fp = 0;
2444
2445 // Already done no need to repeat
2446 fp = getFile(pathName);
2447 if (fp)
2448 return true;
2449
2450 bzero(&file, sizeof(file));
2451
2452 #if KERNEL
2453 file.fMap = map;
2454 file.fMapSize = mapSize;
2455 file.fIsKmem = isKmem;
2456 #else
2457 if (!mapObjectFile(&file, pathName))
2458 return false;
2459 #endif /* KERNEL */
2460
2461 do {
2462 const struct machOMapping {
2463 struct mach_header h;
2464 struct load_command c[1];
2465 } *machO;
2466 const struct load_command *cmd;
2467 boolean_t lookVMRange;
2468 unsigned long i;
2469
2470 if (!findBestArch(&file, pathName))
2471 break;
2472
2473 machO = (const struct machOMapping *) file.fMachO;
2474 if (file.fMachOSize < machO->h.sizeofcmds)
2475 break;
2476
2477 // If the file type is MH_EXECUTE then this must be a kernel
2478 // as all Kernel extensions must be of type MH_OBJECT
2479 file.fIsKernel = (MH_EXECUTE == machO->h.filetype);
2480
2481 for (i = 0, cmd = &machO->c[0], lookVMRange = true; i < machO->h.ncmds; i++) {
2482 if (cmd->cmd == LC_SYMTAB)
2483 file.fSymtab = (struct symtab_command *) cmd;
2484 else if (cmd->cmd == LC_SEGMENT) {
2485 struct segment_command *seg = (struct segment_command *) cmd;
2486 int nsects = seg->nsects;
2487
2488 if (lookVMRange) {
2489 if (!strcmp("__PRELINK", seg->segname))
2490 // segments following __PRELINK are going to move, so ignore them
2491 lookVMRange = false;
2492 else if (!file.fVMAddr && !file.fVMEnd) {
2493 file.fVMAddr = seg->vmaddr;
2494 file.fVMEnd = seg->vmaddr + seg->vmsize;
2495 } else {
2496 if (seg->vmaddr < file.fVMAddr)
2497 file.fVMAddr = seg->vmaddr;
2498 if ((seg->vmaddr + seg->vmsize) > file.fVMEnd)
2499 file.fVMEnd = seg->vmaddr + seg->vmsize;
2500 }
2501 }
2502
2503 if (nsects)
2504 return_if(!parseSegments(&file, seg),
2505 false, ("%s isn't a valid mach-o, bad segment",
2506 pathName));
2507
2508 if (file.fIsKernel) {
2509 #if KERNEL
2510 // We don't need to look for the LinkEdit segment unless
2511 // we are running in the kernel environment.
2512 if (!strcmp(kLinkEditSegName, seg->segname))
2513 file.fLinkEditSeg = seg;
2514 #endif
2515 }
2516 }
2517 cmd = (struct load_command *) ((UInt8 *) cmd + cmd->cmdsize);
2518 }
2519 break_if(!file.fSymtab,
2520 ("%s isn't a valid mach-o, no symbols\n", pathName));
2521
2522 if (machO->h.flags & MH_INCRLINK) {
2523
2524 file.fIsIncrLink = true;
2525 ((struct machOMapping *) machO)->h.flags &= ~MH_INCRLINK;
2526
2527 #if !KERNEL
2528 // the symtab fileoffset is the end of seg0's vmsize,
2529 // which can be (rarely) unaligned.
2530 unsigned int
2531 align = file.fSymtab->symoff % sizeof(long);
2532 if (align != 0) {
2533 align = sizeof(long) - align;
2534 growImage(&file, align);
2535 bcopy(file.fMachO + file.fSymtab->symoff,
2536 file.fMachO + file.fSymtab->symoff + align,
2537 file.fSymtab->stroff + file.fSymtab->strsize - file.fSymtab->symoff);
2538 file.fSymtab->symoff += align;
2539 file.fSymtab->stroff += align;
2540 }
2541 #endif
2542 }
2543
2544 if (!parseSymtab(&file, pathName))
2545 break;
2546
2547 fp = addFile(&file, pathName);
2548 if (!fp)
2549 break;
2550
2551 if (file.fFoundOSObject && !getMetaClassGraph(fp))
2552 break;
2553
2554 if (file.fIsKernel)
2555 sKernelFile = fp;
2556
2557 #if KERNEL
2558 // Automatically load the kernel's link edit segment if we are
2559 // attempting to load a driver.
2560 if (!sKernelFile) {
2561 struct segment_command *sg;
2562 size_t kernelSize;
2563 Boolean ret;
2564
2565 sg = (struct segment_command *) getsegbyname(kLinkEditSegName);
2566 break_if(!sg, ("Can't find kernel link edit segment\n"));
2567
2568 kernelSize = sg->vmaddr + sg->vmsize - (size_t) &_mh_execute_header;
2569 ret = kld_file_map(kld_basefile_name,
2570 (unsigned char *) &_mh_execute_header, kernelSize,
2571 /* isKmem */ false);
2572 break_if(!ret, ("kld can't map kernel file"));
2573 }
2574 #endif /* KERNEL */
2575
2576 return true;
2577 } while(0);
2578
2579 // Failure path, then clean up
2580 if (fp)
2581 // @@@ gvdl: for the time being leak the file ref in the file table
2582 removeFile(fp);
2583 else
2584 unmapFile(&file);
2585
2586 return false;
2587 }
2588
2589 void *kld_file_getaddr(const char *pathName, long *size)
2590 {
2591 struct fileRecord *file = getFile(pathName);
2592
2593 if (!file)
2594 return 0;
2595
2596 if (size)
2597 *size = file->fMachOSize;
2598
2599 return file->fMachO;
2600 }
2601
2602 void *kld_file_lookupsymbol(const char *pathName, const char *symname)
2603 {
2604 struct fileRecord *file = getFile(pathName);
2605 const struct nlist *sym;
2606 const struct section *section;
2607 unsigned char *sectionBase;
2608 unsigned char sectind;
2609
2610 return_if(!file,
2611 NULL, ("Unknown file %s\n", pathName));
2612
2613 sym = findSymbolByName(file, symname);
2614
2615 // May be a non-extern symbol so look for it there
2616 if (!sym) {
2617 unsigned int i, nsyms;
2618
2619 sym = file->fSymbolBase;
2620 for (i = 0, nsyms = file->fSymtab->nsyms; i < nsyms; i++, sym++) {
2621 if ( (sym->n_type & N_EXT) ) {
2622 sym = 0;
2623 break; // Terminate search when we hit an extern
2624 }
2625 if ( (sym->n_type & N_STAB) )
2626 continue;
2627 if ( !strcmp(symname, symNameByIndex(file, i)) )
2628 break;
2629 }
2630 }
2631
2632 return_if(!sym,
2633 NULL, ("Unknown symbol %s in %s\n", symname, pathName));
2634
2635 // Is the vtable in a valid section?
2636 sectind = sym->n_sect;
2637 return_if(sectind == NO_SECT || sectind > file->fNSects, NULL,
2638 ("Malformed object file, invalid section reference for %s in %s\n",
2639 symname, pathName));
2640
2641 section = file->fSections[sectind - 1].fSection;
2642 sectionBase = file->fMachO + section->offset - section->addr;
2643
2644 return (void *) (sectionBase + sym->n_value);
2645 }
2646
2647 Boolean kld_file_merge_OSObjects(const char *pathName)
2648 {
2649 struct fileRecord *file = getFile(pathName);
2650
2651 return_if(!file,
2652 false, ("Internal error - unable to find file %s\n", pathName));
2653
2654 return mergeOSObjectsForFile(file);
2655 }
2656
2657 Boolean kld_file_patch_OSObjects(const char *pathName)
2658 {
2659 struct fileRecord *file = getFile(pathName);
2660 struct metaClassRecord **classes;
2661 unsigned long i, last;
2662
2663 return_if(!file,
2664 false, ("Internal error - unable to find file %s\n", pathName));
2665
2666 DEBUG_LOG(("Patch file %s\n", pathName)); // @@@ gvdl:
2667
2668 // If we don't have any classes we can return now.
2669 if (!file->fClassList)
2670 return true;
2671
2672 // If we haven't alread merged the kernel then do it now
2673 if (!sMergedKernel && sKernelFile)
2674 mergeOSObjectsForFile(sKernelFile);
2675 return_if(!sMergedKernel, false, ("Internal error no kernel?\n"));
2676
2677 if (!mergeOSObjectsForFile(file))
2678 return false;
2679
2680 // Patch all of the classes in this executable
2681 last = DataGetLength(file->fClassList) / sizeof(void *);
2682 classes = (struct metaClassRecord **) DataGetPtr(file->fClassList);
2683 for (i = 0; i < last; i++) {
2684 if (!patchVTable(classes[i])) {
2685 // RY: Set a flag in the file list to invalidate this data.
2686 // I would remove the file from the list, but that seems to be
2687 // not worth the effort.
2688 file->fIgnoreFile = TRUE;
2689
2690 return false;
2691 }
2692 }
2693
2694 return true;
2695 }
2696
2697 Boolean kld_file_prepare_for_link(void)
2698 {
2699 if (sMergedFiles) {
2700 unsigned long i, nmerged = 0;
2701 struct fileRecord **files;
2702
2703 // Check to see if we have already merged this file
2704 nmerged = DataGetLength(sMergedFiles) / sizeof(struct fileRecord *);
2705 files = (struct fileRecord **) DataGetPtr(sMergedFiles);
2706 for (i = 0; i < nmerged; i++) {
2707 if (!files[i]->fIgnoreFile && !prepareFileForLink(files[i]))
2708 return false;
2709 }
2710 }
2711
2712 // Clear down the meta class table and merged file lists
2713 DataRelease(sMergeMetaClasses);
2714 DataRelease(sMergedFiles);
2715 sMergedFiles = sMergeMetaClasses = NULL;
2716 sMergedKernel = false;
2717
2718 return true;
2719 }
2720
2721 void kld_file_cleanup_all_resources(void)
2722 {
2723 unsigned long i, nfiles;
2724
2725 #if KERNEL // @@@ gvdl:
2726 // Debugger("kld_file_cleanup_all_resources");
2727 #endif
2728
2729 if (!sFilesTable || !(nfiles = DataGetLength(sFilesTable)))
2730 return; // Nothing to do just return now
2731
2732 nfiles /= sizeof(struct fileRecord *);
2733 for (i = 0; i < nfiles; i++)
2734 removeFile(((void **) DataGetPtr(sFilesTable))[i]);
2735
2736 DataRelease(sFilesTable);
2737 sFilesTable = NULL;
2738
2739 // Don't really have to clean up anything more as the whole
2740 // malloc engine is going to be released and I couldn't be bothered.
2741 }
2742
2743
2744 #if !KERNEL
2745 #if 0
2746 static const struct fileRecord *sortFile;
2747 static int symCompare(const void *vSym1, const void *vSym2)
2748 {
2749 const struct nlist *sym1 = vSym1;
2750 const struct nlist *sym2 = vSym2;
2751
2752 {
2753 unsigned int ind1, ind2;
2754
2755 ind1 = sym1->n_type & N_TYPE;
2756 ind2 = sym2->n_type & N_TYPE;
2757 if (ind1 != ind2) {
2758 // if sym1 is undefined then sym1 must come later than sym2
2759 if (ind1 == N_UNDF)
2760 return 1;
2761 // if sym2 is undefined then sym1 must come earlier than sym2
2762 if (ind2 == N_UNDF)
2763 return -1;
2764 /* drop out if neither are undefined */
2765 }
2766 }
2767
2768 {
2769 const struct fileRecord *file = sortFile;
2770 const char *name1, *name2;
2771
2772 name1 = file->fStringBase + sym1->n_un.n_strx;
2773 name2 = file->fStringBase + sym2->n_un.n_strx;
2774 return strcmp(name1, name2);
2775 }
2776 }
2777 #endif /* 0 */
2778
2779 Boolean kld_file_debug_dump(const char *pathName, const char *outName)
2780 {
2781 const struct fileRecord *file = getFile(pathName);
2782 int fd;
2783 Boolean ret = false;
2784
2785 return_if(!file, false, ("Unknown file %s for dumping\n", pathName));
2786
2787 fd = open(outName, O_WRONLY|O_CREAT|O_TRUNC, 0666);
2788 return_if(-1 == fd, false, ("Can't create output file %s - %s(%d)\n",
2789 outName, strerror(errno), errno));
2790
2791 do {
2792 #if 0
2793 // Sorting doesn't work until I fix the relocs too?
2794
2795 // sort the symbol table appropriately
2796 unsigned int nsyms = file->fSymtab->nsyms
2797 - (file->fLocalSyms - file->fSymbolBase);
2798 sortFile = file;
2799 heapsort((void *) file->fLocalSyms, nsyms, sizeof(struct nlist),
2800 symCompare);
2801 #endif
2802
2803 break_if(-1 == write(fd, file->fMachO, file->fMachOSize),
2804 ("Can't dump output file %s - %s(%d)\n",
2805 outName, strerror(errno), errno));
2806 ret = true;
2807 } while(0);
2808
2809 close(fd);
2810
2811 return ret;
2812 }
2813
2814 #endif /* !KERNEL */
2815