]> git.saurik.com Git - apple/xnu.git/blob - libsa/kld_patch.c
xnu-201.5.tar.gz
[apple/xnu.git] / libsa / kld_patch.c
1 /*
2 * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * History:
26 * 2001-05-30 gvdl Initial implementation of the vtable patcher.
27 */
28 // 45678901234567890123456789012345678901234567890123456789012345678901234567890
29
30 #include <mach-o/fat.h>
31 #include <mach-o/loader.h>
32 #include <mach-o/nlist.h>
33 #include <mach-o/reloc.h>
34
35 #if KERNEL
36
37 #include <stdarg.h>
38 #include <string.h>
39
40 #include <sys/systm.h>
41
42 #include <libkern/OSTypes.h>
43
44 #include <libsa/stdlib.h>
45 #include <libsa/mach/mach.h>
46
47 #include "mach_loader.h"
48
49 #include <vm/vm_kern.h>
50
51 enum { false = 0, true = 1 };
52
53 #define vm_page_size page_size
54
55 extern load_return_t fatfile_getarch(
56 void * vp, // normally a (struct vnode *)
57 vm_offset_t data_ptr,
58 struct fat_arch * archret);
59
60 #else /* !KERNEL */
61 #include <unistd.h>
62
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66
67 #include <sys/errno.h>
68 #include <sys/fcntl.h>
69 #include <sys/stat.h>
70 #include <sys/mman.h>
71
72 #include <mach/mach.h>
73 #include <mach/mach_error.h>
74
75 #include <mach-o/arch.h>
76
77 #include <CoreFoundation/CoreFoundation.h>
78
79 #endif /* KERNEL */
80
81 #include "kld_patch.h"
82
83 #if 0
84 static __inline__ void DIE(void) { IODelay(2000000000); }
85
86 #define LOG_DELAY() IODelay(200000)
87 #define DEBUG_LOG(x) do { IOLog x; LOG_DELAY(); } while(0)
88 #else
89
90 #define DIE()
91 #define LOG_DELAY()
92 #define DEBUG_LOG(x)
93
94 #endif
95
96 // OSObject symbol prefixes and suffixes
97 #define kVTablePrefix "___vt"
98 #define kReservedPrefix "__RESERVED"
99 #define kSuperClassSuffix ".superClass"
100 #define kGMetaSuffix ".gMetaClass"
101 #define kLinkEditSegName SEG_LINKEDIT
102
103 // GCC 2.95 drops 2 leading constants in the vtable
104 #define kVTablePreambleLen 2
105
106 // Last address that I'm willing to try find vm in
107 #define kTopAddr ((unsigned char *) (1024 * 1024 * 1024))
108
109 // Size in bytes that Data Ref object's get increased in size
110 // Must be a power of 2
111 #define kDataCapacityIncrement 128
112
113 // My usual set of helper macros. I personally find these macros
114 // easier to read in the code rather than an explicit error condition
115 // check. If I don't make it easy then I may get lazy ond not check
116 // everything. I'm sorry if you find this code harder to read.
117
118 // break_if will evaluate the expression and if it is true
119 // then it will print the msg, which is enclosed in parens
120 // and then break. Usually used in loops are do { } while (0)
121 #define break_if(expr, msg) \
122 if (expr) { \
123 errprintf msg; \
124 break; \
125 }
126
127 // return_if will evaluate expr and if true it will log the
128 // msg, which is enclosed in parens, and then it will return
129 // with the return code of ret.
130 #define return_if(expr, ret, msg) do { \
131 if (expr) { \
132 errprintf msg; \
133 return ret; \
134 } \
135 } while (0)
136
137 #ifndef MIN
138 #define MIN(a,b) (((a)<(b))?(a):(b))
139 #endif /* MIN */
140 #ifndef MAX
141 #define MAX(a,b) (((a)>(b))?(a):(b))
142 #endif /* MAX */
143
144 typedef struct Data {
145 unsigned long fLength, fCapacity;
146 unsigned char *fData;
147 } Data, *DataRef;
148
149 struct sectionRecord {
150 const struct section *fSection;
151 DataRef fRelocCache;
152 };
153
154 enum patchState {
155 kSymbolIdentical,
156 kSymbolLocal,
157 kSymbolPadUpdate,
158 kSymbolSuperUpdate,
159 kSymbolMismatch
160 };
161
162 struct patchRecord {
163 struct nlist *fSymbol;
164 enum patchState fType;
165 };
166
167 struct relocRecord {
168 void *fValue;
169 const struct nlist *fSymbol;
170 struct relocation_info *fRInfo;
171 void *reserved;
172 };
173
174 struct metaClassRecord {
175 char *fSuperName;
176 struct fileRecord *fFile;
177 const struct nlist *fVTableSym;
178 struct patchRecord *fPatchedVTable;
179 char fClassName[1];
180 };
181
182 struct fileRecord {
183 size_t fMapSize, fMachOSize;
184 const char *fPath;
185 unsigned char *fMap, *fMachO, *fPadEnd;
186 DataRef fClassList;
187 DataRef fSectData;
188 DataRef fNewSymbols, fNewStrings;
189 struct symtab_command *fSymtab;
190 struct sectionRecord *fSections;
191 char *fStringBase;
192 struct nlist *fSymbolBase;
193 const struct nlist *fLocalSyms;
194 unsigned int fNSects;
195 int fNLocal;
196 int fNewStringsLen;
197 Boolean fIsKernel, fNoKernelExecutable, fIsKmem;
198 Boolean fImageDirty, fSymbolsDirty;
199 };
200
201 static DataRef sFilesTable;
202 static struct fileRecord *sKernelFile;
203
204 static DataRef sMergedFiles;
205 static DataRef sMergeMetaClasses;
206 static Boolean sMergedKernel;
207
208 static void errprintf(const char *fmt, ...)
209 {
210 extern void kld_error_vprintf(const char *format, va_list ap);
211
212 va_list ap;
213
214 va_start(ap, fmt);
215 kld_error_vprintf(fmt, ap);
216 va_end(ap);
217
218 DIE();
219 }
220
221 static __inline__ unsigned long DataGetLength(DataRef data)
222 {
223 return data->fLength;
224 }
225
226 static __inline__ unsigned char *DataGetPtr(DataRef data)
227 {
228 return data->fData;
229 }
230
231
232 static __inline__ Boolean DataContainsAddr(DataRef data, void *vAddr)
233 {
234 unsigned char *addr = vAddr;
235
236 return (data->fData <= addr) && (addr < data->fData + data->fLength);
237 }
238
239 static __inline__ Boolean DataAddLength(DataRef data, unsigned long length)
240 {
241 static Boolean DataSetLength(DataRef data, unsigned long length);
242 return DataSetLength(data, data->fLength + length);
243 }
244
245 static __inline__ Boolean
246 DataAppendBytes(DataRef data, const void *addr, unsigned int len)
247 {
248 unsigned long size = DataGetLength(data);
249
250 if (!DataAddLength(data, len))
251 return false;
252
253 bcopy(addr, DataGetPtr(data) + size, len);
254 return true;
255 }
256
257 static __inline__ Boolean DataAppendData(DataRef dst, DataRef src)
258 {
259 return DataAppendBytes(dst, DataGetPtr(src), DataGetLength(src));
260 }
261
262 static Boolean DataSetLength(DataRef data, unsigned long length)
263 {
264 // Don't bother to ever shrink a data object.
265 if (length > data->fCapacity) {
266 unsigned char *newData;
267 unsigned long newCapacity;
268
269 newCapacity = length + kDataCapacityIncrement - 1;
270 newCapacity &= ~(kDataCapacityIncrement - 1);
271 newData = (unsigned char *) realloc(data->fData, newCapacity);
272 if (!newData)
273 return false;
274
275 bzero(newData + data->fCapacity, newCapacity - data->fCapacity);
276 data->fData = newData;
277 data->fCapacity = newCapacity;
278 }
279
280 data->fLength = length;
281 return true;
282 }
283
284 static DataRef DataCreate(unsigned long length)
285 {
286 DataRef data = (DataRef) malloc(sizeof(Data));
287
288 if (data) {
289 if (!length)
290 data->fCapacity = kDataCapacityIncrement;
291 else {
292 data->fCapacity = length + kDataCapacityIncrement - 1;
293 data->fCapacity &= ~(kDataCapacityIncrement - 1);
294 }
295
296 data->fData = (unsigned char *) malloc(data->fCapacity);
297 if (!data->fData) {
298 free(data);
299 return NULL;
300 }
301
302 bzero(data->fData, data->fCapacity);
303 data->fLength = length;
304 }
305 return data;
306 }
307
308 static void DataRelease(DataRef data)
309 {
310 if (data) {
311 if (data->fData)
312 free(data->fData);
313 data->fData = 0;
314 free(data);
315 }
316 }
317
318 static const char *
319 symbolname(const struct fileRecord *file, const struct nlist *sym)
320 {
321 unsigned long strsize;
322 long strx = sym->n_un.n_strx;
323
324 if (strx >= 0)
325 return file->fStringBase + strx;
326
327 strsize = file->fSymtab->strsize;
328 strx = -strx;
329 if (strx < strsize)
330 return file->fStringBase + strx;
331
332 strx -= strsize;
333 return (char *) DataGetPtr(file->fNewStrings) + strx;
334 }
335
336 static struct fileRecord *getFile(const char *path)
337 {
338 if (sFilesTable) {
339 int i, nfiles;
340 struct fileRecord **files;
341
342 // Check to see if we have already merged this file
343 nfiles = DataGetLength(sFilesTable) / sizeof(struct fileRecord *);
344 files = (struct fileRecord **) DataGetPtr(sFilesTable);
345 for (i = 0; i < nfiles; i++) {
346 if (!strcmp(path, files[i]->fPath))
347 return files[i];
348 }
349 }
350
351 return NULL;
352 }
353
354 static struct fileRecord * addFile(struct fileRecord *file)
355 {
356 struct fileRecord *newFile;
357
358 if (!sFilesTable) {
359 sFilesTable = DataCreate(0);
360 if (!sFilesTable)
361 return NULL;
362 }
363
364 newFile = (struct fileRecord *) malloc(sizeof(struct fileRecord));
365 if (!newFile)
366 return NULL;
367
368 if (!DataAppendBytes(sFilesTable, &newFile, sizeof(newFile))) {
369 free(newFile);
370 return NULL;
371 }
372
373 bcopy(file, newFile, sizeof(struct fileRecord));
374 return newFile;
375 }
376
377 // @@@ gvdl: need to clean up the sMergeMetaClasses
378 // @@@ gvdl: I had better fix the object file up again
379 static void removeFile(struct fileRecord *file)
380 {
381 if (file->fClassList) {
382 DataRelease(file->fClassList);
383 file->fClassList = 0;
384 }
385
386 if (file->fSectData) {
387 struct sectionRecord *section;
388 unsigned int i, nsect;
389
390 nsect = file->fNSects;
391 section = file->fSections;
392 for (i = 0; i < nsect; i++, section++) {
393 if (section->fRelocCache) {
394 DataRelease(section->fRelocCache);
395 section->fRelocCache = 0;
396 }
397 }
398
399 DataRelease(file->fSectData);
400 file->fSectData = 0;
401 file->fSections = 0;
402 file->fNSects = 0;
403 }
404
405 if (file->fMap) {
406 #if KERNEL
407 if (file->fIsKmem)
408 kmem_free(kernel_map, (vm_address_t) file->fMap, file->fMapSize);
409 #else /* !KERNEL */
410 if (file->fPadEnd) {
411 vm_address_t padVM;
412 vm_size_t padSize;
413
414 padVM = round_page((vm_address_t) file->fMap + file->fMapSize);
415 padSize = (vm_size_t) ((vm_address_t) file->fPadEnd - padVM);
416 (void) vm_deallocate(mach_task_self(), padVM, padSize);
417 file->fPadEnd = 0;
418 }
419
420 (void) munmap((caddr_t) file->fMap, file->fMapSize);
421 #endif /* !KERNEL */
422 file->fMap = 0;
423 }
424
425 file->fPath = 0;
426 }
427
428 #if !KERNEL
429 static Boolean
430 mapObjectFile(struct fileRecord *file)
431 {
432 Boolean result = false;
433 static unsigned char *sFileMapBaseAddr;
434
435 int fd = 0;
436
437 if (!sFileMapBaseAddr) {
438 kern_return_t ret;
439 vm_address_t probeAddr;
440
441 // If we don't already have a base addr find any random chunk
442 // of 32 meg of VM and to use the 16 meg boundrary as a base.
443 ret = vm_allocate(mach_task_self(), &probeAddr,
444 32 * 1024 * 1024, VM_FLAGS_ANYWHERE);
445 return_if(KERN_SUCCESS != ret, false,
446 ("Unable to allocate base memory %s\n", mach_error_string(ret)));
447 (void) vm_deallocate(mach_task_self(), probeAddr, 32 * 1024 * 1024);
448
449 // Now round to the next 16 Meg boundrary
450 probeAddr = (probeAddr + (16 * 1024 * 1024 - 1))
451 & ~(16 * 1024 * 1024 - 1);
452 sFileMapBaseAddr = (unsigned char *) probeAddr;
453 }
454
455 fd = open(file->fPath, O_RDONLY, 0);
456 return_if(fd == -1, false, ("Can't open %s for reading - %s\n",
457 file->fPath, strerror(errno)));
458
459 do {
460 kern_return_t ret;
461 struct stat sb;
462 int retaddr = -1;
463
464 break_if(fstat(fd, &sb) == -1,
465 ("Can't stat %s - %s\n", file->fPath, strerror(errno)));
466
467 file->fMapSize = sb.st_size;
468 file->fMap = sFileMapBaseAddr;
469 ret = KERN_SUCCESS;
470 while (file->fMap < kTopAddr) {
471 vm_address_t padVM;
472 vm_address_t padVMEnd;
473 vm_size_t padSize;
474
475 padVM = round_page((vm_address_t) file->fMap + file->fMapSize);
476 retaddr = (int) mmap(file->fMap, file->fMapSize,
477 PROT_READ|PROT_WRITE,
478 MAP_FIXED|MAP_FILE|MAP_PRIVATE,
479 fd, 0);
480 if (-1 == retaddr) {
481 break_if(ENOMEM != errno,
482 ("mmap failed %d - %s\n", errno, strerror(errno)));
483
484 file->fMap = (unsigned char *) padVM;
485 continue;
486 }
487
488
489 // Round up padVM to the next page after the file and assign at
490 // least another fMapSize more room rounded up to the next page
491 // boundary.
492 padVMEnd = round_page(padVM + file->fMapSize);
493 padSize = padVMEnd - padVM;
494 ret = vm_allocate(
495 mach_task_self(), &padVM, padSize, VM_FLAGS_FIXED);
496 if (KERN_SUCCESS == ret) {
497 file->fPadEnd = (unsigned char *) padVMEnd;
498 break;
499 }
500 else {
501 munmap(file->fMap, file->fMapSize);
502 break_if(KERN_INVALID_ADDRESS != ret,
503 ("Unable to allocate pad vm for %s - %s\n",
504 file->fPath, mach_error_string(ret)));
505
506 file->fMap = (unsigned char *) padVMEnd;
507 continue; // try again wherever the vm system wants
508 }
509 }
510
511 if (-1 == retaddr || KERN_SUCCESS != ret)
512 break;
513
514 break_if(file->fMap >= kTopAddr,
515 ("Unable to map memory %s\n", file->fPath));
516
517 sFileMapBaseAddr = file->fPadEnd;
518 result = true;
519 } while(0);
520
521 close(fd);
522 return result;
523 }
524 #endif /* !KERNEL */
525
526 static Boolean findBestArch(struct fileRecord *file)
527 {
528 unsigned long magic;
529 struct fat_header *fat;
530
531
532 file->fMachOSize = file->fMapSize;
533 file->fMachO = file->fMap;
534 magic = ((const struct mach_header *) file->fMachO)->magic;
535 fat = (struct fat_header *) file->fMachO;
536
537 // Try to figure out what type of file this is
538 return_if(file->fMapSize < sizeof(unsigned long), false,
539 ("%s isn't a valid object file - no magic\n", file->fPath));
540
541 #if KERNEL
542
543 // CIGAM is byte-swapped MAGIC
544 if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
545
546 load_return_t load_return;
547 struct fat_arch fatinfo;
548
549 load_return = fatfile_getarch(NULL, (vm_address_t) fat, &fatinfo);
550 return_if(load_return != LOAD_SUCCESS, false,
551 ("Extension \"%s\": has no code for this computer\n", file->fPath));
552
553 file->fMachO = file->fMap + fatinfo.offset;
554 file->fMachOSize = fatinfo.size;
555 magic = ((const struct mach_header *) file->fMachO)->magic;
556 }
557
558 #else /* !KERNEL */
559
560 // Do we need to in-place swap the endianness of the fat header?
561 if (magic == FAT_CIGAM) {
562 unsigned long i;
563 struct fat_arch *arch;
564
565 fat->nfat_arch = NXSwapBigLongToHost(fat->nfat_arch);
566 return_if(file->fMapSize < sizeof(struct fat_header)
567 + fat->nfat_arch * sizeof(struct fat_arch),
568 false, ("%s is too fat\n", file->fPath));
569
570 arch = (struct fat_arch *) &fat[1];
571 for (i = 0; i < fat->nfat_arch; i++) {
572 arch[i].cputype = NXSwapBigLongToHost(arch[i].cputype);
573 arch[i].cpusubtype = NXSwapBigLongToHost(arch[i].cpusubtype);
574 arch[i].offset = NXSwapBigLongToHost(arch[i].offset);
575 arch[i].size = NXSwapBigLongToHost(arch[i].size);
576 arch[i].align = NXSwapBigLongToHost(arch[i].align);
577 }
578
579 magic = NXSwapBigLongToHost(fat->magic);
580 }
581
582 // Now see if we can find any valid architectures
583 if (magic == FAT_MAGIC) {
584 const NXArchInfo *myArch;
585 unsigned long fatsize;
586 struct fat_arch *arch;
587
588 fatsize = sizeof(struct fat_header)
589 + fat->nfat_arch * sizeof(struct fat_arch);
590 return_if(file->fMapSize < fatsize,
591 false, ("%s isn't a valid fat file\n", file->fPath));
592
593 myArch = NXGetLocalArchInfo();
594 arch = NXFindBestFatArch(myArch->cputype, myArch->cpusubtype,
595 (struct fat_arch *) &fat[1], fat->nfat_arch);
596 return_if(!arch,
597 false, ("%s hasn't got arch for %s\n", file->fPath, myArch->name));
598 return_if(arch->offset + arch->size > file->fMapSize,
599 false, ("%s's %s arch is incomplete\n", file->fPath, myArch->name));
600 file->fMachO = file->fMap + arch->offset;
601 file->fMachOSize = arch->size;
602 magic = ((const struct mach_header *) file->fMachO)->magic;
603 }
604
605 #endif /* KERNEL */
606
607 return_if(magic != MH_MAGIC,
608 false, ("%s isn't a valid mach-o\n", file->fPath));
609
610 return true;
611 }
612
613 static Boolean
614 parseSegments(struct fileRecord *file, struct segment_command *seg)
615 {
616 struct sectionRecord *sections;
617 int i, nsects = seg->nsects;
618 const struct segmentMap {
619 struct segment_command seg;
620 const struct section sect[1];
621 } *segMap;
622
623 if (!nsects) {
624 #if KERNEL
625 // We don't need to look for the LinkEdit segment unless
626 // we are running in the kernel environment.
627 if (!strcmp(kLinkEditSegName, seg->segname)) {
628 // Grab symbol table from linkedit we will need this later
629 file->fSymbolBase = (void *) seg;
630 }
631 #endif
632
633 return true; // Nothing more to do, so that was easy.
634 }
635
636 if (!file->fSectData) {
637 file->fSectData = DataCreate(0);
638 if (!file->fSectData)
639 return false;
640 }
641
642 // Increase length of section DataRef and cache data pointer
643 if (!DataAddLength(file->fSectData, nsects * sizeof(struct sectionRecord)))
644 return false;
645 file->fSections = (struct sectionRecord *) DataGetPtr(file->fSectData);
646
647 // Initialise the new sections
648 sections = &file->fSections[file->fNSects];
649 file->fNSects += nsects;
650 for (i = 0, segMap = (struct segmentMap *) seg; i < nsects; i++)
651 sections[i].fSection = &segMap->sect[i];
652
653 return true;
654 }
655
656 // @@@ gvdl: These functions need to be hashed they are
657 // going to be way too slow for production code.
658 static const struct nlist *
659 findSymbolByAddress(const struct fileRecord *file, void *entry)
660 {
661 // not quite so dumb linear search of all symbols
662 const struct nlist *sym;
663 int i, nsyms;
664
665 // First try to find the symbol in the most likely place which is the
666 // extern symbols
667 sym = file->fLocalSyms;
668 for (i = 0, nsyms = file->fNLocal; i < nsyms; i++, sym++) {
669 if (sym->n_value == (unsigned long) entry && !(sym->n_type & N_STAB) )
670 return sym;
671 }
672
673 // Didn't find it in the external symbols so try to local symbols before
674 // giving up.
675 sym = file->fSymbolBase;
676 for (i = 0, nsyms = file->fSymtab->nsyms; i < nsyms; i++, sym++) {
677 if ( (sym->n_type & N_EXT) )
678 return NULL;
679 if ( sym->n_value == (unsigned long) entry && !(sym->n_type & N_STAB) )
680 return sym;
681 }
682
683 return NULL;
684 }
685
686 struct searchContext {
687 const char *fSymname;
688 const char *fStrbase;
689 };
690
691 static int symbolSearch(const void *vKey, const void *vSym)
692 {
693 const struct searchContext *key = (const struct searchContext *) vKey;
694 const struct nlist *sym = (const struct nlist *) vSym;
695
696 return strcmp(key->fSymname, key->fStrbase + sym->n_un.n_strx);
697 }
698
699 static const struct nlist *
700 findSymbolByName(struct fileRecord *file, const char *symname)
701 {
702 struct searchContext context;
703
704 context.fSymname = symname;
705 context.fStrbase = file->fStringBase;
706 return (struct nlist *)
707 bsearch(&context,
708 file->fLocalSyms, file->fNLocal, sizeof(struct nlist),
709 symbolSearch);
710 }
711
712 static Boolean
713 relocateSection(const struct fileRecord *file, struct sectionRecord *sectionRec)
714 {
715 const struct nlist *symbol;
716 const struct section *section;
717 struct relocRecord *rec;
718 struct relocation_info *rinfo;
719 unsigned long i;
720 unsigned long r_address, r_symbolnum, r_length;
721 enum reloc_type_generic r_type;
722 UInt8 *sectionBase;
723 void **entry;
724
725 sectionRec->fRelocCache = DataCreate(
726 sectionRec->fSection->nreloc * sizeof(struct relocRecord));
727 if (!sectionRec->fRelocCache)
728 return false;
729
730 section = sectionRec->fSection;
731 sectionBase = file->fMachO + section->offset;
732
733 rec = (struct relocRecord *) DataGetPtr(sectionRec->fRelocCache);
734 rinfo = (struct relocation_info *) (file->fMachO + section->reloff);
735 for (i = 0; i < section->nreloc; i++, rec++, rinfo++) {
736
737 // Totally uninterested in scattered relocation entries
738 if ( (rinfo->r_address & R_SCATTERED) )
739 continue;
740
741 r_address = rinfo->r_address;
742 entry = (void **) (sectionBase + r_address);
743
744 /*
745 * The r_address field is really an offset into the contents of the
746 * section and must reference something inside the section (Note
747 * that this is not the case for PPC_RELOC_PAIR entries but this
748 * can't be one with the above checks).
749 */
750 return_if(r_address >= section->size, false,
751 ("Invalid relocation entry in %s - not in section\n", file->fPath));
752
753 // If we don't have a VANILLA entry or the Vanilla entry isn't
754 // a 'long' then ignore the entry and try the next.
755 r_type = (enum reloc_type_generic) rinfo->r_type;
756 r_length = rinfo->r_length;
757 if (r_type != GENERIC_RELOC_VANILLA || r_length != 2)
758 continue;
759
760 r_symbolnum = rinfo->r_symbolnum;
761
762 /*
763 * If rinfo->r_extern is set this relocation entry is an external entry
764 * else it is a local entry.
765 */
766 if (rinfo->r_extern) {
767 /*
768 * This is an external relocation entry.
769 * r_symbolnum is an index into the input file's symbol table
770 * of the symbol being refered to. The symbol must be
771 * undefined to be used in an external relocation entry.
772 */
773 return_if(r_symbolnum >= file->fSymtab->nsyms, false,
774 ("Invalid relocation entry in %s - no symbol\n", file->fPath));
775
776 /*
777 * If this is an indirect symbol resolve indirection (all chains
778 * of indirect symbols have been resolved so that they point at
779 * a symbol that is not an indirect symbol).
780 */
781 symbol = file->fSymbolBase;
782 if ((symbol[r_symbolnum].n_type & N_TYPE) == N_INDR)
783 r_symbolnum = symbol[r_symbolnum].n_value;
784 symbol = &symbol[r_symbolnum];
785
786 return_if(symbol->n_type != (N_EXT | N_UNDF), false,
787 ("Invalid relocation entry in %s - extern\n", file->fPath));
788 }
789 else {
790 /*
791 * If the symbol is not in any section then it can't be a
792 * pointer to a local segment and I don't care about it.
793 */
794 if (r_symbolnum == R_ABS)
795 continue;
796
797 // Note segment references are offset by 1 from 0.
798 return_if(r_symbolnum > file->fNSects, false,
799 ("Invalid relocation entry in %s - local\n", file->fPath));
800
801 // Find the symbol, if any, that backs this entry
802 symbol = findSymbolByAddress(file, *entry);
803 }
804
805 rec->fValue = *entry; // Save the previous value
806 rec->fRInfo = rinfo; // Save a pointer to the reloc
807 rec->fSymbol = symbol; // Record the current symbol
808
809 *entry = (void *) rec; // Save pointer to record in object image
810 }
811
812 ((struct fileRecord *) file)->fImageDirty = true;
813
814 return true;
815 }
816
817 static const struct nlist *
818 findSymbolRefAtLocation(const struct fileRecord *file,
819 struct sectionRecord *sctn, void **loc)
820 {
821 if (file->fIsKernel) {
822 if (*loc)
823 return findSymbolByAddress(file, *loc);
824 }
825 else if (sctn->fRelocCache || relocateSection(file, sctn)) {
826 struct relocRecord *reloc = (struct relocRecord *) *loc;
827
828 if (DataContainsAddr(sctn->fRelocCache, reloc))
829 return reloc->fSymbol;
830 }
831
832 return NULL;
833 }
834
835 static Boolean
836 addClass(struct fileRecord *file,
837 struct metaClassRecord *inClass,
838 const char *cname)
839 {
840 struct metaClassRecord *newClass = NULL;
841 struct metaClassRecord **fileClasses = NULL;
842 int len;
843
844 if (!file->fIsKernel) { // @@@ gvdl:
845 DEBUG_LOG(("Adding Class %s\n", cname));
846 }
847
848 if (!file->fClassList) {
849 file->fClassList = DataCreate(0);
850 if (!file->fClassList)
851 return false;
852 }
853
854 do {
855 // Attempt to allocate all necessary resource first
856 len = strlen(cname) + 1
857 + (int) (&((struct metaClassRecord *) 0)->fClassName);
858 newClass = (struct metaClassRecord *) malloc(len);
859 if (!newClass)
860 break;
861
862 if (!DataAddLength(file->fClassList, sizeof(struct metaClassRecord *)))
863 break;
864 fileClasses = (struct metaClassRecord **)
865 (DataGetPtr(file->fClassList) + DataGetLength(file->fClassList));
866
867 // Copy the meta Class structure and string name into newClass
868 // and insert object at end of the file->fClassList and sMergeMetaClasses
869 *newClass = *inClass;
870 strcpy(newClass->fClassName, cname);
871 fileClasses[-1] = newClass;
872
873 return true;
874 } while (0);
875
876 if (fileClasses)
877 DataAddLength(file->fClassList, -sizeof(struct metaClassRecord *));
878
879 if (newClass)
880 free(newClass);
881
882 return false;
883 }
884
885 static struct metaClassRecord *getClass(DataRef classList, const char *cname)
886 {
887 if (classList) {
888 int i, nclass;
889 struct metaClassRecord **classes, *thisClass;
890
891 nclass = DataGetLength(classList) / sizeof(struct metaClassRecord *);
892 classes = (struct metaClassRecord **) DataGetPtr(classList);
893 for (i = 0; i < nclass; i++) {
894 thisClass = classes[i];
895 if (!strcmp(thisClass->fClassName, cname))
896 return thisClass;
897 }
898 }
899
900 return NULL;
901 }
902
903 // Add the class 'cname' to the list of known OSObject based classes
904 // Note 'sym' is the <cname>.superClass symbol.
905 static Boolean
906 recordClass(struct fileRecord *file, const char *cname, const struct nlist *sym)
907 {
908 char *supername = NULL;
909 const char *classname = NULL;
910 struct metaClassRecord newClass;
911 char strbuffer[1024];
912
913 // Only do the work actual work to find the super class if we are
914 // not currently working on the kernel. The kernel is the end
915 // of all superclass chains as by definition the kernel is binary
916 // compatible with itself.
917 if (!file->fIsKernel) {
918 const char *dot;
919 const struct nlist *supersym;
920 const struct section *section;
921 struct sectionRecord *sectionRec;
922 unsigned char sectind = sym->n_sect;
923 const char *superstr;
924 void **location;
925
926 // We can't resolve anything that isn't in a real section
927 // Note that the sectind is starts at one to make room for the
928 // NO_SECT flag but the fNSects field isn't offset so we have a
929 // '>' test. Which means this isn't an OSObject based class
930 if (sectind == NO_SECT || sectind > file->fNSects)
931 return true;
932
933 sectionRec = file->fSections + sectind - 1;
934 section = sectionRec->fSection;
935 location = (void **) ( file->fMachO + section->offset
936 + sym->n_value - section->addr );
937
938 supersym = findSymbolRefAtLocation(file, sectionRec, location);
939 if (!supersym)
940 return true; // No superclass symbol then it isn't an OSObject.
941
942 // Find string in file and skip leading '_' and find last '.'
943 superstr = symbolname(file, supersym) + 1;
944 dot = strrchr(superstr, '.');
945 if (!dot || strcmp(dot, kGMetaSuffix))
946 return true; // Not an OSObject superclass so ignore it.
947
948 supername = (char *) malloc(dot - superstr + 1);
949 strncpy(supername, superstr, dot - superstr);
950 supername[dot - superstr] = '\0';
951 }
952
953 do {
954 break_if(getClass(file->fClassList, cname),
955 ("Duplicate class %s in %s\n", cname, file->fPath));
956
957 snprintf(strbuffer, sizeof(strbuffer), "%s%s", kVTablePrefix, cname);
958 newClass.fVTableSym = findSymbolByName(file, strbuffer);
959 break_if(!newClass.fVTableSym,
960 ("Can't find vtable %s in %s\n", cname, file->fPath));
961
962 newClass.fFile = file;
963 newClass.fSuperName = supername;
964 newClass.fPatchedVTable = NULL;
965
966 // Can't use cname as it may be a stack variable
967 // However the vtable's string has the class name as a suffix
968 // so why don't we use that rather than mallocing a string.
969 classname = symbolname(file, newClass.fVTableSym)
970 + sizeof(kVTablePrefix) - 1;
971 break_if(!addClass(file, &newClass, classname),
972 ("recordClass - no memory?\n"));
973
974 return true;
975 } while (0);
976
977 if (supername)
978 free(supername);
979
980 return false;
981 }
982
983 static Boolean getMetaClassGraph(struct fileRecord *file)
984 {
985 const struct nlist *sym;
986 const char *strbase;
987 int i, nsyms;
988
989 // Search the symbol table for the local symbols that are generated
990 // by the metaclass system. There are three metaclass variables
991 // that are relevant.
992 //
993 // <ClassName>.metaClass A pointer to the meta class structure.
994 // <ClassName>.superClass A pointer to the super class's meta class.
995 // <ClassName>.gMetaClass The meta class structure itself.
996 // ___vt<ClassName> The VTable for the class <ClassName>.
997 //
998 // In this code I'm going to search for any symbols that
999 // ends in kSuperClassSuffix as this indicates this class is a conforming
1000 // OSObject subclass and will need to be patched, and it also
1001 // contains a pointer to the super class's meta class structure.
1002 strbase = file->fStringBase;
1003 sym = file->fLocalSyms;
1004 for (i = 0, nsyms = file->fNLocal; i < nsyms; i++, sym++) {
1005 const char *symname;
1006 const char *dot;
1007 char classname[1024];
1008 unsigned char n_type = sym->n_type & (N_TYPE | N_EXT);
1009
1010 // Check that the symbols is a global and that it has a name.
1011 if (((N_SECT | N_EXT) != n_type && (N_ABS | N_EXT) != n_type)
1012 || !sym->n_un.n_strx)
1013 continue;
1014
1015 // Only search from the last '.' in the symbol.
1016 // but skip the leading '_' in all symbols first.
1017 symname = strbase + sym->n_un.n_strx + 1;
1018 dot = strrchr(symname, '.');
1019 if (!dot || strcmp(dot, kSuperClassSuffix))
1020 continue;
1021
1022 // Got a candidate so hand it over for class processing.
1023 return_if(dot - symname >= (int) sizeof(classname),
1024 false, ("Symbol %s is too long\n", symname));
1025
1026 bcopy(symname, classname, dot - symname);
1027 classname[dot - symname] = '\0';
1028 if (!recordClass(file, classname, sym))
1029 return false;
1030 }
1031
1032 return_if(!file->fClassList, false, ("Internal error, "
1033 "getMetaClassGraph(%s) found no classes", file->fPath));
1034
1035 DEBUG_LOG(("Found %d classes in %x for %s\n",
1036 DataGetLength(file->fClassList)/sizeof(void*),
1037 file->fClassList, file->fPath));
1038
1039 return true;
1040 }
1041
1042 static Boolean mergeOSObjectsForFile(const struct fileRecord *file)
1043 {
1044 int i, nmerged;
1045 Boolean foundDuplicates = false;
1046
1047 DEBUG_LOG(("Merging file %s\n", file->fPath)); // @@@ gvdl:
1048
1049 if (!file->fClassList)
1050 return true;
1051
1052 if (!sMergedFiles) {
1053 sMergedFiles = DataCreate(0);
1054 return_if(!sMergedFiles, false,
1055 ("Unable to allocate memory metaclass list\n", file->fPath));
1056 }
1057
1058 // Check to see if we have already merged this file
1059 nmerged = DataGetLength(sMergedFiles) / sizeof(struct fileRecord *);
1060 for (i = 0; i < nmerged; i++) {
1061 if (file == ((void **) DataGetPtr(sMergedFiles))[i])
1062 return true;
1063 }
1064
1065 if (!sMergeMetaClasses) {
1066 sMergeMetaClasses = DataCreate(0);
1067 return_if(!sMergeMetaClasses, false,
1068 ("Unable to allocate memory metaclass list\n", file->fPath));
1069 }
1070 else { /* perform a duplicate check */
1071 int i, j, cnt1, cnt2;
1072 struct metaClassRecord **list1, **list2;
1073
1074 list1 = (struct metaClassRecord **) DataGetPtr(file->fClassList);
1075 cnt1 = DataGetLength(file->fClassList) / sizeof(*list1);
1076 list2 = (struct metaClassRecord **) DataGetPtr(sMergeMetaClasses);
1077 cnt2 = DataGetLength(sMergeMetaClasses) / sizeof(*list2);
1078
1079 for (i = 0; i < cnt1; i++) {
1080 for (j = 0; j < cnt2; j++) {
1081 if (!strcmp(list1[i]->fClassName, list2[j]->fClassName)) {
1082 errprintf("duplicate class %s in %s & %s\n",
1083 list1[i]->fClassName,
1084 file->fPath, list2[j]->fFile->fPath);
1085 }
1086 }
1087 }
1088 }
1089 if (foundDuplicates)
1090 return false;
1091
1092 return_if(!DataAppendBytes(sMergedFiles, &file, sizeof(file)), false,
1093 ("Unable to allocate memory to merge %s\n", file->fPath));
1094
1095 return_if(!DataAppendData(sMergeMetaClasses, file->fClassList), false,
1096 ("Unable to allocate memory to merge %s\n", file->fPath));
1097
1098 if (file == sKernelFile)
1099 sMergedKernel = true;
1100
1101 return true;
1102 }
1103
1104 // Returns a pointer to the base of the section offset by the sections
1105 // base address. The offset is so that we can add nlist::n_values directly
1106 // to this address and get a valid pointer in our memory.
1107 static unsigned char *
1108 getSectionForSymbol(const struct fileRecord *file, const struct nlist *symb,
1109 void ***endP)
1110 {
1111 const struct section *section;
1112 unsigned char sectind;
1113 unsigned char *base;
1114
1115 sectind = symb->n_sect; // Default to symbols section
1116 if ((symb->n_type & N_TYPE) == N_ABS && file->fIsKernel) {
1117 // Absolute symbol so we have to iterate over our sections
1118 for (sectind = 1; sectind <= file->fNSects; sectind++) {
1119 unsigned long start, end;
1120
1121 section = file->fSections[sectind - 1].fSection;
1122 start = section->addr;
1123 end = start + section->size;
1124 if (start <= symb->n_value && symb->n_value < end) {
1125 // Found the relevant section
1126 break;
1127 }
1128 }
1129 }
1130
1131 // Is the vtable in a valid section?
1132 return_if(sectind == NO_SECT || sectind > file->fNSects,
1133 (unsigned char *) -1,
1134 ("%s isn't a valid kext, bad section reference\n", file->fPath));
1135
1136 section = file->fSections[sectind - 1].fSection;
1137
1138 // for when we start walking the vtable so compute offset's now.
1139 base = file->fMachO + section->offset;
1140 *endP = (void **) (base + section->size);
1141
1142 return base - section->addr; // return with addr offset
1143 }
1144
1145 static Boolean resolveKernelVTable(struct metaClassRecord *metaClass)
1146 {
1147 const struct fileRecord *file;
1148 struct patchRecord *patchedVTable;
1149 void **curEntry, **vtableEntries, **endSection;
1150 unsigned char *sectionBase;
1151 struct patchRecord *curPatch;
1152 int classSize;
1153
1154 // Should never occur but it doesn't cost us anything to check.
1155 if (metaClass->fPatchedVTable)
1156 return true;
1157
1158 DEBUG_LOG(("Kernel vtable %s\n", metaClass->fClassName)); // @@@ gvdl:
1159
1160 // Do we have a valid vtable to patch?
1161 return_if(!metaClass->fVTableSym,
1162 false, ("Internal error - no class vtable symbol?\n"));
1163
1164 file = metaClass->fFile;
1165
1166 // If the metaClass we are being to ask is in the kernel then we
1167 // need to do a quick scan to grab the fPatchList in a reliable format
1168 // however we don't need to check the superclass in the kernel
1169 // as the kernel vtables are always correct wrt themselves.
1170 // Note this ends the superclass chain recursion.
1171 return_if(!file->fIsKernel,
1172 false, ("Internal error - resolveKernelVTable not kernel\n"));
1173
1174 if (file->fNoKernelExecutable) {
1175 // Oh dear attempt to map the kernel's VM into my memory space
1176 return_if(file->fNoKernelExecutable, false,
1177 ("Internal error - fNoKernelExecutable not implemented yet\n"));
1178 }
1179
1180 // We are going to need the base and the end
1181 sectionBase = getSectionForSymbol(file, metaClass->fVTableSym, &endSection);
1182 if (-1 == (long) sectionBase)
1183 return false;
1184
1185 vtableEntries = (void **) (sectionBase + metaClass->fVTableSym->n_value);
1186 curEntry = vtableEntries + kVTablePreambleLen;
1187 for (classSize = 0; curEntry < endSection && *curEntry; classSize++)
1188 curEntry++;
1189
1190 return_if(*curEntry, false, ("Bad kernel image, short section\n"));
1191
1192 patchedVTable = (struct patchRecord *)
1193 malloc((classSize + 1) * sizeof(struct patchRecord));
1194 return_if(!patchedVTable, false, ("resolveKernelVTable - no memory\n"));
1195
1196 // Copy the vtable of this class into the patch table
1197 curPatch = patchedVTable;
1198 curEntry = vtableEntries + kVTablePreambleLen;
1199 for (; *curEntry; curEntry++, curPatch++) {
1200 curPatch->fSymbol = (struct nlist *)
1201 findSymbolByAddress(file, *curEntry);
1202 curPatch->fType = kSymbolLocal;
1203 }
1204
1205 // Tag the end of the patch vtable
1206 curPatch->fSymbol = NULL;
1207 metaClass->fPatchedVTable = patchedVTable;
1208
1209 return true;
1210 }
1211
1212 // reloc->fPatch must contain a valid pointer on entry
1213 static struct nlist *
1214 getNewSymbol(struct fileRecord *file,
1215 const struct relocRecord *reloc, const char *supername)
1216 {
1217 unsigned int size, i, namelen;
1218 struct nlist **sym;
1219 struct nlist *msym;
1220 const char *strbase;
1221 struct relocation_info *rinfo;
1222 long strx;
1223
1224 if (!file->fNewSymbols) {
1225 file->fNewSymbols = DataCreate(0);
1226 return_if(!file->fNewSymbols, NULL,
1227 ("Unable to allocate new symbol table for %s\n", file->fPath));
1228 }
1229
1230 // Make sure we have a string table as well for the new symbol
1231 if (!file->fNewStrings) {
1232 file->fNewStrings = DataCreate(0);
1233 return_if(!file->fNewStrings, NULL,
1234 ("Unable to allocate string table for %s\n", file->fPath));
1235 }
1236
1237 rinfo = (struct relocation_info *) reloc->fRInfo;
1238 size = DataGetLength(file->fNewSymbols) / sizeof(struct nlist *);
1239 sym = (const struct nlist **) DataGetPtr(file->fNewSymbols);
1240 // remember that the n_strx for new symbols names is negated
1241 strbase = (const char *)
1242 DataGetPtr(file->fNewStrings) - file->fSymtab->strsize;
1243 for (i = 0; i < size; i++, sym++) {
1244 const char *symname = strbase - (*sym)->n_un.n_strx;
1245
1246 if (!strcmp(symname, supername)) {
1247 rinfo->r_symbolnum = i + file->fSymtab->nsyms;
1248 file->fSymbolsDirty = true;
1249 return *sym;
1250 }
1251 }
1252
1253 // Assert that this is a vaild symbol. I need this condition to be true
1254 // for the later code to make non-zero. So the first time through I'd
1255 // better make sure that it is 0.
1256 return_if(reloc->fSymbol->n_sect, NULL,
1257 ("Undefined symbol entry with non-zero section %s:%s\n",
1258 file->fPath, symbolname(file, reloc->fSymbol)));
1259
1260 msym = (struct nlist *) malloc(sizeof(struct nlist));
1261 return_if(!msym,
1262 NULL, ("Unable to create symbol table entry for %s\n", file->fPath));
1263
1264 // If we are here we didn't find the symbol so create a new one now
1265 if (!DataAppendBytes(file->fNewSymbols, &msym, sizeof(msym))) {
1266 free(msym);
1267 return_if(true,
1268 NULL, ("Unable to grow symbol table for %s\n", file->fPath));
1269 }
1270
1271 namelen = strlen(supername) + 1;
1272 strx = DataGetLength(file->fNewStrings);
1273 if (!DataAppendBytes(file->fNewStrings, supername, namelen)) {
1274 free(msym);
1275 DataAddLength(file->fNewSymbols, -sizeof(struct nlist)); // Undo harm
1276 return_if(true, NULL,
1277 ("Unable to grow string table for %s\n", file->fPath));
1278 }
1279
1280 // Offset the string index by the original string table size
1281 // and negate the address to indicate that this is a 'new' symbol
1282 msym->n_un.n_strx = -(strx + file->fSymtab->strsize);
1283 msym->n_type = (N_EXT | N_UNDF);
1284 msym->n_sect = NO_SECT;
1285 msym->n_desc = 0;
1286 msym->n_value = 0;
1287
1288 // Mark the old symbol as being potentially deletable I can use the
1289 // n_sect field as the input symbol must be of type N_UNDF which means
1290 // that the n_sect field must be set to NO_SECT otherwise it is an
1291 // in valid input file.
1292 ((struct nlist *) reloc->fSymbol)->n_un.n_strx
1293 = -reloc->fSymbol->n_un.n_strx;
1294 ((struct nlist *) reloc->fSymbol)->n_sect = (unsigned char) -1;
1295
1296 rinfo->r_symbolnum = i + file->fSymtab->nsyms;
1297 file->fSymbolsDirty = true;
1298 return msym;
1299 }
1300
1301 static struct nlist *
1302 fixOldSymbol(struct fileRecord *file,
1303 const struct relocRecord *reloc, const char *supername)
1304 {
1305 unsigned int namelen;
1306 struct nlist *sym = (struct nlist *) reloc->fSymbol;
1307 const char *oldname = symbolname(file, sym);
1308
1309 // assert(sym->n_un.n_strx >= 0);
1310
1311 namelen = strlen(supername);
1312 if (namelen < strlen(oldname)) {
1313 // Overwrite old string in string table
1314 strcpy((char *) oldname, supername);
1315 }
1316 else {
1317 long strx;
1318
1319 // Make sure we have a string table as well for this symbol
1320 if (!file->fNewStrings) {
1321 file->fNewStrings = DataCreate(0);
1322 return_if(!file->fNewStrings, NULL,
1323 ("Unable to allocate string table for %s\n", file->fPath));
1324 }
1325
1326 // Find the end of the fNewStrings data structure;
1327 strx = DataGetLength(file->fNewStrings);
1328 return_if(!DataAppendBytes(file->fNewStrings, supername, namelen + 1),
1329 NULL, ("Unable to grow string table for %s\n", file->fPath));
1330
1331 // now add the current table size to the offset
1332 sym->n_un.n_strx = strx + file->fSymtab->strsize;
1333 }
1334
1335 // Mark the symbol as having been processed by negating it.
1336 // Also note that we have dirtied the file and need to repair the
1337 // symbol table.
1338 sym->n_un.n_strx = -sym->n_un.n_strx;
1339 file->fSymbolsDirty = true;
1340 return sym;
1341 }
1342
1343 static enum patchState
1344 symbolCompare(const struct fileRecord *file,
1345 const struct nlist *classsym,
1346 const char *supername)
1347 {
1348 const char *classname;
1349
1350
1351 // Check to see if the target function is locally defined
1352 // if it is then we can assume this is a local vtable override
1353 if ((classsym->n_type & N_TYPE) != N_UNDF)
1354 return kSymbolLocal;
1355
1356 // Check to see if both symbols point to the same symbol name
1357 // if so then we are still identical.
1358 classname = symbolname(file, classsym);
1359 if (!strcmp(classname, supername))
1360 return kSymbolIdentical;
1361
1362 // Right now we know that the target's vtable entry is different from the
1363 // superclass' vtable entry. This means that we will have to apply a
1364 // patch to the current entry, however before returning lets check to
1365 // see if we have a _RESERVEDnnn field 'cause we can use this as a
1366 // registration point that must align between vtables.
1367 if (!strncmp(supername, kReservedPrefix, sizeof(kReservedPrefix) - 1))
1368 return kSymbolMismatch;
1369
1370 // OK, we have a superclass difference where the superclass doesn't
1371 // reference a pad function so assume that the superclass is correct.
1372 if (!strncmp(classname, kReservedPrefix, sizeof(kReservedPrefix) - 1))
1373 return kSymbolPadUpdate;
1374 else
1375 return kSymbolSuperUpdate;
1376 }
1377
1378 static Boolean patchVTable(struct metaClassRecord *metaClass)
1379 {
1380 struct metaClassRecord *super = NULL;
1381 struct fileRecord *file;
1382 struct patchRecord *patchedVTable;
1383 struct relocRecord **curReloc, **vtableRelocs, **endSection;
1384 unsigned char *sectionBase;
1385 int classSize;
1386
1387 // Should never occur but it doesn't cost us anything to check.
1388 if (metaClass->fPatchedVTable)
1389 return true;
1390
1391 // Do we have a valid vtable to patch?
1392 return_if(!metaClass->fVTableSym,
1393 false, ("Internal error - no class vtable symbol?\n"));
1394
1395 file = metaClass->fFile;
1396
1397 // If the metaClass we are being to ask is in the kernel then we
1398 // need to do a quick scan to grab the fPatchList in a reliable format
1399 // however we don't need to check the superclass in the kernel
1400 // as the kernel vtables are always correct wrt themselves.
1401 // Note this ends the superclass chain recursion.
1402 return_if(file->fIsKernel,
1403 false, ("Internal error - patchVTable shouldn't used for kernel\n"));
1404
1405 if (!metaClass->fSuperName)
1406 return false;
1407
1408 // The class isn't in the kernel so make sure that the super class
1409 // is patched before patching ouselves.
1410 super = getClass(sMergeMetaClasses, metaClass->fSuperName);
1411 return_if(!super, false, ("Can't find superclass for %s : %s \n",
1412 metaClass->fClassName, metaClass->fSuperName));
1413
1414 // Superclass recursion if necessary
1415 if (!super->fPatchedVTable) {
1416 Boolean res;
1417
1418 if (super->fFile->fIsKernel)
1419 res = resolveKernelVTable(super);
1420 else
1421 res = patchVTable(super);
1422 if (!res)
1423 return false;
1424 }
1425
1426 DEBUG_LOG(("Patching %s\n", metaClass->fClassName)); // @@@ gvdl:
1427
1428 // We are going to need the base and the end
1429
1430 sectionBase = getSectionForSymbol(file,
1431 metaClass->fVTableSym, (void ***) &endSection);
1432 if (-1 == (long) sectionBase)
1433 return false;
1434
1435 vtableRelocs = (struct relocRecord **)
1436 (sectionBase + metaClass->fVTableSym->n_value);
1437 curReloc = vtableRelocs + kVTablePreambleLen;
1438 for (classSize = 0; curReloc < endSection && *curReloc; classSize++)
1439 curReloc++;
1440
1441 return_if(*curReloc, false,
1442 ("%s isn't a valid kext, short section\n", file->fPath));
1443
1444 patchedVTable = (struct patchRecord *)
1445 malloc((classSize + 1) * sizeof(struct patchRecord));
1446 return_if(!patchedVTable, false, ("patchedVTable - no memory\n"));
1447
1448 do {
1449 struct patchRecord *curPatch;
1450 struct nlist *symbol;
1451
1452 curPatch = patchedVTable;
1453 curReloc = vtableRelocs + kVTablePreambleLen;
1454
1455 // Grab the super table patches if necessary
1456 // Can't be patching a kernel table as we don't walk super
1457 // class chains in the kernel symbol space.
1458 if (super && super->fPatchedVTable) {
1459 const struct patchRecord *spp;
1460
1461 spp = super->fPatchedVTable;
1462
1463 for ( ; spp->fSymbol; curReloc++, spp++, curPatch++) {
1464 const char *supername =
1465 symbolname(super->fFile, spp->fSymbol);
1466
1467 symbol = (struct nlist *) (*curReloc)->fSymbol;
1468
1469 curPatch->fType = symbolCompare(file, symbol, supername);
1470 switch (curPatch->fType) {
1471 case kSymbolIdentical:
1472 case kSymbolLocal:
1473 break;
1474
1475 case kSymbolSuperUpdate:
1476 symbol = getNewSymbol(file, (*curReloc), supername);
1477 break;
1478
1479 case kSymbolPadUpdate:
1480 symbol = fixOldSymbol(file, (*curReloc), supername);
1481 break;
1482
1483 case kSymbolMismatch:
1484 errprintf("%s is not compatible with its %s superclass, "
1485 "broken superclass?\n",
1486 metaClass->fClassName, super->fClassName);
1487 goto abortPatch;
1488
1489 default:
1490 errprintf("Internal error - unknown patch type\n");
1491 goto abortPatch;
1492 }
1493 if (symbol) {
1494 curPatch->fSymbol = symbol;
1495 (*curReloc)->fSymbol = symbol;
1496 }
1497 else
1498 goto abortPatch;
1499 }
1500 }
1501
1502 // Copy the remainder of this class' vtable into the patch table
1503 for (; *curReloc; curReloc++, curPatch++) {
1504 // Local reloc symbols
1505 curPatch->fType = kSymbolLocal;
1506 curPatch->fSymbol = (struct nlist *) (*curReloc)->fSymbol;
1507 }
1508
1509 // Tag the end of the patch vtable
1510 curPatch->fSymbol = NULL;
1511
1512 metaClass->fPatchedVTable = patchedVTable;
1513 return true;
1514 } while(0);
1515
1516 abortPatch:
1517 if (patchedVTable)
1518 free(patchedVTable);
1519
1520 return false;
1521 }
1522
1523 static Boolean growImage(struct fileRecord *file, vm_size_t delta)
1524 {
1525 #if !KERNEL
1526 file->fMachOSize += delta;
1527 return (file->fMachO + file->fMachOSize <= file->fPadEnd);
1528 #else /* KERNEL */
1529 vm_address_t startMachO, endMachO, endMap;
1530 vm_offset_t newMachO;
1531 vm_size_t newsize;
1532 unsigned long i, nsect, nclass = 0;
1533 struct metaClassRecord **classes = NULL;
1534 struct sectionRecord *section;
1535 kern_return_t ret;
1536
1537 startMachO = (vm_address_t) file->fMachO;
1538 endMachO = startMachO + file->fMachOSize + delta;
1539 endMap = (vm_address_t) file->fMap + file->fMapSize;
1540
1541 // Do we have room in the current mapped image
1542 if (endMachO < round_page(endMap)) {
1543 file->fMachOSize += delta;
1544 return true;
1545 }
1546
1547 newsize = endMachO - startMachO;
1548 if (newsize < round_page(file->fMapSize)) {
1549 // We have room in the map if we shift the macho image within the
1550 // current map. We will have to patch up pointers into the object.
1551 newMachO = (vm_offset_t) file->fMap;
1552 bcopy((char *) startMachO, (char *) newMachO, file->fMachOSize);
1553 }
1554 else if (file->fIsKmem) {
1555 // kmem_alloced mapping so we can try a kmem_realloc
1556 ret = kmem_realloc(kernel_map,
1557 (vm_address_t) file->fMap,
1558 (vm_size_t) file->fMapSize,
1559 &newMachO,
1560 newsize);
1561 if (KERN_SUCCESS != ret)
1562 return false;
1563
1564 // If the mapping didn't move then just return
1565 if ((vm_address_t) file->fMap == newMachO) {
1566 file->fMachOSize = file->fMapSize = newsize;
1567 return true;
1568 }
1569
1570 // We have relocated the kmem image so we are going to have to
1571 // move all of the pointers into the image around.
1572 }
1573 else {
1574 // The image doesn't have room for us and I can't kmem_realloc
1575 // then I just have to bite the bullet and copy the object code
1576 // into a bigger memory segment
1577 ret = kmem_alloc(kernel_map, &newMachO, newsize);
1578
1579 if (KERN_SUCCESS != ret)
1580 return false;
1581 bcopy((char *) startMachO, (void *) newMachO, file->fMachOSize);
1582 file->fIsKmem = true;
1583 }
1584
1585
1586 file->fMap = file->fMachO = (unsigned char *) newMachO;
1587 file->fMapSize = newsize;
1588 file->fMachOSize += delta; // Increment the image size
1589
1590 // If we are here then we have shifted the object image in memory
1591 // I really should change all of my pointers into the image to machO offsets
1592 // but I have run out of time. So I'm going to very quickly go over the
1593 // cached data structures and add adjustments to the addresses that are
1594 // affected. I wonder how long it will take me to get them all.
1595 //
1596 // For every pointer into the MachO I need to add an adjustment satisfying
1597 // the following simultanous equations
1598 // addr_old = macho_old + fixed_offset
1599 // addr_new = macho_new + fixed_offset therefore:
1600 // addr_new = addr_old + (macho_new - macho_old)
1601 #define REBASE(addr, delta) ( ((vm_address_t) (addr)) += (delta) )
1602 delta = newMachO - startMachO;
1603
1604 // Rebase the cached in object 'struct symtab_command' pointer
1605 REBASE(file->fSymtab, delta);
1606
1607 // Rebase the cached in object 'struct nlist' pointer for all symbols
1608 REBASE(file->fSymbolBase, delta);
1609
1610 // Rebase the cached in object 'struct nlist' pointer for local symbols
1611 REBASE(file->fLocalSyms, delta);
1612
1613 // Rebase the cached in object 'char' pointer for the string table
1614 REBASE(file->fStringBase, delta);
1615
1616 // Ok now we have to go over all of the relocs one last time
1617 // to clean up the pad updates which had their string index negated
1618 // to indicate that we have finished with them.
1619 section = file->fSections;
1620 for (i = 0, nsect = file->fNSects; i < nsect; i++, section++)
1621 REBASE(section->fSection, delta);
1622
1623 // We only ever grow images that contain class lists so dont bother
1624 // the check if file->fClassList is non-zero 'cause it can't be
1625 // assert(file->fClassList);
1626 nclass = DataGetLength(file->fClassList)
1627 / sizeof(struct metaClassRecord *);
1628 classes = (struct metaClassRecord **) DataGetPtr(file->fClassList);
1629 for (i = 0; i < nclass; i++) {
1630 struct patchRecord *patch;
1631
1632 for (patch = classes[i]->fPatchedVTable; patch->fSymbol; patch++) {
1633 vm_address_t symAddr = (vm_address_t) patch->fSymbol;
1634 if (symAddr >= startMachO && symAddr < endMachO)
1635 REBASE(patch->fSymbol, delta);
1636 }
1637 }
1638
1639
1640 #undef REBASE
1641
1642 return true;
1643
1644 #endif /* KERNEL */
1645 }
1646
1647 static Boolean
1648 prepareFileForLink(struct fileRecord *file)
1649 {
1650 unsigned long i, last, numnewsyms, newsymsize, newstrsize;
1651 struct sectionRecord *section;
1652 struct nlist **symp, *sym;
1653
1654 // If we didn't even do a pseudo 'relocate' and dirty the image
1655 // then we can just return now.
1656 if (!file->fImageDirty)
1657 return true;
1658
1659 DEBUG_LOG(("Linking 2 %s\n", file->fPath)); // @@@ gvdl:
1660
1661 // We have to go over all of the relocs to repair the damage
1662 // that we have done to the image when we did our 'relocation'
1663 section = file->fSections;
1664 for (i = 0, last = file->fNSects; i < last; i++, section++) {
1665 unsigned char *sectionBase;
1666 struct relocRecord *rec;
1667 unsigned long j, nreloc;
1668
1669 if (section->fRelocCache) {
1670 sectionBase = file->fMachO + section->fSection->offset;
1671 nreloc = section->fSection->nreloc;
1672 rec = (struct relocRecord *) DataGetPtr(section->fRelocCache);
1673
1674 // We will need to repair the reloc list
1675 for (j = 0; j < nreloc; j++, rec++) {
1676 void **entry;
1677 struct nlist *sym;
1678
1679 // Repair Damage to object image
1680 entry = (void **) (sectionBase + rec->fRInfo->r_address);
1681 *entry = rec->fValue;
1682
1683 // Check if the symbol that this relocation entry points
1684 // to is marked as erasable
1685 sym = (struct nlist *) rec->fSymbol;
1686 if (sym && sym->n_type == (N_EXT | N_UNDF)
1687 && sym->n_sect == (unsigned char) -1) {
1688 // clear mark now
1689 sym->n_un.n_strx = -sym->n_un.n_strx;
1690 sym->n_sect = NO_SECT;
1691 }
1692 }
1693
1694 // Clean up the fRelocCache we don't need it any more.
1695 DataRelease(section->fRelocCache);
1696 section->fRelocCache = 0;
1697 }
1698 }
1699 file->fImageDirty = false; // Image is clean
1700
1701 // If we didn't dirty the symbol table then just return
1702 if (!file->fSymbolsDirty)
1703 return true;
1704
1705 // calculate total file size increase and check against padding
1706 numnewsyms = (file->fNewSymbols)? DataGetLength(file->fNewSymbols) : 0;
1707 numnewsyms /= sizeof(struct nlist *);
1708 newsymsize = numnewsyms * sizeof(struct nlist);
1709 newstrsize = (file->fNewStrings)? DataGetLength(file->fNewStrings) : 0;
1710 newstrsize = (newstrsize + 3) & ~3; // Round to nearest word
1711
1712 return_if(!growImage(file, newsymsize + newstrsize),
1713 false, ("Unable to patch the extension, no memory\n", file->fPath));
1714
1715 // Push out the new symbol table if necessary
1716 if (numnewsyms) {
1717 caddr_t base;
1718
1719 // Move the string table out of the way of the grown symbol table
1720 // Don't forget the '\0' from end of string table.
1721 base = (caddr_t) file->fStringBase;
1722 bcopy(base, base + newsymsize, file->fSymtab->strsize);
1723 file->fStringBase += newsymsize;
1724 file->fSymtab->stroff += newsymsize;
1725
1726 // Now append the new symbols to the symbol table.
1727 base = (caddr_t) file->fSymbolBase
1728 + file->fSymtab->nsyms * sizeof(struct nlist);
1729 symp = (struct nlist **) DataGetPtr(file->fNewSymbols);
1730 for (i = 0; i < numnewsyms; i++, base += sizeof(struct nlist), symp++)
1731 bcopy(*symp, base, sizeof(struct nlist));
1732 file->fSymtab->nsyms += numnewsyms;
1733
1734 DataRelease(file->fNewSymbols);
1735 file->fNewSymbols = 0;
1736 }
1737
1738 // Push out the new string table if necessary
1739 if (newstrsize) {
1740 caddr_t base = (caddr_t) file->fStringBase + file->fSymtab->strsize;
1741 unsigned long actuallen = DataGetLength(file->fNewStrings);
1742
1743 // Set the last word in string table to zero before copying data
1744 *((unsigned long *) ((char *) base + newstrsize - 4)) = 0;
1745
1746 // Now append the new strings to the end of the file
1747 bcopy((caddr_t) DataGetPtr(file->fNewStrings), base, actuallen);
1748
1749 file->fSymtab->strsize += newstrsize;
1750
1751 DataRelease(file->fNewStrings);
1752 file->fNewStrings = 0;
1753 }
1754
1755 // Repair the symbol table string index values
1756 // I used negative strx's to indicate symbol has been processed
1757 sym = file->fSymbolBase;
1758 for (i = 0, last = file->fSymtab->nsyms; i < last; i++, sym++) {
1759 if (sym->n_un.n_strx < 0) {
1760 if ( sym->n_type != (N_EXT | N_UNDF)
1761 || (unsigned char) -1 != sym->n_sect)
1762 sym->n_un.n_strx = -sym->n_un.n_strx;
1763 else {
1764 // This symbol isn't being used by any vtable's reloc so
1765 // convert it into an N_ABS style of symbol, remove the
1766 // external bit and null out the symbol name.
1767 bzero(sym, sizeof(*sym));
1768 sym->n_type = N_ABS; /* type flag, see below */
1769 }
1770 }
1771 }
1772 file->fSymbolsDirty = false;
1773
1774 return true;
1775 }
1776
1777 Boolean
1778 #if KERNEL
1779 kld_file_map(const char *pathName,
1780 unsigned char *map,
1781 size_t mapSize,
1782 Boolean isKmem)
1783 #else
1784 kld_file_map(const char *pathName)
1785 #endif /* KERNEL */
1786 {
1787 struct fileRecord file, *fp = 0;
1788
1789 // Already done no need to repeat
1790 fp = getFile(pathName);
1791 if (fp)
1792 return true;
1793
1794 bzero(&file, sizeof(file));
1795 file.fPath = pathName;
1796
1797 #if KERNEL
1798 file.fMap = map;
1799 file.fMapSize = mapSize;
1800 file.fIsKmem = isKmem;
1801 #else
1802 if (!mapObjectFile(&file))
1803 return false;
1804 #endif /* KERNEL */
1805
1806 do {
1807 const struct machOMapping {
1808 struct mach_header h;
1809 struct load_command c[1];
1810 } *machO;
1811 const struct load_command *cmd;
1812 const struct nlist *sym;
1813 unsigned int i, firstlocal, nsyms;
1814 unsigned long strsize;
1815 const char *strbase;
1816 Boolean foundOSObject;
1817
1818 if (!findBestArch(&file))
1819 break;
1820
1821 machO = (const struct machOMapping *) file.fMachO;
1822 if (file.fMachOSize < machO->h.sizeofcmds)
1823 break;
1824
1825 // If the file type is MH_EXECUTE then this must be a kernel
1826 // as all Kernel extensions must be of type MH_OBJECT
1827 for (i = 0, cmd = &machO->c[0]; i < machO->h.ncmds; i++) {
1828 if (cmd->cmd == LC_SEGMENT) {
1829 return_if(!parseSegments(&file, (struct segment_command *) cmd),
1830 false, ("%s isn't a valid mach-o, bad segment\n",
1831 file.fPath));
1832 }
1833 else if (cmd->cmd == LC_SYMTAB)
1834 file.fSymtab = (struct symtab_command *) cmd;
1835
1836 cmd = (struct load_command *) ((UInt8 *) cmd + cmd->cmdsize);
1837 }
1838 break_if(!file.fSymtab,
1839 ("%s isn't a valid mach-o, no symbols\n", file.fPath));
1840
1841 // we found a link edit segment so recompute the bases
1842 if (file.fSymbolBase) {
1843 struct segment_command *link =
1844 (struct segment_command *) file.fSymbolBase;
1845
1846 file.fSymbolBase = (struct nlist *)
1847 (link->vmaddr + (file.fSymtab->symoff - link->fileoff));
1848 file.fStringBase = (char *)
1849 (link->vmaddr + (file.fSymtab->stroff - link->fileoff));
1850 break_if( ( (caddr_t) file.fStringBase + file.fSymtab->strsize
1851 > (caddr_t) link->vmaddr + link->vmsize ),
1852 ("%s isn't a valid mach-o le, bad symbols\n", file.fPath));
1853 }
1854 else {
1855 file.fSymbolBase = (struct nlist *)
1856 (file.fMachO + file.fSymtab->symoff);
1857 file.fStringBase = (char *)
1858 (file.fMachO + file.fSymtab->stroff);
1859 break_if( ( file.fSymtab->stroff + file.fSymtab->strsize
1860 > file.fMachOSize ),
1861 ("%s isn't a valid mach-o, bad symbols\n", file.fPath));
1862 }
1863
1864 // If this file the kernel and do we have an executable image
1865 file.fIsKernel = (MH_EXECUTE == machO->h.filetype);
1866 file.fNoKernelExecutable = (vm_page_size == file.fSymtab->symoff)
1867 && (file.fSections[0].fSection->size == 0);
1868
1869 // Search for the first non-stab symbol in table
1870 strsize = file.fSymtab->strsize;
1871 strbase = file.fStringBase;
1872 sym = file.fSymbolBase;
1873 firstlocal = 0;
1874 foundOSObject = false;
1875 for (i = 0, nsyms = file.fSymtab->nsyms; i < nsyms; i++, sym++) {
1876 if ((unsigned long) sym->n_un.n_strx > strsize)
1877 break;
1878
1879 // Find the first exported symbol
1880 if ( !file.fLocalSyms && (sym->n_type & N_EXT) ) {
1881 file.fLocalSyms = sym;
1882 firstlocal = i;
1883 }
1884
1885 // Find the a OSObject based subclass by searching for symbols
1886 // that have a suffix of '.superClass'
1887 if (!foundOSObject
1888 && ((sym->n_type & (N_TYPE | N_EXT)) == (N_SECT | N_EXT)
1889 || (sym->n_type & (N_TYPE | N_EXT)) == (N_ABS | N_EXT))
1890 && sym->n_un.n_strx) {
1891 const char *dot;
1892
1893 // Only search from the last '.' in the symbol.
1894 // but skip the leading '_' in all symbols first.
1895 dot = strrchr(strbase + sym->n_un.n_strx + 1, '.');
1896 if (dot && !strcmp(dot, kSuperClassSuffix))
1897 foundOSObject = true;
1898 }
1899
1900 // Find the last local symbol
1901 if ( !file.fNLocal && sym->n_type == (N_EXT | N_UNDF) )
1902 file.fNLocal = i - firstlocal;
1903
1904 }
1905 break_if(i < nsyms,
1906 ("%s isn't a valid mach-o, bad symbol strings\n", file.fPath));
1907
1908 break_if(!file.fLocalSyms, ("%s has no symbols?\n", file.fPath));
1909
1910 // If we don't have any undefined symbols then all symbols
1911 // must be local so just compute it now if necessary.
1912 if ( !file.fNLocal )
1913 file.fNLocal = i - firstlocal;
1914
1915 fp = addFile(&file);
1916 if (!fp)
1917 break;
1918
1919 if (foundOSObject && !getMetaClassGraph(fp))
1920 break;
1921
1922 if (file.fIsKernel)
1923 sKernelFile = fp;
1924 #if KERNEL
1925 if (!sKernelFile) {
1926 extern struct mach_header _mh_execute_header;
1927 extern struct segment_command *getsegbyname(char *seg_name);
1928
1929 struct segment_command *sg;
1930 size_t kernelSize;
1931 Boolean ret;
1932
1933 sg = (struct segment_command *) getsegbyname(kLinkEditSegName);
1934 break_if(!sg, ("Can't find kernel link edit segment\n"));
1935
1936 kernelSize = sg->vmaddr + sg->vmsize - (size_t) &_mh_execute_header;
1937 ret = kld_file_map(kld_basefile_name,
1938 (unsigned char *) &_mh_execute_header, kernelSize,
1939 /* isKmem */ false);
1940 break_if(!ret, ("kld can't map kernel file"));
1941 }
1942 #endif /* KERNEL */
1943
1944 return true;
1945 } while(0);
1946
1947 removeFile(&file);
1948
1949 return false;
1950 }
1951
1952 void *kld_file_getaddr(const char *pathName, long *size)
1953 {
1954 struct fileRecord *file = getFile(pathName);
1955
1956 if (!file)
1957 return 0;
1958
1959 if (size)
1960 *size = file->fMachOSize;
1961
1962 return file->fMachO;
1963 }
1964
1965 void *kld_file_lookupsymbol(const char *pathName, const char *symname)
1966 {
1967 struct fileRecord *file = getFile(pathName);
1968 const struct nlist *sym;
1969 const struct section *section;
1970 unsigned char *sectionBase;
1971 unsigned char sectind;
1972
1973 return_if(!file,
1974 NULL, ("Unknown file %s\n", pathName));
1975
1976 sym = findSymbolByName(file, symname);
1977
1978 // May be a non-extern symbol so look for it there
1979 if (!sym) {
1980 const char *strbase;
1981 unsigned int i, nsyms;
1982
1983 sym = file->fSymbolBase;
1984 strbase = file->fStringBase;
1985 for (i = 0, nsyms = file->fSymtab->nsyms; i < nsyms; i++, sym++) {
1986 if ( (sym->n_type & N_EXT) ) {
1987 sym = 0;
1988 break; // Terminate search when we hit an extern
1989 }
1990 if ( (sym->n_type & N_STAB) )
1991 continue;
1992 if ( !strcmp(symname, strbase + sym->n_un.n_strx) )
1993 break;
1994 }
1995 }
1996
1997 return_if(!sym,
1998 NULL, ("Unknown symbol %s in %s\n", symname, pathName));
1999
2000 // Is the vtable in a valid section?
2001 sectind = sym->n_sect;
2002 return_if(sectind == NO_SECT || sectind > file->fNSects, NULL,
2003 ("Malformed object file, invalid section reference for %s in %s\n",
2004 symname, pathName));
2005
2006 section = file->fSections[sectind - 1].fSection;
2007 sectionBase = file->fMachO + section->offset - section->addr;
2008
2009 return (void *) (sectionBase + sym->n_value);
2010 }
2011
2012 Boolean kld_file_merge_OSObjects(const char *pathName)
2013 {
2014 struct fileRecord *file = getFile(pathName);
2015
2016 return_if(!file,
2017 false, ("Internal error - unable to find file %s\n", pathName));
2018
2019 return mergeOSObjectsForFile(file);
2020 }
2021
2022 Boolean kld_file_patch_OSObjects(const char *pathName)
2023 {
2024 struct fileRecord *file = getFile(pathName);
2025 struct metaClassRecord **classes;
2026 unsigned long i, last;
2027
2028 return_if(!file,
2029 false, ("Internal error - unable to find file %s\n", pathName));
2030
2031 DEBUG_LOG(("Patch file %s\n", pathName)); // @@@ gvdl:
2032
2033 // If we don't have any classes we can return now.
2034 if (!file->fClassList)
2035 return true;
2036
2037 // If we haven't alread merged the kernel then do it now
2038 if (!sMergedKernel && sKernelFile)
2039 mergeOSObjectsForFile(sKernelFile);
2040 return_if(!sMergedKernel, false, ("Internal error no kernel?\n"));
2041
2042 if (!mergeOSObjectsForFile(file))
2043 return false;
2044
2045 // Patch all of the classes in this executable
2046 last = DataGetLength(file->fClassList) / sizeof(void *);
2047 classes = (struct metaClassRecord **) DataGetPtr(file->fClassList);
2048 for (i = 0; i < last; i++) {
2049 if (!patchVTable(classes[i]))
2050 return false;
2051 }
2052
2053 return true;
2054 }
2055
2056 Boolean kld_file_prepare_for_link()
2057 {
2058 if (sMergedFiles) {
2059 unsigned long i, nmerged = 0;
2060 struct fileRecord **files;
2061
2062 // Check to see if we have already merged this file
2063 nmerged = DataGetLength(sMergedFiles) / sizeof(struct fileRecord *);
2064 files = (struct fileRecord **) DataGetPtr(sMergedFiles);
2065 for (i = 0; i < nmerged; i++) {
2066 if (!prepareFileForLink(files[i]))
2067 return false;
2068 }
2069 }
2070
2071 // Clear down the meta class table and merged file lists
2072 DataRelease(sMergeMetaClasses);
2073 DataRelease(sMergedFiles);
2074 sMergedFiles = sMergeMetaClasses = NULL;
2075 sMergedKernel = false;
2076
2077 return true;
2078 }
2079
2080 void kld_file_cleanup_all_resources()
2081 {
2082 unsigned long i, nfiles;
2083
2084 #if KERNEL // @@@ gvdl:
2085 // Debugger("kld_file_cleanup_all_resources");
2086 #endif
2087
2088 if (!sFilesTable || !(nfiles = DataGetLength(sFilesTable)))
2089 return; // Nothing to do just return now
2090
2091 nfiles /= sizeof(struct fileRecord *);
2092 for (i = 0; i < nfiles; i++)
2093 removeFile(((void **) DataGetPtr(sFilesTable))[i]);
2094
2095 // Don't really have to clean up anything more as the whole
2096 // malloc engine is going to be released and I couldn't be bothered.
2097 }
2098
2099 #if !KERNEL
2100 Boolean kld_file_debug_dump(const char *pathName, const char *outName)
2101 {
2102 const struct fileRecord *file = getFile(pathName);
2103 int fd;
2104 Boolean ret = false;
2105
2106 return_if(!file, false, ("Unknown file %s for dumping\n", pathName));
2107
2108 fd = open(outName, O_WRONLY|O_CREAT|O_TRUNC, 0666);
2109 return_if(-1 == fd, false, ("Can't create output file %s - %s(%d)\n",
2110 outName, strerror(errno), errno));
2111
2112 do {
2113 break_if(-1 == write(fd, file->fMachO, file->fMachOSize),
2114 ("Can't dump output file %s - %s(%d)\n",
2115 outName, strerror(errno), errno));
2116 ret = true;
2117 } while(0);
2118
2119 close(fd);
2120
2121 return ret;
2122 }
2123 #endif /* !KERNEL */
2124