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