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