2 * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 * 2001-05-30 gvdl Initial implementation of the vtable patcher.
29 // 45678901234567890123456789012345678901234567890123456789012345678901234567890
31 #include <mach-o/fat.h>
32 #include <mach-o/loader.h>
33 #include <mach-o/nlist.h>
34 #include <mach-o/reloc.h>
41 #include <sys/systm.h>
43 #include <libkern/OSTypes.h>
45 #include <libsa/stdlib.h>
46 #include <libsa/mach/mach.h>
48 #include "mach_loader.h"
50 #include <vm/vm_kern.h>
52 enum { false = 0, true = 1 };
54 #define vm_page_size page_size
56 extern load_return_t
fatfile_getarch(
57 void * vp
, // normally a (struct vnode *)
59 struct fat_arch
* archret
);
61 __private_extern__
char *strstr(const char *in
, const char *str
);
71 #include <sys/errno.h>
72 #include <sys/fcntl.h>
77 #include <mach/mach.h>
78 #include <mach/mach_error.h>
80 #include <mach-o/arch.h>
82 #include <CoreFoundation/CoreFoundation.h>
84 #define PAGE_SIZE vm_page_size
85 #define PAGE_MASK (PAGE_SIZE - 1)
89 #include "kld_patch.h"
93 #define DIE() do { for (;;) ; } while(0)
96 # define LOG_DELAY() /* IODelay(200000) */
97 # define DEBUG_LOG(x) do { IOLog x; LOG_DELAY(); } while(0)
100 # define DEBUG_LOG(x) do { printf x; } while(0)
111 // OSObject symbol prefixes and suffixes
112 #define kCPPSymbolPrefix "_Z"
113 #define kVTablePrefix "_" kCPPSymbolPrefix "TV"
114 #define kOSObjPrefix "_" kCPPSymbolPrefix "N"
115 #define kReservedNamePrefix "_RESERVED"
116 #define k29SuperClassSuffix "superClass"
117 #define k31SuperClassSuffix "10superClassE"
118 #define kGMetaSuffix "10gMetaClassE"
119 #define kLinkEditSegName SEG_LINKEDIT
121 // GCC 2.95 drops 2 leading constants in the vtable
122 #define kVTablePreambleLen 2
124 // Last address that I'm willing to try find vm in
125 #define kTopAddr ((unsigned char *) (1024 * 1024 * 1024))
127 // Size in bytes that Data Ref object's get increased in size
128 // Must be a power of 2
129 #define kDataCapacityIncrement 128
131 // My usual set of helper macros. I personally find these macros
132 // easier to read in the code rather than an explicit error condition
133 // check. If I don't make it easy then I may get lazy ond not check
134 // everything. I'm sorry if you find this code harder to read.
136 // break_if will evaluate the expression and if it is true
137 // then it will print the msg, which is enclosed in parens
138 // and then break. Usually used in loops are do { } while (0)
139 #define break_if(expr, msg) \
145 // return_if will evaluate expr and if true it will log the
146 // msg, which is enclosed in parens, and then it will return
147 // with the return code of ret.
148 #define return_if(expr, ret, msg) do { \
156 #define MIN(a,b) (((a)<(b))?(a):(b))
159 #define MAX(a,b) (((a)>(b))?(a):(b))
162 typedef struct Data
{
163 unsigned long fLength
, fCapacity
;
164 unsigned char *fData
;
167 struct sectionRecord
{
168 const struct section
*fSection
;
181 struct nlist
*fSymbol
;
182 enum patchState fType
;
187 const struct nlist
*fSymbol
;
188 struct relocation_info
*fRInfo
;
192 struct metaClassRecord
{
194 struct fileRecord
*fFile
;
195 const struct nlist
*fVTableSym
;
196 struct patchRecord
*fPatchedVTable
;
201 size_t fMapSize
, fMachOSize
;
202 unsigned char *fMap
, *fMachO
, *fPadEnd
;
205 DataRef fNewSymbols
, fNewStringBlocks
;
206 DataRef fSym2Strings
;
207 struct symtab_command
*fSymtab
;
208 struct sectionRecord
*fSections
;
209 struct segment_command
*fLinkEditSeg
;
210 const char **fSymbToStringTable
;
212 struct nlist
*fSymbolBase
;
213 const struct nlist
*fLocalSyms
;
214 unsigned int fNSects
;
216 Boolean fIsKernel
, fNoKernelExecutable
, fIsKmem
;
217 Boolean fImageDirty
, fSymbolsDirty
;
218 Boolean fRemangled
, fFoundOSObject
;
223 static DataRef sFilesTable
;
224 static struct fileRecord
*sKernelFile
;
226 static DataRef sMergedFiles
;
227 static DataRef sMergeMetaClasses
;
228 static Boolean sMergedKernel
;
230 static void errprintf(const char *fmt
, ...)
232 extern void kld_error_vprintf(const char *format
, va_list ap
);
237 kld_error_vprintf(fmt
, ap
);
243 static __inline__
unsigned long DataGetLength(DataRef data
)
245 return data
->fLength
;
248 static __inline__
unsigned char *DataGetPtr(DataRef data
)
253 static __inline__
unsigned char *DataGetEndPtr(DataRef data
)
255 return data
->fData
+ data
->fLength
;
258 static __inline__
unsigned long DataRemaining(DataRef data
)
260 return data
->fCapacity
- data
->fLength
;
263 static __inline__ Boolean
DataContainsAddr(DataRef data
, void *vAddr
)
265 vm_offset_t offset
= (vm_address_t
) vAddr
;
270 offset
= (vm_address_t
) vAddr
- (vm_address_t
) data
->fData
;
271 return (offset
< data
->fLength
);
274 static Boolean
DataEnsureCapacity(DataRef data
, unsigned long capacity
)
276 // Don't bother to ever shrink a data object.
277 if (capacity
> data
->fCapacity
) {
278 unsigned char *newData
;
280 capacity
+= kDataCapacityIncrement
- 1;
281 capacity
&= ~(kDataCapacityIncrement
- 1);
282 newData
= (unsigned char *) realloc(data
->fData
, capacity
);
286 bzero(newData
+ data
->fCapacity
, capacity
- data
->fCapacity
);
287 data
->fData
= newData
;
288 data
->fCapacity
= capacity
;
294 static __inline__ Boolean
DataSetLength(DataRef data
, unsigned long length
)
296 if (DataEnsureCapacity(data
, length
)) {
297 data
->fLength
= length
;
304 static __inline__ Boolean
DataAddLength(DataRef data
, unsigned long length
)
306 return DataSetLength(data
, data
->fLength
+ length
);
309 static __inline__ Boolean
310 DataAppendBytes(DataRef data
, const void *addr
, unsigned int len
)
312 unsigned long size
= DataGetLength(data
);
314 if (!DataAddLength(data
, len
))
317 bcopy(addr
, DataGetPtr(data
) + size
, len
);
321 static __inline__ Boolean
DataAppendData(DataRef dst
, DataRef src
)
323 return DataAppendBytes(dst
, DataGetPtr(src
), DataGetLength(src
));
326 static DataRef
DataCreate(unsigned long capacity
)
328 DataRef data
= (DataRef
) malloc(sizeof(Data
));
332 data
->fCapacity
= kDataCapacityIncrement
;
334 data
->fCapacity
= capacity
+ kDataCapacityIncrement
- 1;
335 data
->fCapacity
&= ~(kDataCapacityIncrement
- 1);
338 data
->fData
= (unsigned char *) malloc(data
->fCapacity
);
344 bzero(data
->fData
, data
->fCapacity
);
350 static void DataRelease(DataRef data
)
360 static __inline__
const char *
361 symNameByIndex(const struct fileRecord
*file
, unsigned int symInd
)
363 return file
->fSymbToStringTable
[symInd
];
366 static __inline__
const char *
367 symbolname(const struct fileRecord
*file
, const struct nlist
*sym
)
371 index
= sym
- file
->fSymbolBase
;
372 if (index
< file
->fSymtab
->nsyms
)
373 return symNameByIndex(file
, index
);
375 if (-1 == sym
->n_un
.n_strx
)
376 return (const char *) sym
->n_value
;
378 // If the preceding tests fail then we have a getNewSymbol patch and
379 // the file it refers to has already been patched as the n_strx is set
380 // to -1 temporarily while we are still processing a file.
381 // Once we have finished with a file then we repair the 'strx' offset
382 // to be valid for the repaired file's string table.
383 return file
->fStringBase
+ sym
->n_un
.n_strx
;
386 static struct fileRecord
*
387 getFile(const char *path
)
391 struct fileRecord
**files
;
393 // Check to see if we have already merged this file
394 nfiles
= DataGetLength(sFilesTable
) / sizeof(struct fileRecord
*);
395 files
= (struct fileRecord
**) DataGetPtr(sFilesTable
);
396 for (i
= 0; i
< nfiles
; i
++) {
397 if (!strcmp(path
, files
[i
]->fPath
))
405 static struct fileRecord
*
406 addFile(struct fileRecord
*file
, const char *path
)
408 struct fileRecord
*newFile
;
411 sFilesTable
= DataCreate(0);
416 newFile
= (struct fileRecord
*)
417 malloc(sizeof(struct fileRecord
) + strlen(path
));
421 if (!DataAppendBytes(sFilesTable
, &newFile
, sizeof(newFile
))) {
426 bcopy(file
, newFile
, sizeof(struct fileRecord
) - 1);
427 strcpy((char *) newFile
->fPath
, path
);
432 // @@@ gvdl: need to clean up the sMergeMetaClasses
433 // @@@ gvdl: I had better fix the object file up again
434 static void unmapFile(struct fileRecord
*file
)
436 if (file
->fSectData
) {
437 struct sectionRecord
*section
;
438 unsigned int i
, nsect
;
440 nsect
= file
->fNSects
;
441 section
= file
->fSections
;
442 for (i
= 0; i
< nsect
; i
++, section
++) {
443 if (section
->fRelocCache
) {
444 DataRelease(section
->fRelocCache
);
445 section
->fRelocCache
= 0;
449 DataRelease(file
->fSectData
);
455 if (file
->fSym2Strings
) {
456 DataRelease(file
->fSym2Strings
);
457 file
->fSym2Strings
= 0;
463 kmem_free(kernel_map
, (vm_address_t
) file
->fMap
, file
->fMapSize
);
469 padVM
= round_page((vm_address_t
) file
->fMap
+ file
->fMapSize
);
470 padSize
= (vm_size_t
) ((vm_address_t
) file
->fPadEnd
- padVM
);
471 (void) vm_deallocate(mach_task_self(), padVM
, padSize
);
475 (void) munmap((caddr_t
) file
->fMap
, file
->fMapSize
);
481 static void removeFile(struct fileRecord
*file
)
483 if (file
->fClassList
) {
484 DataRelease(file
->fClassList
);
485 file
->fClassList
= 0;
495 mapObjectFile(struct fileRecord
*file
, const char *pathName
)
497 Boolean result
= false;
498 static unsigned char *sFileMapBaseAddr
= 0;
502 if (!sFileMapBaseAddr
) {
504 vm_address_t probeAddr
;
506 // If we don't already have a base addr find any random chunk
507 // of 32 meg of VM and to use the 16 meg boundrary as a base.
508 ret
= vm_allocate(mach_task_self(), &probeAddr
,
509 32 * 1024 * 1024, VM_FLAGS_ANYWHERE
);
510 return_if(KERN_SUCCESS
!= ret
, false,
511 ("Unable to allocate base memory %s\n", mach_error_string(ret
)));
512 (void) vm_deallocate(mach_task_self(), probeAddr
, 32 * 1024 * 1024);
514 // Now round to the next 16 Meg boundrary
515 probeAddr
= (probeAddr
+ (16 * 1024 * 1024 - 1))
516 & ~(16 * 1024 * 1024 - 1);
517 sFileMapBaseAddr
= (unsigned char *) probeAddr
;
520 fd
= open(pathName
, O_RDONLY
, 0);
521 return_if(fd
== -1, false, ("Can't open %s for reading - %s\n",
522 pathName
, strerror(errno
)));
529 break_if(fstat(fd
, &sb
) == -1,
530 ("Can't stat %s - %s\n", file
->fPath
, strerror(errno
)));
532 file
->fMapSize
= sb
.st_size
;
533 file
->fMap
= sFileMapBaseAddr
;
535 while (file
->fMap
< kTopAddr
) {
537 vm_address_t padVMEnd
;
540 padVM
= round_page((vm_address_t
) file
->fMap
+ file
->fMapSize
);
541 retaddr
= (int) mmap(file
->fMap
, file
->fMapSize
,
542 PROT_READ
|PROT_WRITE
,
543 MAP_FIXED
|MAP_FILE
|MAP_PRIVATE
,
546 break_if(ENOMEM
!= errno
,
547 ("mmap failed %d - %s\n", errno
, strerror(errno
)));
549 file
->fMap
= (unsigned char *) padVM
;
554 // Round up padVM to the next page after the file and assign at
555 // least another fMapSize more room rounded up to the next page
557 padVMEnd
= round_page(padVM
+ file
->fMapSize
);
558 padSize
= padVMEnd
- padVM
;
560 mach_task_self(), &padVM
, padSize
, VM_FLAGS_FIXED
);
561 if (KERN_SUCCESS
== ret
) {
562 file
->fPadEnd
= (unsigned char *) padVMEnd
;
566 munmap(file
->fMap
, file
->fMapSize
);
567 break_if(KERN_INVALID_ADDRESS
!= ret
,
568 ("Unable to allocate pad vm for %s - %s\n",
569 pathName
, mach_error_string(ret
)));
571 file
->fMap
= (unsigned char *) padVMEnd
;
572 continue; // try again wherever the vm system wants
576 if (-1 == retaddr
|| KERN_SUCCESS
!= ret
)
579 break_if(file
->fMap
>= kTopAddr
,
580 ("Unable to map memory %s\n", file
->fPath
));
582 sFileMapBaseAddr
= file
->fPadEnd
;
591 static Boolean
findBestArch(struct fileRecord
*file
, const char *pathName
)
594 struct fat_header
*fat
;
597 file
->fMachOSize
= file
->fMapSize
;
598 file
->fMachO
= file
->fMap
;
599 magic
= ((const struct mach_header
*) file
->fMachO
)->magic
;
600 fat
= (struct fat_header
*) file
->fMachO
;
602 // Try to figure out what type of file this is
603 return_if(file
->fMapSize
< sizeof(unsigned long), false,
604 ("%s isn't a valid object file - no magic\n", pathName
));
608 // CIGAM is byte-swapped MAGIC
609 if (magic
== FAT_MAGIC
|| magic
== FAT_CIGAM
) {
611 load_return_t load_return
;
612 struct fat_arch fatinfo
;
614 load_return
= fatfile_getarch(NULL
, (vm_address_t
) fat
, &fatinfo
);
615 return_if(load_return
!= LOAD_SUCCESS
, false,
616 ("Extension \"%s\": has no code for this computer\n", pathName
));
618 file
->fMachO
= file
->fMap
+ fatinfo
.offset
;
619 file
->fMachOSize
= fatinfo
.size
;
620 magic
= ((const struct mach_header
*) file
->fMachO
)->magic
;
625 // Do we need to in-place swap the endianness of the fat header?
626 if (magic
== FAT_CIGAM
) {
628 struct fat_arch
*arch
;
630 fat
->nfat_arch
= NXSwapBigLongToHost(fat
->nfat_arch
);
631 return_if(file
->fMapSize
< sizeof(struct fat_header
)
632 + fat
->nfat_arch
* sizeof(struct fat_arch
),
633 false, ("%s is too fat\n", file
->fPath
));
635 arch
= (struct fat_arch
*) &fat
[1];
636 for (i
= 0; i
< fat
->nfat_arch
; i
++) {
637 arch
[i
].cputype
= NXSwapBigLongToHost(arch
[i
].cputype
);
638 arch
[i
].cpusubtype
= NXSwapBigLongToHost(arch
[i
].cpusubtype
);
639 arch
[i
].offset
= NXSwapBigLongToHost(arch
[i
].offset
);
640 arch
[i
].size
= NXSwapBigLongToHost(arch
[i
].size
);
641 arch
[i
].align
= NXSwapBigLongToHost(arch
[i
].align
);
644 magic
= NXSwapBigLongToHost(fat
->magic
);
647 // Now see if we can find any valid architectures
648 if (magic
== FAT_MAGIC
) {
649 const NXArchInfo
*myArch
;
650 unsigned long fatsize
;
651 struct fat_arch
*arch
;
653 fatsize
= sizeof(struct fat_header
)
654 + fat
->nfat_arch
* sizeof(struct fat_arch
);
655 return_if(file
->fMapSize
< fatsize
,
656 false, ("%s isn't a valid fat file\n", pathName
));
658 myArch
= NXGetLocalArchInfo();
659 arch
= NXFindBestFatArch(myArch
->cputype
, myArch
->cpusubtype
,
660 (struct fat_arch
*) &fat
[1], fat
->nfat_arch
);
662 false, ("%s hasn't got arch for %s\n", pathName
, myArch
->name
));
663 return_if(arch
->offset
+ arch
->size
> file
->fMapSize
,
664 false, ("%s's %s arch is incomplete\n", pathName
, myArch
->name
));
665 file
->fMachO
= file
->fMap
+ arch
->offset
;
666 file
->fMachOSize
= arch
->size
;
667 magic
= ((const struct mach_header
*) file
->fMachO
)->magic
;
672 return_if(magic
!= MH_MAGIC
,
673 false, ("%s isn't a valid mach-o\n", pathName
));
679 parseSegments(struct fileRecord
*file
, struct segment_command
*seg
)
681 struct sectionRecord
*sections
;
682 int i
, nsects
= seg
->nsects
;
683 const struct segmentMap
{
684 struct segment_command seg
;
685 const struct section sect
[1];
688 if (!file
->fSectData
) {
689 file
->fSectData
= DataCreate(0);
690 if (!file
->fSectData
)
694 // Increase length of section DataRef and cache data pointer
695 if (!DataAddLength(file
->fSectData
, nsects
* sizeof(struct sectionRecord
)))
697 file
->fSections
= (struct sectionRecord
*) DataGetPtr(file
->fSectData
);
699 // Initialise the new sections
700 sections
= &file
->fSections
[file
->fNSects
];
701 file
->fNSects
+= nsects
;
702 for (i
= 0, segMap
= (struct segmentMap
*) seg
; i
< nsects
; i
++)
703 sections
[i
].fSection
= &segMap
->sect
[i
];
709 remangleExternSymbols(struct fileRecord
*file
, const char *pathName
)
711 const struct nlist
*sym
;
713 DataRef strings
= NULL
;
715 DEBUG_LOG(("Remangling %s\n", pathName
));
717 file
->fNewStringBlocks
= DataCreate(0);
718 return_if(!file
->fNewStringBlocks
, false,
719 ("Unable to allocate new string table for %s\n", pathName
));
721 nsyms
= file
->fSymtab
->nsyms
;
722 for (i
= 0, sym
= file
->fSymbolBase
; i
< nsyms
; i
++, sym
++) {
726 unsigned char n_type
= sym
->n_type
;
728 // Not an external symbol or it is a stab in any case don't bother
729 if ((n_type
^ N_EXT
) & (N_STAB
| N_EXT
))
732 symname
= symNameByIndex(file
, i
);
736 strings
= DataCreate(16 * 1024); // Arbitrary block size
737 return_if(!strings
, false,
738 ("Unable to allocate new string block for %s\n", pathName
));
741 len
= DataRemaining(strings
);
742 newname
= DataGetEndPtr(strings
);
743 ret
= rem3_remangle_name(newname
, &len
, symname
);
745 case kR3InternalNotRemangled
:
746 errprintf("Remangler fails on %s in %s\n", symname
, pathName
);
748 case kR3NotRemangled
:
752 file
->fSymbToStringTable
[i
] = newname
;
753 file
->fRemangled
= file
->fSymbolsDirty
= true;
754 DataAddLength(strings
, len
+ 1); // returns strlen
757 case kR3BufferTooSmallRemangled
:
758 return_if(!DataAppendBytes
759 (file
->fNewStringBlocks
, &strings
, sizeof(strings
)),
760 false, ("Unable to allocate string table for %s\n", pathName
));
762 goto tryRemangleAgain
;
766 return_if(true, false,
767 ("Internal error - remangle of %s\n", pathName
));
772 return_if(!DataAppendBytes
773 (file
->fNewStringBlocks
, &strings
, sizeof(strings
)),
774 false, ("Unable to allocate string table for %s\n", pathName
));
780 static Boolean
parseSymtab(struct fileRecord
*file
, const char *pathName
)
782 const struct nlist
*sym
;
783 unsigned int i
, firstlocal
, nsyms
;
784 unsigned long strsize
;
786 Boolean foundOSObject
, found295CPP
;
788 // we found a link edit segment so recompute the bases
789 if (file
->fLinkEditSeg
) {
790 struct segment_command
*link
= file
->fLinkEditSeg
;
792 file
->fSymbolBase
= (struct nlist
*)
793 (link
->vmaddr
+ (file
->fSymtab
->symoff
- link
->fileoff
));
794 file
->fStringBase
= (char *)
795 (link
->vmaddr
+ (file
->fSymtab
->stroff
- link
->fileoff
));
796 return_if( ( (caddr_t
) file
->fStringBase
+ file
->fSymtab
->strsize
797 > (caddr_t
) link
->vmaddr
+ link
->vmsize
), false,
798 ("%s isn't a valid mach-o le, bad symbols\n", pathName
));
801 file
->fSymbolBase
= (struct nlist
*)
802 (file
->fMachO
+ file
->fSymtab
->symoff
);
803 file
->fStringBase
= (char *)
804 (file
->fMachO
+ file
->fSymtab
->stroff
);
805 return_if( ( file
->fSymtab
->stroff
+ file
->fSymtab
->strsize
806 > file
->fMachOSize
), false,
807 ("%s isn't a valid mach-o, bad symbols\n", pathName
));
810 nsyms
= file
->fSymtab
->nsyms
;
812 // If this file the kernel and do we have an executable image
813 file
->fNoKernelExecutable
= (vm_page_size
== file
->fSymtab
->symoff
)
814 && (file
->fSections
[0].fSection
->size
== 0);
816 // Generate a table of pointers to strings indexed by the symbol number
818 file
->fSym2Strings
= DataCreate(nsyms
* sizeof(const char *));
819 DataSetLength(file
->fSym2Strings
, nsyms
* sizeof(const char *));
820 return_if(!file
->fSym2Strings
, false,
821 ("Unable to allocate memory - symbol string trans\n", pathName
));
822 file
->fSymbToStringTable
= (const char **) DataGetPtr(file
->fSym2Strings
);
824 // Search for the first non-stab symbol in table
825 strsize
= file
->fSymtab
->strsize
;
826 strbase
= file
->fStringBase
;
828 found295CPP
= foundOSObject
= false;
829 for (i
= 0, sym
= file
->fSymbolBase
; i
< nsyms
; i
++, sym
++) {
830 long strx
= sym
->n_un
.n_strx
;
831 const char *symname
= strbase
+ strx
;
832 unsigned char n_type
;
834 return_if(((unsigned long) strx
> strsize
), false,
835 ("%s has an illegal string offset in symbol %d\n", pathName
, i
));
837 // Load up lookup symbol look table with sym names
838 file
->fSymbToStringTable
[i
] = symname
;
840 n_type
= sym
->n_type
& (N_TYPE
| N_EXT
);
842 // Find the first exported symbol
843 if ( !firstlocal
&& (n_type
& N_EXT
) ) {
845 file
->fLocalSyms
= sym
;
848 // Find the a OSObject based subclass by searching for symbols
849 // that have a suffix of '10superClassE'
850 symname
++; // Skip leading '_'
853 && (n_type
== (N_SECT
| N_EXT
) || n_type
== (N_ABS
| N_EXT
))
855 const char *suffix
, *endSym
;
857 endSym
= symname
+ strlen(symname
);
859 // Find out if this symbol has the superclass suffix.
860 if (symname
[0] == kCPPSymbolPrefix
[0]
861 && symname
[1] == kCPPSymbolPrefix
[1]) {
863 suffix
= endSym
- sizeof(k31SuperClassSuffix
) + 1;
865 // Check for a gcc3 OSObject subclass
867 && !strcmp(suffix
, k31SuperClassSuffix
))
868 foundOSObject
= true;
871 suffix
= endSym
- sizeof(k29SuperClassSuffix
);
873 // Check for a gcc295 OSObject subclass
875 && ('.' == *suffix
|| '$' == *suffix
)
876 && !strcmp(suffix
+1, k29SuperClassSuffix
)) {
877 found295CPP
= foundOSObject
= true;
879 else if (!found295CPP
) {
880 // Finally just check if we need to remangle
881 symname
++; // skip leading '__'
883 if ('_' == *symname
++ && '_' == *symname
++) {
891 else if (sym
->n_type
== (N_EXT
| N_UNDF
)) {
892 if ( !file
->fNLocal
) // Find the last local symbol
893 file
->fNLocal
= i
- firstlocal
;
895 symname
++; // Skip possible second '_' at start.
897 if ('_' == *symname
++ && '_' == *symname
++) {
904 // Note symname is trashed at this point
906 return_if(i
< nsyms
, false,
907 ("%s isn't a valid mach-o, bad symbol strings\n", pathName
));
909 return_if(!file
->fLocalSyms
, false, ("%s has no symbols?\n", pathName
));
911 // If we don't have any undefined symbols then all symbols
912 // must be local so just compute it now if necessary.
913 if ( !file
->fNLocal
)
914 file
->fNLocal
= i
- firstlocal
;
916 file
->fFoundOSObject
= foundOSObject
;
918 if (found295CPP
&& !remangleExternSymbols(file
, pathName
))
924 // @@@ gvdl: These functions need to be hashed they are
925 // going to be way too slow for production code.
926 static const struct nlist
*
927 findSymbolByAddress(const struct fileRecord
*file
, void *entry
)
929 // not quite so dumb linear search of all symbols
930 const struct nlist
*sym
;
933 // First try to find the symbol in the most likely place which is the
935 sym
= file
->fLocalSyms
;
936 for (i
= 0, nsyms
= file
->fNLocal
; i
< nsyms
; i
++, sym
++) {
937 if (sym
->n_value
== (unsigned long) entry
&& !(sym
->n_type
& N_STAB
) )
941 // Didn't find it in the external symbols so try to local symbols before
943 sym
= file
->fSymbolBase
;
944 for (i
= 0, nsyms
= file
->fSymtab
->nsyms
; i
< nsyms
; i
++, sym
++) {
945 if ( (sym
->n_type
& N_EXT
) )
947 if ( sym
->n_value
== (unsigned long) entry
&& !(sym
->n_type
& N_STAB
) )
954 struct searchContext
{
955 const char *fSymname
;
956 const struct fileRecord
*fFile
;
959 static int symbolSearch(const void *vKey
, const void *vSym
)
961 const struct searchContext
*key
= (const struct searchContext
*) vKey
;
962 const struct nlist
*sym
= (const struct nlist
*) vSym
;
964 return strcmp(key
->fSymname
+ 1, symbolname(key
->fFile
, sym
) + 1);
967 static const struct nlist
*
968 findSymbolByName(struct fileRecord
*file
, const char *symname
)
970 if (file
->fRemangled
) {
971 // @@@ gvdl: Performance problem
972 // Linear search as we don't sort after remangling
973 const struct nlist
*sym
;
974 int i
= file
->fLocalSyms
- file
->fSymbolBase
;
975 int nLocal
= file
->fNLocal
+ i
;
977 for (sym
= file
->fLocalSyms
; i
< nLocal
; i
++, sym
++)
978 if (!strcmp(symNameByIndex(file
, i
) + 1, symname
+ 1))
983 struct searchContext context
;
985 context
.fSymname
= symname
;
986 context
.fFile
= file
;
987 return (struct nlist
*)
989 file
->fLocalSyms
, file
->fNLocal
, sizeof(struct nlist
),
995 relocateSection(const struct fileRecord
*file
, struct sectionRecord
*sectionRec
)
997 const struct nlist
*symbol
;
998 const struct section
*section
;
999 struct relocRecord
*rec
;
1000 struct relocation_info
*rinfo
;
1002 unsigned long r_address
, r_symbolnum
, r_length
;
1003 enum reloc_type_generic r_type
;
1007 sectionRec
->fRelocCache
= DataCreate(
1008 sectionRec
->fSection
->nreloc
* sizeof(struct relocRecord
));
1009 if (!sectionRec
->fRelocCache
)
1012 section
= sectionRec
->fSection
;
1013 sectionBase
= file
->fMachO
+ section
->offset
;
1015 rec
= (struct relocRecord
*) DataGetPtr(sectionRec
->fRelocCache
);
1016 rinfo
= (struct relocation_info
*) (file
->fMachO
+ section
->reloff
);
1017 for (i
= 0; i
< section
->nreloc
; i
++, rec
++, rinfo
++) {
1019 // Totally uninterested in scattered relocation entries
1020 if ( (rinfo
->r_address
& R_SCATTERED
) )
1023 r_address
= rinfo
->r_address
;
1024 entry
= (void **) (sectionBase
+ r_address
);
1027 * The r_address field is really an offset into the contents of the
1028 * section and must reference something inside the section (Note
1029 * that this is not the case for PPC_RELOC_PAIR entries but this
1030 * can't be one with the above checks).
1032 return_if(r_address
>= section
->size
, false,
1033 ("Invalid relocation entry in %s - not in section\n", file
->fPath
));
1035 // If we don't have a VANILLA entry or the Vanilla entry isn't
1036 // a 'long' then ignore the entry and try the next.
1037 r_type
= (enum reloc_type_generic
) rinfo
->r_type
;
1038 r_length
= rinfo
->r_length
;
1039 if (r_type
!= GENERIC_RELOC_VANILLA
|| r_length
!= 2)
1042 r_symbolnum
= rinfo
->r_symbolnum
;
1045 * If rinfo->r_extern is set this relocation entry is an external entry
1046 * else it is a local entry.
1048 if (rinfo
->r_extern
) {
1050 * This is an external relocation entry.
1051 * r_symbolnum is an index into the input file's symbol table
1052 * of the symbol being refered to. The symbol must be
1053 * undefined to be used in an external relocation entry.
1055 return_if(r_symbolnum
>= file
->fSymtab
->nsyms
, false,
1056 ("Invalid relocation entry in %s - no symbol\n", file
->fPath
));
1059 * If this is an indirect symbol resolve indirection (all chains
1060 * of indirect symbols have been resolved so that they point at
1061 * a symbol that is not an indirect symbol).
1063 symbol
= file
->fSymbolBase
;
1064 if ((symbol
[r_symbolnum
].n_type
& N_TYPE
) == N_INDR
)
1065 r_symbolnum
= symbol
[r_symbolnum
].n_value
;
1066 symbol
= &symbol
[r_symbolnum
];
1068 return_if(symbol
->n_type
!= (N_EXT
| N_UNDF
), false,
1069 ("Invalid relocation entry in %s - extern\n", file
->fPath
));
1073 * If the symbol is not in any section then it can't be a
1074 * pointer to a local segment and I don't care about it.
1076 if (r_symbolnum
== R_ABS
)
1079 // Note segment references are offset by 1 from 0.
1080 return_if(r_symbolnum
> file
->fNSects
, false,
1081 ("Invalid relocation entry in %s - local\n", file
->fPath
));
1083 // Find the symbol, if any, that backs this entry
1084 symbol
= findSymbolByAddress(file
, *entry
);
1087 rec
->fValue
= *entry
; // Save the previous value
1088 rec
->fRInfo
= rinfo
; // Save a pointer to the reloc
1089 rec
->fSymbol
= symbol
; // Record the current symbol
1091 *entry
= (void *) rec
; // Save pointer to record in object image
1094 DataSetLength(sectionRec
->fRelocCache
, i
* sizeof(struct relocRecord
));
1095 ((struct fileRecord
*) file
)->fImageDirty
= true;
1100 static const struct nlist
*
1101 findSymbolRefAtLocation(const struct fileRecord
*file
,
1102 struct sectionRecord
*sctn
, void **loc
)
1104 if (file
->fIsKernel
) {
1106 return findSymbolByAddress(file
, *loc
);
1108 else if (sctn
->fRelocCache
|| relocateSection(file
, sctn
)) {
1109 struct relocRecord
*reloc
= (struct relocRecord
*) *loc
;
1111 if (DataContainsAddr(sctn
->fRelocCache
, reloc
))
1112 return reloc
->fSymbol
;
1119 addClass(struct fileRecord
*file
,
1120 struct metaClassRecord
*inClass
,
1123 Boolean result
= false;
1124 struct metaClassRecord
*newClass
= NULL
;
1125 struct metaClassRecord
**fileClasses
= NULL
;
1128 if (!file
->fClassList
) {
1129 file
->fClassList
= DataCreate(0);
1130 if (!file
->fClassList
)
1135 // Attempt to allocate all necessary resource first
1136 len
= strlen(cname
) + 1
1137 + (int) (&((struct metaClassRecord
*) 0)->fClassName
);
1138 newClass
= (struct metaClassRecord
*) malloc(len
);
1142 if (!DataAddLength(file
->fClassList
, sizeof(struct metaClassRecord
*)))
1144 fileClasses
= (struct metaClassRecord
**)
1145 (DataGetPtr(file
->fClassList
) + DataGetLength(file
->fClassList
));
1147 // Copy the meta Class structure and string name into newClass and
1148 // insert object at end of the file->fClassList and sMergeMetaClasses
1149 *newClass
= *inClass
;
1150 strcpy(newClass
->fClassName
, cname
);
1151 fileClasses
[-1] = newClass
;
1157 DataAddLength(file
->fClassList
, -sizeof(struct metaClassRecord
*));
1165 static struct metaClassRecord
*getClass(DataRef classList
, const char *cname
)
1169 struct metaClassRecord
**classes
, *thisClass
;
1171 nclass
= DataGetLength(classList
) / sizeof(struct metaClassRecord
*);
1172 classes
= (struct metaClassRecord
**) DataGetPtr(classList
);
1173 for (i
= 0; i
< nclass
; i
++) {
1174 thisClass
= classes
[i
];
1175 if (!strcmp(thisClass
->fClassName
, cname
))
1183 // Add the class 'cname' to the list of known OSObject based classes
1184 // Note 'sym' is the <cname>10superClassE symbol.
1186 recordClass(struct fileRecord
*file
, const char *cname
, const struct nlist
*sym
)
1188 Boolean result
= false;
1189 char *supername
= NULL
;
1190 const char *classname
= NULL
;
1191 struct metaClassRecord newClass
;
1192 char strbuffer
[1024];
1194 // Only do the work to find the super class if we are
1195 // not currently working on the kernel. The kernel is the end
1196 // of all superclass chains by definition as the kernel must be binary
1197 // compatible with itself.
1198 if (!file
->fIsKernel
) {
1200 const struct nlist
*supersym
;
1201 const struct section
*section
;
1202 struct sectionRecord
*sectionRec
;
1203 unsigned char sectind
= sym
->n_sect
;
1204 const char *superstr
;
1208 // We can't resolve anything that isn't in a real section
1209 // Note that the sectind is starts at one to make room for the
1210 // NO_SECT flag but the fNSects field isn't offset so we have a
1211 // '>' test. Which means this isn't an OSObject based class
1212 if (sectind
== NO_SECT
|| sectind
> file
->fNSects
) {
1216 sectionRec
= file
->fSections
+ sectind
- 1;
1217 section
= sectionRec
->fSection
;
1218 location
= (void **) ( file
->fMachO
+ section
->offset
1219 + sym
->n_value
- section
->addr
);
1221 supersym
= findSymbolRefAtLocation(file
, sectionRec
, location
);
1223 result
= true; // No superclass symbol then it isn't an OSObject.
1227 // Find string in file and skip leading '_' and then find the suffix
1228 superstr
= symbolname(file
, supersym
) + 1;
1229 suffix
= superstr
+ strlen(superstr
) - sizeof(kGMetaSuffix
) + 1;
1230 if (suffix
<= superstr
|| strcmp(suffix
, kGMetaSuffix
)) {
1231 result
= true; // Not an OSObject superclass so ignore it..
1235 // Got a candidate so hand it over for class processing.
1236 snamelen
= suffix
- superstr
- sizeof(kOSObjPrefix
) + 2;
1237 supername
= (char *) malloc(snamelen
+ 1);
1238 bcopy(superstr
+ sizeof(kOSObjPrefix
) - 2, supername
, snamelen
);
1239 supername
[snamelen
] = '\0';
1243 break_if(getClass(file
->fClassList
, cname
),
1244 ("Duplicate class %s in %s\n", cname
, file
->fPath
));
1246 snprintf(strbuffer
, sizeof(strbuffer
), "%s%s", kVTablePrefix
, cname
);
1247 newClass
.fVTableSym
= findSymbolByName(file
, strbuffer
);
1248 break_if(!newClass
.fVTableSym
,
1249 ("Can't find vtable %s in %s\n", cname
, file
->fPath
));
1251 newClass
.fFile
= file
;
1252 newClass
.fSuperName
= supername
;
1253 newClass
.fPatchedVTable
= NULL
;
1255 // Can't use cname as it may be a stack variable
1256 // However the vtable's string has the class name as a suffix
1257 // so why don't we use that rather than mallocing a string.
1258 classname
= symbolname(file
, newClass
.fVTableSym
)
1259 + sizeof(kVTablePrefix
) - 1;
1260 break_if(!addClass(file
, &newClass
, classname
),
1261 ("recordClass - no memory?\n"));
1275 static Boolean
getMetaClassGraph(struct fileRecord
*file
)
1277 const struct nlist
*sym
;
1280 // Search the symbol table for the local symbols that are generated
1281 // by the metaclass system. There are three metaclass variables
1282 // that are relevant.
1284 // <ClassName>.metaClass A pointer to the meta class structure.
1285 // <ClassName>.superClass A pointer to the super class's meta class.
1286 // <ClassName>.gMetaClass The meta class structure itself.
1287 // ___vt<ClassName> The VTable for the class <ClassName>.
1289 // In this code I'm going to search for any symbols that
1290 // ends in k31SuperClassSuffix as this indicates this class is a conforming
1291 // OSObject subclass and will need to be patched, and it also
1292 // contains a pointer to the super class's meta class structure.
1293 sym
= file
->fLocalSyms
;
1294 for (i
= 0, nsyms
= file
->fNLocal
; i
< nsyms
; i
++, sym
++) {
1295 const char *symname
;
1297 char classname
[1024];
1298 unsigned char n_type
= sym
->n_type
& (N_TYPE
| N_EXT
);
1301 // Check that the symbols is a global and that it has a name.
1302 if (((N_SECT
| N_EXT
) != n_type
&& (N_ABS
| N_EXT
) != n_type
)
1303 || !sym
->n_un
.n_strx
)
1306 // Only search from the last *sep* in the symbol.
1307 // but skip the leading '_' in all symbols first.
1308 symname
= symbolname(file
, sym
) + 1;
1309 if (symname
[0] != kCPPSymbolPrefix
[0]
1310 || symname
[1] != kCPPSymbolPrefix
[1])
1313 suffix
= symname
+ strlen(symname
) - sizeof(k31SuperClassSuffix
) + 1;
1314 if (suffix
<= symname
|| strcmp(suffix
, k31SuperClassSuffix
))
1317 // Got a candidate so hand it over for class processing.
1318 cnamelen
= suffix
- symname
- sizeof(kOSObjPrefix
) + 2;
1319 return_if(cnamelen
+ 1 >= (int) sizeof(classname
),
1320 false, ("Symbol %s is too long", symname
));
1322 bcopy(symname
+ sizeof(kOSObjPrefix
) - 2, classname
, cnamelen
);
1323 classname
[cnamelen
] = '\0';
1324 if (!recordClass(file
, classname
, sym
))
1328 return_if(!file
->fClassList
, false, ("Internal error, "
1329 "getMetaClassGraph(%s) found no classes", file
->fPath
));
1331 DEBUG_LOG(("Found %ld classes in %p for %s\n",
1332 DataGetLength(file
->fClassList
)/sizeof(void*),
1333 file
->fClassList
, file
->fPath
));
1338 static Boolean
mergeOSObjectsForFile(const struct fileRecord
*file
)
1341 Boolean foundDuplicates
= false;
1343 DEBUG_LOG(("Merging file %s\n", file
->fPath
)); // @@@ gvdl:
1345 if (!file
->fClassList
)
1348 if (!sMergedFiles
) {
1349 sMergedFiles
= DataCreate(0);
1350 return_if(!sMergedFiles
, false,
1351 ("Unable to allocate memory metaclass list\n", file
->fPath
));
1354 // Check to see if we have already merged this file
1355 nmerged
= DataGetLength(sMergedFiles
) / sizeof(struct fileRecord
*);
1356 for (i
= 0; i
< nmerged
; i
++) {
1357 if (file
== ((void **) DataGetPtr(sMergedFiles
))[i
])
1361 if (!sMergeMetaClasses
) {
1362 sMergeMetaClasses
= DataCreate(0);
1363 return_if(!sMergeMetaClasses
, false,
1364 ("Unable to allocate memory metaclass list\n", file
->fPath
));
1366 else { /* perform a duplicate check */
1367 int i
, j
, cnt1
, cnt2
;
1368 struct metaClassRecord
**list1
, **list2
;
1370 list1
= (struct metaClassRecord
**) DataGetPtr(file
->fClassList
);
1371 cnt1
= DataGetLength(file
->fClassList
) / sizeof(*list1
);
1372 list2
= (struct metaClassRecord
**) DataGetPtr(sMergeMetaClasses
);
1373 cnt2
= DataGetLength(sMergeMetaClasses
) / sizeof(*list2
);
1375 for (i
= 0; i
< cnt1
; i
++) {
1376 for (j
= 0; j
< cnt2
; j
++) {
1377 if (!strcmp(list1
[i
]->fClassName
, list2
[j
]->fClassName
)) {
1378 errprintf("duplicate class %s in %s & %s\n",
1379 list1
[i
]->fClassName
,
1380 file
->fPath
, list2
[j
]->fFile
->fPath
);
1385 if (foundDuplicates
)
1388 return_if(!DataAppendBytes(sMergedFiles
, &file
, sizeof(file
)), false,
1389 ("Unable to allocate memory to merge %s\n", file
->fPath
));
1391 return_if(!DataAppendData(sMergeMetaClasses
, file
->fClassList
), false,
1392 ("Unable to allocate memory to merge %s\n", file
->fPath
));
1394 if (file
== sKernelFile
)
1395 sMergedKernel
= true;
1400 // Returns a pointer to the base of the section offset by the sections
1401 // base address. The offset is so that we can add nlist::n_values directly
1402 // to this address and get a valid pointer in our memory.
1403 static unsigned char *
1404 getSectionForSymbol(const struct fileRecord
*file
, const struct nlist
*symb
,
1407 const struct section
*section
;
1408 unsigned char sectind
;
1409 unsigned char *base
;
1411 sectind
= symb
->n_sect
; // Default to symbols section
1412 if ((symb
->n_type
& N_TYPE
) == N_ABS
&& file
->fIsKernel
) {
1413 // Absolute symbol so we have to iterate over our sections
1414 for (sectind
= 1; sectind
<= file
->fNSects
; sectind
++) {
1415 unsigned long start
, end
;
1417 section
= file
->fSections
[sectind
- 1].fSection
;
1418 start
= section
->addr
;
1419 end
= start
+ section
->size
;
1420 if (start
<= symb
->n_value
&& symb
->n_value
< end
) {
1421 // Found the relevant section
1427 // Is the vtable in a valid section?
1428 return_if(sectind
== NO_SECT
|| sectind
> file
->fNSects
,
1429 (unsigned char *) -1,
1430 ("%s isn't a valid kext, bad section reference\n", file
->fPath
));
1432 section
= file
->fSections
[sectind
- 1].fSection
;
1434 // for when we start walking the vtable so compute offset's now.
1435 base
= file
->fMachO
+ section
->offset
;
1436 *endP
= (void **) (base
+ section
->size
);
1438 return base
- section
->addr
; // return with addr offset
1441 static Boolean
resolveKernelVTable(struct metaClassRecord
*metaClass
)
1443 const struct fileRecord
*file
;
1444 struct patchRecord
*patchedVTable
;
1445 void **curEntry
, **vtableEntries
, **endSection
;
1446 unsigned char *sectionBase
;
1447 struct patchRecord
*curPatch
;
1450 // Should never occur but it doesn't cost us anything to check.
1451 if (metaClass
->fPatchedVTable
)
1454 DEBUG_LOG(("Kernel vtable %s\n", metaClass
->fClassName
)); // @@@ gvdl:
1456 // Do we have a valid vtable to patch?
1457 return_if(!metaClass
->fVTableSym
,
1458 false, ("Internal error - no class vtable symbol?\n"));
1460 file
= metaClass
->fFile
;
1462 // If the metaClass we are being to ask is in the kernel then we
1463 // need to do a quick scan to grab the fPatchList in a reliable format
1464 // however we don't need to check the superclass in the kernel
1465 // as the kernel vtables are always correct wrt themselves.
1466 // Note this ends the superclass chain recursion.
1467 return_if(!file
->fIsKernel
,
1468 false, ("Internal error - resolveKernelVTable not kernel\n"));
1470 if (file
->fNoKernelExecutable
) {
1471 // Oh dear attempt to map the kernel's VM into my memory space
1472 return_if(file
->fNoKernelExecutable
, false,
1473 ("Internal error - fNoKernelExecutable not implemented yet\n"));
1476 // We are going to need the base and the end
1477 sectionBase
= getSectionForSymbol(file
, metaClass
->fVTableSym
, &endSection
);
1478 if (-1 == (long) sectionBase
)
1481 vtableEntries
= (void **) (sectionBase
+ metaClass
->fVTableSym
->n_value
);
1482 curEntry
= vtableEntries
+ kVTablePreambleLen
;
1483 for (classSize
= 0; curEntry
< endSection
&& *curEntry
; classSize
++)
1486 return_if(*curEntry
, false, ("Bad kernel image, short section\n"));
1488 patchedVTable
= (struct patchRecord
*)
1489 malloc((classSize
+ 1) * sizeof(struct patchRecord
));
1490 return_if(!patchedVTable
, false, ("resolveKernelVTable - no memory\n"));
1492 // Copy the vtable of this class into the patch table
1493 curPatch
= patchedVTable
;
1494 curEntry
= vtableEntries
+ kVTablePreambleLen
;
1495 for (; *curEntry
; curEntry
++, curPatch
++) {
1496 curPatch
->fSymbol
= (struct nlist
*)
1497 findSymbolByAddress(file
, *curEntry
);
1498 curPatch
->fType
= kSymbolLocal
;
1501 // Tag the end of the patch vtable
1502 curPatch
->fSymbol
= NULL
;
1503 metaClass
->fPatchedVTable
= patchedVTable
;
1508 static const char *addNewString(struct fileRecord
*file
,
1509 const char *strname
, int namelen
)
1511 DataRef strings
= 0;
1514 namelen
++; // Include terminating '\0';
1516 // Make sure we have a string table as well for this symbol
1517 if (file
->fNewStringBlocks
) {
1518 DataRef
*blockTable
= (DataRef
*) DataGetPtr(file
->fNewStringBlocks
);
1519 int index
= DataGetLength(file
->fNewStringBlocks
) / sizeof(DataRef
*);
1520 strings
= blockTable
[index
- 1];
1521 if (DataRemaining(strings
) < namelen
)
1526 file
->fNewStringBlocks
= DataCreate(0);
1527 return_if(!file
->fNewStringBlocks
, NULL
,
1528 ("Unable to allocate new string table %s\n", file
->fPath
));
1532 int size
= (namelen
+ 1023) & ~1023;
1533 if (size
< 16 * 1024)
1535 strings
= DataCreate(size
);
1536 return_if(!strings
, NULL
,
1537 ("Unable to allocate new string block %s\n", file
->fPath
));
1539 !DataAppendBytes(file
->fNewStringBlocks
, &strings
, sizeof(strings
)),
1540 false, ("Unable to allocate string table for %s\n", file
->fPath
));
1543 newStr
= DataGetEndPtr(strings
);
1544 DataAppendBytes(strings
, strname
, namelen
);
1548 // reloc->fPatch must contain a valid pointer
1549 static struct nlist
*
1550 getNewSymbol(struct fileRecord
*file
,
1551 const struct relocRecord
*reloc
, const char *supername
)
1553 unsigned int size
, i
;
1556 struct relocation_info
*rinfo
;
1559 if (!file
->fNewSymbols
) {
1560 file
->fNewSymbols
= DataCreate(0);
1561 return_if(!file
->fNewSymbols
, NULL
,
1562 ("Unable to allocate new symbol table for %s\n", file
->fPath
));
1565 rinfo
= (struct relocation_info
*) reloc
->fRInfo
;
1566 size
= DataGetLength(file
->fNewSymbols
) / sizeof(struct nlist
*);
1567 sym
= (struct nlist
**) DataGetPtr(file
->fNewSymbols
);
1568 for (i
= 0; i
< size
; i
++, sym
++) {
1569 int symnum
= i
+ file
->fSymtab
->nsyms
;
1570 newStr
= symNameByIndex(file
, symnum
);
1571 if (!strcmp(newStr
, supername
)) {
1572 rinfo
->r_symbolnum
= symnum
;
1573 file
->fSymbolsDirty
= true;
1578 // Assert that this is a vaild symbol. I need this condition to be true
1579 // for the later code to make non-zero. So the first time through I'd
1580 // better make sure that it is 0.
1581 return_if(reloc
->fSymbol
->n_sect
, NULL
,
1582 ("Undefined symbol entry with non-zero section %s:%s\n",
1583 file
->fPath
, symbolname(file
, reloc
->fSymbol
)));
1585 // If we are here we didn't find the symbol so create a new one now
1586 msym
= (struct nlist
*) malloc(sizeof(struct nlist
));
1588 NULL
, ("Unable to create symbol table entry for %s", file
->fPath
));
1589 return_if(!DataAppendBytes(file
->fNewSymbols
, &msym
, sizeof(msym
)),
1590 NULL
, ("Unable to grow symbol table for %s\n", file
->fPath
));
1592 newStr
= addNewString(file
, supername
, strlen(supername
));
1595 // If we are here we didn't find the symbol so create a new one now
1596 return_if(!DataAppendBytes(file
->fSym2Strings
, &newStr
, sizeof(newStr
)),
1597 NULL
, ("Unable to grow symbol table for %s\n", file
->fPath
));
1598 file
->fSymbToStringTable
= (const char **) DataGetPtr(file
->fSym2Strings
);
1600 // Offset the string index by the original string table size
1601 // and negate the address to indicate that this is a 'new' symbol
1602 msym
->n_un
.n_strx
= -1;
1603 msym
->n_type
= (N_EXT
| N_UNDF
);
1604 msym
->n_sect
= NO_SECT
;
1606 msym
->n_value
= (unsigned long) newStr
;
1608 // Mark the old symbol as being potentially deletable I can use the
1609 // n_sect field as the input symbol must be of type N_UNDF which means
1610 // that the n_sect field must be set to NO_SECT otherwise it is an
1611 // invalid input file.
1613 // However the symbol may have been just inserted by the fixOldSymbol path.
1614 // If this is the case then we know it is in use and we don't have to
1615 // mark it as a deletable symbol.
1616 if (reloc
->fSymbol
->n_un
.n_strx
>= 0) {
1617 ((struct nlist
*) reloc
->fSymbol
)->n_un
.n_strx
1618 = -reloc
->fSymbol
->n_un
.n_strx
;
1619 ((struct nlist
*) reloc
->fSymbol
)->n_sect
= (unsigned char) -1;
1622 rinfo
->r_symbolnum
= i
+ file
->fSymtab
->nsyms
;
1623 file
->fSymbolsDirty
= true;
1627 static struct nlist
*
1628 fixOldSymbol(struct fileRecord
*file
,
1629 const struct relocRecord
*reloc
, const char *supername
)
1631 unsigned int namelen
;
1632 struct nlist
*sym
= (struct nlist
*) reloc
->fSymbol
;
1633 const char *oldname
= symbolname(file
, sym
);
1635 // assert(sym->n_un.n_strx >= 0);
1637 namelen
= strlen(supername
);
1639 sym
->n_un
.n_strx
= -sym
->n_un
.n_strx
;
1640 if (oldname
&& namelen
< strlen(oldname
))
1642 // Overwrite old string in string table
1643 strcpy((char *) oldname
, supername
);
1644 file
->fSymbolsDirty
= true;
1648 oldname
= addNewString(file
, supername
, namelen
);
1652 file
->fSymbToStringTable
[sym
- file
->fSymbolBase
] = oldname
;
1653 file
->fSymbolsDirty
= true;
1657 static enum patchState
1658 symbolCompare(const struct fileRecord
*file
,
1659 const struct nlist
*classsym
,
1660 const char *supername
)
1662 const char *classname
;
1665 // Check to see if the target function is locally defined
1666 // if it is then we can assume this is a local vtable override
1667 if ((classsym
->n_type
& N_TYPE
) != N_UNDF
)
1668 return kSymbolLocal
;
1670 // Check to see if both symbols point to the same symbol name
1671 // if so then we are still identical.
1672 classname
= symbolname(file
, classsym
);
1673 if (!strcmp(classname
, supername
))
1674 return kSymbolIdentical
;
1676 // We know that the target's vtable entry is different from the
1677 // superclass' vtable entry. This means that we will have to apply a
1678 // patch to the current entry, however before returning lets check to
1679 // see if we have a _RESERVEDnnn field 'cause we can use this as a
1680 // registration point that must align between vtables.
1681 if (strstr(supername
, kReservedNamePrefix
))
1682 return kSymbolMismatch
;
1684 // OK, we have a superclass difference where the superclass doesn't
1685 // reference a pad function so assume that the superclass is correct.
1686 if (strstr(classname
, kReservedNamePrefix
))
1687 return kSymbolPadUpdate
;
1689 return kSymbolSuperUpdate
;
1692 static Boolean
patchVTable(struct metaClassRecord
*metaClass
)
1694 struct metaClassRecord
*super
= NULL
;
1695 struct fileRecord
*file
;
1696 struct patchRecord
*patchedVTable
;
1697 struct relocRecord
**curReloc
, **vtableRelocs
, **endSection
;
1698 unsigned char *sectionBase
;
1701 // Should never occur but it doesn't cost us anything to check.
1702 if (metaClass
->fPatchedVTable
)
1705 // Do we have a valid vtable to patch?
1706 return_if(!metaClass
->fVTableSym
,
1707 false, ("Internal error - no class vtable symbol?\n"));
1709 file
= metaClass
->fFile
;
1711 // If the metaClass we are being to ask is in the kernel then we
1712 // need to do a quick scan to grab the fPatchList in a reliable format
1713 // however we don't need to check the superclass in the kernel
1714 // as the kernel vtables are always correct wrt themselves.
1715 // Note this ends the superclass chain recursion.
1716 return_if(file
->fIsKernel
,
1717 false, ("Internal error - patchVTable shouldn't used for kernel\n"));
1719 if (!metaClass
->fSuperName
)
1722 // The class isn't in the kernel so make sure that the super class
1723 // is patched before patching ouselves.
1724 super
= getClass(sMergeMetaClasses
, metaClass
->fSuperName
);
1725 return_if(!super
, false, ("Can't find superclass for %s : %s\n",
1726 metaClass
->fClassName
, metaClass
->fSuperName
));
1728 // Superclass recursion if necessary
1729 if (!super
->fPatchedVTable
) {
1732 if (super
->fFile
->fIsKernel
)
1733 res
= resolveKernelVTable(super
);
1735 res
= patchVTable(super
);
1740 DEBUG_LOG(("Patching %s\n", metaClass
->fClassName
)); // @@@ gvdl:
1742 // We are going to need the base and the end
1744 sectionBase
= getSectionForSymbol(file
,
1745 metaClass
->fVTableSym
, (void ***) &endSection
);
1746 if (-1 == (long) sectionBase
)
1749 vtableRelocs
= (struct relocRecord
**)
1750 (sectionBase
+ metaClass
->fVTableSym
->n_value
);
1751 curReloc
= vtableRelocs
+ kVTablePreambleLen
;
1752 for (classSize
= 0; curReloc
< endSection
&& *curReloc
; classSize
++)
1755 return_if(*curReloc
, false,
1756 ("%s isn't a valid kext, short section\n", file
->fPath
));
1758 patchedVTable
= (struct patchRecord
*)
1759 malloc((classSize
+ 1) * sizeof(struct patchRecord
));
1760 return_if(!patchedVTable
, false, ("patchedVTable - no memory\n"));
1763 struct patchRecord
*curPatch
;
1764 struct nlist
*symbol
;
1766 curPatch
= patchedVTable
;
1767 curReloc
= vtableRelocs
+ kVTablePreambleLen
;
1769 // Grab the super table patches if necessary
1770 // Can't be patching a kernel table as we don't walk super
1771 // class chains in the kernel symbol space.
1772 if (super
&& super
->fPatchedVTable
) {
1773 const struct patchRecord
*spp
;
1775 spp
= super
->fPatchedVTable
;
1777 for ( ; spp
->fSymbol
; curReloc
++, spp
++, curPatch
++) {
1778 const char *supername
=
1779 symbolname(super
->fFile
, spp
->fSymbol
);
1781 symbol
= (struct nlist
*) (*curReloc
)->fSymbol
;
1783 curPatch
->fType
= symbolCompare(file
, symbol
, supername
);
1784 switch (curPatch
->fType
) {
1785 case kSymbolIdentical
:
1789 case kSymbolSuperUpdate
:
1790 symbol
= getNewSymbol(file
, (*curReloc
), supername
);
1793 case kSymbolPadUpdate
:
1794 symbol
= fixOldSymbol(file
, (*curReloc
), supername
);
1797 case kSymbolMismatch
:
1798 errprintf("%s is not compatible with its superclass, "
1799 "%s superclass changed?\n",
1800 metaClass
->fClassName
, super
->fClassName
);
1804 errprintf("Internal error - unknown patch type\n");
1808 curPatch
->fSymbol
= symbol
;
1809 (*curReloc
)->fSymbol
= symbol
;
1816 // Copy the remainder of this class' vtable into the patch table
1817 for (; *curReloc
; curReloc
++, curPatch
++) {
1818 // Local reloc symbols
1819 curPatch
->fType
= kSymbolLocal
;
1820 curPatch
->fSymbol
= (struct nlist
*) (*curReloc
)->fSymbol
;
1823 // Tag the end of the patch vtable
1824 curPatch
->fSymbol
= NULL
;
1826 metaClass
->fPatchedVTable
= patchedVTable
;
1832 free(patchedVTable
);
1837 static Boolean
growImage(struct fileRecord
*file
, vm_size_t delta
)
1840 file
->fMachOSize
+= delta
;
1841 return (file
->fMachO
+ file
->fMachOSize
<= file
->fPadEnd
);
1843 vm_address_t startMachO
, endMachO
, endMap
;
1844 vm_offset_t newMachO
;
1846 unsigned long i
, last
= 0;
1847 struct metaClassRecord
**classes
= NULL
;
1848 struct sectionRecord
*section
;
1851 startMachO
= (vm_address_t
) file
->fMachO
;
1852 endMachO
= startMachO
+ file
->fMachOSize
+ delta
;
1853 endMap
= (vm_address_t
) file
->fMap
+ file
->fMapSize
;
1855 // Do we have room in the current mapped image
1856 if (endMachO
< round_page(endMap
)) {
1857 file
->fMachOSize
+= delta
;
1861 newsize
= endMachO
- startMachO
;
1862 if (newsize
< round_page(file
->fMapSize
)) {
1863 DEBUG_LOG(("Growing image %s by moving\n", file
->fPath
));
1865 // We have room in the map if we shift the macho image within the
1866 // current map. We will have to patch up pointers into the object.
1867 newMachO
= (vm_offset_t
) file
->fMap
;
1868 bcopy((char *) startMachO
, (char *) newMachO
, file
->fMachOSize
);
1870 else if (file
->fIsKmem
) {
1871 // kmem_alloced mapping so we can try a kmem_realloc
1872 ret
= kmem_realloc(kernel_map
,
1873 (vm_address_t
) file
->fMap
,
1874 (vm_size_t
) file
->fMapSize
,
1877 if (KERN_SUCCESS
!= ret
)
1880 // If the mapping didn't move then just return
1881 if ((vm_address_t
) file
->fMap
== newMachO
) {
1882 file
->fMachOSize
= file
->fMapSize
= newsize
;
1886 DEBUG_LOG(("Growing image %s by reallocing\n", file
->fPath
));
1887 // We have relocated the kmem image so we are going to have to
1888 // move all of the pointers into the image around.
1891 DEBUG_LOG(("Growing image %s by allocating\n", file
->fPath
));
1892 // The image doesn't have room for us and I can't kmem_realloc
1893 // then I just have to bite the bullet and copy the object code
1894 // into a bigger memory segment
1895 ret
= kmem_alloc(kernel_map
, &newMachO
, newsize
);
1897 if (KERN_SUCCESS
!= ret
)
1899 bcopy((char *) startMachO
, (void *) newMachO
, file
->fMachOSize
);
1900 file
->fIsKmem
= true;
1904 file
->fMap
= file
->fMachO
= (unsigned char *) newMachO
;
1905 file
->fMapSize
= newsize
;
1906 file
->fMachOSize
+= delta
; // Increment the image size
1908 // If we are here then we have shifted the object image in memory
1909 // I really should change all of my pointers into the image to machO offsets
1910 // but I have run out of time. So I'm going to very quickly go over the
1911 // cached data structures and add adjustments to the addresses that are
1912 // affected. I wonder how long it will take me to get them all.
1914 // For every pointer into the MachO I need to add an adjustment satisfying
1915 // the following simultanous equations
1916 // addr_old = macho_old + fixed_offset
1917 // addr_new = macho_new + fixed_offset therefore:
1918 // addr_new = addr_old + (macho_new - macho_old)
1919 #define REBASE(addr, delta) ( ((vm_address_t) (addr)) += (delta) )
1920 delta
= newMachO
- startMachO
;
1922 // Rebase the cached-in object 'struct symtab_command' pointer
1923 REBASE(file
->fSymtab
, delta
);
1925 // Rebase the cached-in object 'struct nlist' pointer for all symbols
1926 REBASE(file
->fSymbolBase
, delta
);
1928 // Rebase the cached-in object 'struct nlist' pointer for local symbols
1929 REBASE(file
->fLocalSyms
, delta
);
1931 // Rebase the cached-in object 'char' pointer for the string table
1932 REBASE(file
->fStringBase
, delta
);
1934 // Ok now we have to go over all of the relocs one last time
1935 // to clean up the pad updates which had their string index negated
1936 // to indicate that we have finished with them.
1937 section
= file
->fSections
;
1938 for (i
= 0, last
= file
->fNSects
; i
< last
; i
++, section
++)
1939 REBASE(section
->fSection
, delta
);
1941 // We only ever grow images that contain class lists so dont bother
1942 // the check if file->fClassList is non-zero 'cause it can't be
1943 // assert(file->fClassList);
1944 last
= DataGetLength(file
->fClassList
)
1945 / sizeof(struct metaClassRecord
*);
1946 classes
= (struct metaClassRecord
**) DataGetPtr(file
->fClassList
);
1947 for (i
= 0; i
< last
; i
++) {
1948 struct patchRecord
*patch
;
1950 for (patch
= classes
[i
]->fPatchedVTable
; patch
->fSymbol
; patch
++) {
1951 vm_address_t symAddr
= (vm_address_t
) patch
->fSymbol
;
1953 // Only need to rebase if the symbol is part of the image
1954 // If this is a new symbol then it was independantly allocated
1955 if (symAddr
>= startMachO
&& symAddr
< endMachO
)
1956 REBASE(patch
->fSymbol
, delta
);
1960 // Finally rebase all of the string table pointers
1961 last
= file
->fSymtab
->nsyms
;
1962 for (i
= 0; i
< last
; i
++)
1963 REBASE(file
->fSymbToStringTable
[i
], delta
);
1973 prepareFileForLink(struct fileRecord
*file
)
1975 unsigned long i
, last
, numnewsyms
, newsymsize
, newstrsize
;
1976 struct sectionRecord
*section
;
1977 struct nlist
**symp
, *sym
;
1978 DataRef newStrings
, *stringBlocks
;
1980 // If we didn't even do a pseudo 'relocate' and dirty the image
1981 // then we can just return now.
1982 if (!file
->fImageDirty
)
1985 DEBUG_LOG(("Linking 2 %s\n", file
->fPath
)); // @@@ gvdl:
1987 // We have to go over all of the relocs to repair the damage
1988 // that we have done to the image when we did our 'relocation'
1989 section
= file
->fSections
;
1990 for (i
= 0, last
= file
->fNSects
; i
< last
; i
++, section
++) {
1991 unsigned char *sectionBase
;
1992 struct relocRecord
*rec
;
1993 unsigned long j
, nreloc
;
1995 if (section
->fRelocCache
) {
1996 sectionBase
= file
->fMachO
+ section
->fSection
->offset
;
1997 nreloc
= section
->fSection
->nreloc
;
1998 rec
= (struct relocRecord
*) DataGetPtr(section
->fRelocCache
);
2000 // We will need to repair the reloc list
2001 for (j
= 0; j
< nreloc
; j
++, rec
++) {
2005 // Repair Damage to object image
2006 entry
= (void **) (sectionBase
+ rec
->fRInfo
->r_address
);
2007 *entry
= rec
->fValue
;
2009 // Check if the symbol that this relocation entry points
2010 // to is marked as erasable
2011 sym
= (struct nlist
*) rec
->fSymbol
;
2012 if (sym
&& sym
->n_type
== (N_EXT
| N_UNDF
)
2013 && sym
->n_sect
== (unsigned char) -1) {
2014 // It is in use so we better clear the mark
2015 sym
->n_un
.n_strx
= -sym
->n_un
.n_strx
;
2016 sym
->n_sect
= NO_SECT
;
2020 // Clean up the fRelocCache we don't need it any more.
2021 DataRelease(section
->fRelocCache
);
2022 section
->fRelocCache
= 0;
2025 file
->fImageDirty
= false; // Image is clean
2027 // If we didn't dirty the symbol table then just return
2028 if (!file
->fSymbolsDirty
)
2031 // calculate total file size increase and check against padding
2032 if (file
->fNewSymbols
) {
2033 numnewsyms
= DataGetLength(file
->fNewSymbols
);
2034 symp
= (struct nlist
**) DataGetPtr(file
->fNewSymbols
);
2040 numnewsyms
/= sizeof(struct nlist
*);
2041 file
->fSymtab
->nsyms
+= numnewsyms
;
2043 // old sting size + 30% rounded up to nearest page
2044 newstrsize
= file
->fSymtab
->strsize
* 21 / 16;
2045 newstrsize
= (newstrsize
+ PAGE_MASK
) & ~PAGE_MASK
;
2046 newStrings
= DataCreate(newstrsize
);
2047 return_if(!newStrings
, false,
2048 ("Unable to allocate a copy aside buffer, no memory\n"));
2050 newsymsize
= numnewsyms
* sizeof(struct nlist
);
2051 file
->fStringBase
+= newsymsize
;
2052 file
->fSymtab
->stroff
+= newsymsize
;
2054 last
= file
->fSymtab
->nsyms
- numnewsyms
;
2056 DataAppendBytes(newStrings
, &newstrsize
, 4); // Leading nuls
2057 sym
= file
->fSymbolBase
;
2059 // Pre-compute an already offset new symbol pointer. The offset is the
2060 // orignal symbol table.
2062 for (i
= 0; i
< file
->fSymtab
->nsyms
; i
++, sym
++) {
2063 const char *str
= symNameByIndex(file
, i
);
2064 int len
= strlen(str
) + 1;
2067 // Rebase sym in the new symbol region
2071 if (sym
->n_un
.n_strx
< 0 && sym
->n_type
== (N_EXT
| N_UNDF
)
2072 && (unsigned char) -1 == sym
->n_sect
) {
2073 // after patching we find that this symbol is no longer in
2074 // use. So invalidate it by converting it into an N_ABS
2075 // symbol, remove the external bit and null out the name.
2076 bzero(sym
, sizeof(*sym
));
2077 sym
->n_type
= N_ABS
;
2080 // Repair the symbol for the getNewSymbol case.
2081 if (-1 == sym
->n_un
.n_strx
)
2084 // Record the offset of the string in the new table
2085 strx
= DataGetLength(newStrings
);
2086 return_if(!DataAppendBytes(newStrings
, str
, len
), false,
2087 ("Unable to append string, no memory\n"));
2089 sym
->n_un
.n_strx
= strx
;
2090 file
->fSymbToStringTable
[i
] = file
->fStringBase
+ strx
;
2094 // Don't need the new strings any more
2095 last
= DataGetLength(file
->fNewStringBlocks
) / sizeof(DataRef
);
2096 stringBlocks
= (DataRef
*) DataGetPtr(file
->fNewStringBlocks
);
2097 for (i
= 0; i
< last
; i
++)
2098 DataRelease(stringBlocks
[i
]);
2100 DataRelease(file
->fNewStringBlocks
);
2101 file
->fNewStringBlocks
= 0;
2103 newstrsize
= DataGetLength(newStrings
);
2104 newstrsize
= (newstrsize
+ 3) & ~3; // Round to nearest word
2106 !growImage(file
, newsymsize
+ newstrsize
- file
->fSymtab
->strsize
),
2107 false, ("Unable to patch the extension, no memory\n", file
->fPath
));
2109 // Push out the new symbol table if necessary
2113 // Append the new symbols to the original symbol table.
2114 base
= (caddr_t
) file
->fSymbolBase
2115 + (file
->fSymtab
->nsyms
- numnewsyms
) * sizeof(struct nlist
);
2116 symp
= (struct nlist
**) DataGetPtr(file
->fNewSymbols
);
2117 for (i
= 0; i
< numnewsyms
; i
++, base
+= sizeof(struct nlist
), symp
++)
2118 bcopy(*symp
, base
, sizeof(struct nlist
));
2120 DataRelease(file
->fNewSymbols
);
2121 file
->fNewSymbols
= 0;
2124 // Push out the new string table if necessary
2126 unsigned long *base
= (unsigned long *) file
->fStringBase
;
2127 unsigned long actuallen
= DataGetLength(newStrings
);
2129 // Set the last word in string table to zero before copying data
2130 base
[(newstrsize
/ sizeof(unsigned long)) - 1] = 0;
2132 // Now copy the new strings back to the end of the file
2133 bcopy((caddr_t
) DataGetPtr(newStrings
), file
->fStringBase
, actuallen
);
2135 file
->fSymtab
->strsize
= newstrsize
;
2137 DataRelease(newStrings
);
2140 file
->fSymbolsDirty
= false;
2147 kld_file_map(const char *pathName
,
2152 kld_file_map(const char *pathName
)
2155 struct fileRecord file
, *fp
= 0;
2157 // Already done no need to repeat
2158 fp
= getFile(pathName
);
2162 bzero(&file
, sizeof(file
));
2166 file
.fMapSize
= mapSize
;
2167 file
.fIsKmem
= isKmem
;
2169 if (!mapObjectFile(&file
, pathName
))
2174 const struct machOMapping
{
2175 struct mach_header h
;
2176 struct load_command c
[1];
2178 const struct load_command
*cmd
;
2181 if (!findBestArch(&file
, pathName
))
2184 machO
= (const struct machOMapping
*) file
.fMachO
;
2185 if (file
.fMachOSize
< machO
->h
.sizeofcmds
)
2188 file
.fIsKernel
= (MH_EXECUTE
== machO
->h
.filetype
);
2190 // If the file type is MH_EXECUTE then this must be a kernel
2191 // as all Kernel extensions must be of type MH_OBJECT
2192 for (i
= 0, cmd
= &machO
->c
[0]; i
< machO
->h
.ncmds
; i
++) {
2193 if (cmd
->cmd
== LC_SYMTAB
)
2194 file
.fSymtab
= (struct symtab_command
*) cmd
;
2195 else if (cmd
->cmd
== LC_SEGMENT
) {
2196 struct segment_command
*seg
= (struct segment_command
*) cmd
;
2197 int nsects
= seg
->nsects
;
2200 return_if(!parseSegments(&file
, seg
),
2201 false, ("%s isn't a valid mach-o, bad segment",
2203 else if (file
.fIsKernel
) {
2205 // We don't need to look for the LinkEdit segment unless
2206 // we are running in the kernel environment.
2207 if (!strcmp(kLinkEditSegName
, seg
->segname
))
2208 file
.fLinkEditSeg
= seg
;
2213 cmd
= (struct load_command
*) ((UInt8
*) cmd
+ cmd
->cmdsize
);
2215 break_if(!file
.fSymtab
,
2216 ("%s isn't a valid mach-o, no symbols\n", pathName
));
2218 if (!parseSymtab(&file
, pathName
))
2221 fp
= addFile(&file
, pathName
);
2225 if (file
.fFoundOSObject
&& !getMetaClassGraph(fp
))
2232 // Automatically load the kernel's link edit segment if we are
2233 // attempting to load a driver.
2235 extern struct mach_header _mh_execute_header
;
2236 extern struct segment_command
*getsegbyname(char *seg_name
);
2238 struct segment_command
*sg
;
2242 sg
= (struct segment_command
*) getsegbyname(kLinkEditSegName
);
2243 break_if(!sg
, ("Can't find kernel link edit segment\n"));
2245 kernelSize
= sg
->vmaddr
+ sg
->vmsize
- (size_t) &_mh_execute_header
;
2246 ret
= kld_file_map(kld_basefile_name
,
2247 (unsigned char *) &_mh_execute_header
, kernelSize
,
2248 /* isKmem */ false);
2249 break_if(!ret
, ("kld can't map kernel file"));
2256 // Failure path, then clean up
2258 // @@@ gvdl: for the time being leak the file ref in the file table
2266 void *kld_file_getaddr(const char *pathName
, long *size
)
2268 struct fileRecord
*file
= getFile(pathName
);
2274 *size
= file
->fMachOSize
;
2276 return file
->fMachO
;
2279 void *kld_file_lookupsymbol(const char *pathName
, const char *symname
)
2281 struct fileRecord
*file
= getFile(pathName
);
2282 const struct nlist
*sym
;
2283 const struct section
*section
;
2284 unsigned char *sectionBase
;
2285 unsigned char sectind
;
2288 NULL
, ("Unknown file %s\n", pathName
));
2290 sym
= findSymbolByName(file
, symname
);
2292 // May be a non-extern symbol so look for it there
2294 unsigned int i
, nsyms
;
2296 sym
= file
->fSymbolBase
;
2297 for (i
= 0, nsyms
= file
->fSymtab
->nsyms
; i
< nsyms
; i
++, sym
++) {
2298 if ( (sym
->n_type
& N_EXT
) ) {
2300 break; // Terminate search when we hit an extern
2302 if ( (sym
->n_type
& N_STAB
) )
2304 if ( !strcmp(symname
, symNameByIndex(file
, i
)) )
2310 NULL
, ("Unknown symbol %s in %s\n", symname
, pathName
));
2312 // Is the vtable in a valid section?
2313 sectind
= sym
->n_sect
;
2314 return_if(sectind
== NO_SECT
|| sectind
> file
->fNSects
, NULL
,
2315 ("Malformed object file, invalid section reference for %s in %s\n",
2316 symname
, pathName
));
2318 section
= file
->fSections
[sectind
- 1].fSection
;
2319 sectionBase
= file
->fMachO
+ section
->offset
- section
->addr
;
2321 return (void *) (sectionBase
+ sym
->n_value
);
2324 Boolean
kld_file_merge_OSObjects(const char *pathName
)
2326 struct fileRecord
*file
= getFile(pathName
);
2329 false, ("Internal error - unable to find file %s\n", pathName
));
2331 return mergeOSObjectsForFile(file
);
2334 Boolean
kld_file_patch_OSObjects(const char *pathName
)
2336 struct fileRecord
*file
= getFile(pathName
);
2337 struct metaClassRecord
**classes
;
2338 unsigned long i
, last
;
2341 false, ("Internal error - unable to find file %s\n", pathName
));
2343 DEBUG_LOG(("Patch file %s\n", pathName
)); // @@@ gvdl:
2345 // If we don't have any classes we can return now.
2346 if (!file
->fClassList
)
2349 // If we haven't alread merged the kernel then do it now
2350 if (!sMergedKernel
&& sKernelFile
)
2351 mergeOSObjectsForFile(sKernelFile
);
2352 return_if(!sMergedKernel
, false, ("Internal error no kernel?\n"));
2354 if (!mergeOSObjectsForFile(file
))
2357 // Patch all of the classes in this executable
2358 last
= DataGetLength(file
->fClassList
) / sizeof(void *);
2359 classes
= (struct metaClassRecord
**) DataGetPtr(file
->fClassList
);
2360 for (i
= 0; i
< last
; i
++) {
2361 if (!patchVTable(classes
[i
])) {
2362 // RY: Set a flag in the file list to invalidate this data.
2363 // I would remove the file from the list, but that seems to be
2364 // not worth the effort.
2365 file
->fIgnoreFile
= TRUE
;
2374 Boolean
kld_file_prepare_for_link()
2377 unsigned long i
, nmerged
= 0;
2378 struct fileRecord
**files
;
2380 // Check to see if we have already merged this file
2381 nmerged
= DataGetLength(sMergedFiles
) / sizeof(struct fileRecord
*);
2382 files
= (struct fileRecord
**) DataGetPtr(sMergedFiles
);
2383 for (i
= 0; i
< nmerged
; i
++) {
2384 if (!files
[i
]->fIgnoreFile
&& !prepareFileForLink(files
[i
]))
2389 // Clear down the meta class table and merged file lists
2390 DataRelease(sMergeMetaClasses
);
2391 DataRelease(sMergedFiles
);
2392 sMergedFiles
= sMergeMetaClasses
= NULL
;
2393 sMergedKernel
= false;
2398 void kld_file_cleanup_all_resources()
2400 unsigned long i
, nfiles
;
2402 #if KERNEL // @@@ gvdl:
2403 // Debugger("kld_file_cleanup_all_resources");
2406 if (!sFilesTable
|| !(nfiles
= DataGetLength(sFilesTable
)))
2407 return; // Nothing to do just return now
2409 nfiles
/= sizeof(struct fileRecord
*);
2410 for (i
= 0; i
< nfiles
; i
++)
2411 removeFile(((void **) DataGetPtr(sFilesTable
))[i
]);
2413 DataRelease(sFilesTable
);
2416 // Don't really have to clean up anything more as the whole
2417 // malloc engine is going to be released and I couldn't be bothered.
2423 static const struct fileRecord
*sortFile
;
2424 static int symCompare(const void *vSym1
, const void *vSym2
)
2426 const struct nlist
*sym1
= vSym1
;
2427 const struct nlist
*sym2
= vSym2
;
2430 unsigned int ind1
, ind2
;
2432 ind1
= sym1
->n_type
& N_TYPE
;
2433 ind2
= sym2
->n_type
& N_TYPE
;
2435 // if sym1 is undefined then sym1 must come later than sym2
2438 // if sym2 is undefined then sym1 must come earlier than sym2
2441 /* drop out if neither are undefined */
2446 const struct fileRecord
*file
= sortFile
;
2447 const char *name1
, *name2
;
2449 name1
= file
->fStringBase
+ sym1
->n_un
.n_strx
;
2450 name2
= file
->fStringBase
+ sym2
->n_un
.n_strx
;
2451 return strcmp(name1
, name2
);
2456 Boolean
kld_file_debug_dump(const char *pathName
, const char *outName
)
2458 const struct fileRecord
*file
= getFile(pathName
);
2460 Boolean ret
= false;
2462 return_if(!file
, false, ("Unknown file %s for dumping\n", pathName
));
2464 fd
= open(outName
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666);
2465 return_if(-1 == fd
, false, ("Can't create output file %s - %s(%d)\n",
2466 outName
, strerror(errno
), errno
));
2470 // Sorting doesn't work until I fix the relocs too?
2472 // sort the symbol table appropriately
2473 unsigned int nsyms
= file
->fSymtab
->nsyms
2474 - (file
->fLocalSyms
- file
->fSymbolBase
);
2476 heapsort((void *) file
->fLocalSyms
, nsyms
, sizeof(struct nlist
),
2480 break_if(-1 == write(fd
, file
->fMachO
, file
->fMachOSize
),
2481 ("Can't dump output file %s - %s(%d)\n",
2482 outName
, strerror(errno
), errno
));
2491 #endif /* !KERNEL */