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