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