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