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