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