2 * Copyright (c) 2001-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * 2001-05-30 gvdl Initial implementation of the vtable patcher.
32 // 45678901234567890123456789012345678901234567890123456789012345678901234567890
34 #include <mach-o/fat.h>
35 #include <mach-o/loader.h>
36 #include <mach-o/nlist.h>
37 #include <mach-o/reloc.h>
39 #include <mach-o/swap.h>
40 #include <libkern/OSByteOrder.h>
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;
49 int kld_set_link_options
= 0;
50 int kld_unload_all
= 0;
58 #include <sys/systm.h>
60 #include <libkern/OSTypes.h>
62 #include <libsa/stdlib.h>
63 #include <libsa/mach/mach.h>
65 #include "mach_loader.h"
67 #include <vm/vm_kern.h>
69 enum { false = 0, true = 1 };
71 #define vm_page_size page_size
73 extern void kld_error_vprintf(const char *format
, va_list ap
);
75 extern struct mach_header _mh_execute_header
;
76 extern struct segment_command
*getsegbyname(char *seg_name
); // 32 bit only
86 #include <sys/errno.h>
87 #include <sys/fcntl.h>
92 #include <mach/mach.h>
93 #include <mach/mach_error.h>
95 #include <mach-o/arch.h>
97 #include <CoreFoundation/CoreFoundation.h>
99 #define PAGE_SIZE vm_page_size
100 #define PAGE_MASK (PAGE_SIZE - 1)
104 #include "kld_patch.h"
108 #define DIE() do { for (;;) ; } while(0)
111 # define LOG_DELAY() /* IODelay(200000) */
112 # define DEBUG_LOG(x) do { IOLog x; LOG_DELAY(); } while(0)
115 # define DEBUG_LOG(x) do { printf x; } while(0)
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
136 // GCC 2.95 drops 2 leading constants in the vtable
137 #define kVTablePreambleLen 2
139 // Last address that I'm willing to try find vm in
140 #define kTopAddr ((unsigned char *) (1024 * 1024 * 1024))
142 // Size in bytes that Data Ref object's get increased in size
143 // Must be a power of 2
144 #define kDataCapacityIncrement 128
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.
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) \
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 { \
171 #define MIN(a,b) (((a)<(b))?(a):(b))
174 #define MAX(a,b) (((a)>(b))?(a):(b))
177 typedef struct Data
{
178 unsigned long fLength
, fCapacity
;
182 struct sectionRecord
{
183 const struct section
*fSection
; // 32 bit mach object section
196 struct nlist
*fSymbol
;
197 const struct fileRecord
*fFile
;
198 enum patchState fType
;
203 struct nlist
*fSymbol
;
204 struct relocation_info
*fRInfo
;
208 struct metaClassRecord
{
210 struct fileRecord
*fFile
;
211 const struct nlist
*fVTableSym
;
212 struct patchRecord
*fPatchedVTable
;
217 size_t fMapSize
, fMachOSize
;
218 unsigned char *fMap
, *fMachO
, *fPadEnd
;
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
;
229 struct nlist
*fSymbolBase
;
230 struct nlist
*fLocalSyms
;
231 unsigned int fNSects
;
233 Boolean fIsKernel
, fIsReloc
, fIsIncrLink
, fNoKernelExecutable
, fIsKmem
;
234 Boolean fImageDirty
, fSymbolsDirty
;
235 Boolean fRemangled
, fFoundOSObject
;
243 static DataRef sFilesTable
;
244 static struct fileRecord
*sKernelFile
;
246 static DataRef sMergedFiles
;
247 static DataRef sMergeMetaClasses
;
248 static Boolean sMergedKernel
;
250 static const NXArchInfo
* sPreferArchInfo
;
252 static const struct nlist
*
253 findSymbolByName(struct fileRecord
*file
, const char *symname
);
255 static void errprintf(const char *fmt
, ...)
260 kld_error_vprintf(fmt
, ap
);
266 static __inline__
unsigned long DataGetLength(DataRef data
)
268 return data
->fLength
;
271 static __inline__
char *DataGetPtr(DataRef data
)
276 static __inline__
char *DataGetEndPtr(DataRef data
)
278 return data
->fData
+ data
->fLength
;
281 static __inline__
unsigned long DataRemaining(DataRef data
)
283 return data
->fCapacity
- data
->fLength
;
286 static __inline__ Boolean
DataContainsAddr(DataRef data
, void *vAddr
)
288 vm_offset_t offset
= (vm_address_t
) vAddr
;
293 offset
= (vm_address_t
) vAddr
- (vm_address_t
) data
->fData
;
294 return (offset
< data
->fLength
);
297 static Boolean
DataEnsureCapacity(DataRef data
, unsigned long capacity
)
299 // Don't bother to ever shrink a data object.
300 if (capacity
> data
->fCapacity
) {
303 capacity
+= kDataCapacityIncrement
- 1;
304 capacity
&= ~(kDataCapacityIncrement
- 1);
305 newData
= (char *) realloc(data
->fData
, capacity
);
309 bzero(newData
+ data
->fCapacity
, capacity
- data
->fCapacity
);
310 data
->fData
= newData
;
311 data
->fCapacity
= capacity
;
317 static __inline__ Boolean
DataSetLength(DataRef data
, unsigned long length
)
319 if (DataEnsureCapacity(data
, length
)) {
320 data
->fLength
= length
;
327 static __inline__ Boolean
DataAddLength(DataRef data
, unsigned long length
)
329 return DataSetLength(data
, data
->fLength
+ length
);
332 static __inline__ Boolean
333 DataAppendBytes(DataRef data
, const void *addr
, unsigned int len
)
335 unsigned long size
= DataGetLength(data
);
337 if (!DataAddLength(data
, len
))
340 bcopy(addr
, DataGetPtr(data
) + size
, len
);
344 static __inline__ Boolean
DataAppendData(DataRef dst
, DataRef src
)
346 return DataAppendBytes(dst
, DataGetPtr(src
), DataGetLength(src
));
349 static DataRef
DataCreate(unsigned long capacity
)
351 DataRef data
= (DataRef
) malloc(sizeof(Data
));
355 data
->fCapacity
= kDataCapacityIncrement
;
357 data
->fCapacity
= capacity
+ kDataCapacityIncrement
- 1;
358 data
->fCapacity
&= ~(kDataCapacityIncrement
- 1);
361 data
->fData
= (char *) malloc(data
->fCapacity
);
367 bzero(data
->fData
, data
->fCapacity
);
373 static void DataRelease(DataRef data
)
383 static __inline__
char *
384 symNameByIndex(const struct fileRecord
*file
, unsigned int symInd
)
386 return file
->fSymbToStringTable
[symInd
];
389 static __inline__
char *
390 symbolname(const struct fileRecord
*file
, const struct nlist
*sym
)
394 index
= sym
- file
->fSymbolBase
;
396 if (index
&& !sym
->n_un
.n_strx
)
397 return file
->fStringBase
+ sym
->n_value
;
399 if (index
< file
->fSymtab
->nsyms
)
400 return symNameByIndex(file
, index
);
402 if (-1 == sym
->n_un
.n_strx
)
403 return (char *) sym
->n_value
;
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
;
413 static struct fileRecord
*
414 getFile(const char *path
)
418 struct fileRecord
**files
;
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
))
432 static struct fileRecord
*
433 addFile(struct fileRecord
*file
, const char *path
)
435 struct fileRecord
*newFile
;
438 sFilesTable
= DataCreate(0);
443 newFile
= (struct fileRecord
*)
444 malloc(sizeof(struct fileRecord
) + strlen(path
));
448 if (!DataAppendBytes(sFilesTable
, &newFile
, sizeof(newFile
))) {
453 bcopy(file
, newFile
, sizeof(struct fileRecord
) - 1);
454 strlcpy((char *) newFile
->fPath
, path
, strlen(path
) + 1);
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
)
463 if (file
->fSectData
) {
464 struct sectionRecord
*section
;
465 unsigned int i
, nsect
;
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;
476 DataRelease(file
->fSectData
);
482 if (file
->fSym2Strings
) {
483 DataRelease(file
->fSym2Strings
);
484 file
->fSym2Strings
= 0;
490 kmem_free(kernel_map
, (vm_address_t
) file
->fMap
, file
->fMapSize
);
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
);
502 (void) munmap((caddr_t
) file
->fMap
, file
->fMapSize
);
508 static void removeFile(struct fileRecord
*file
)
512 if (file
->fClassList
) {
513 struct metaClassRecord
** fileClasses
=
514 (struct metaClassRecord
**)DataGetPtr(file
->fClassList
);
516 count
= DataGetLength(file
->fClassList
) / sizeof(struct metaClassRecord
*);
518 for (i
= 0; i
< count
; i
++) {
519 struct metaClassRecord
* thisClass
= fileClasses
[i
];
521 if (thisClass
->fSuperName
) {
522 free(thisClass
->fSuperName
);
524 if (thisClass
->fPatchedVTable
) {
525 free(thisClass
->fPatchedVTable
);
531 DataRelease(file
->fClassList
);
532 file
->fClassList
= 0;
535 // unmapFile() releases file->fSectData
537 if (file
->fNewSymbols
) {
538 struct nlist
** syms
=
539 (struct nlist
**)DataGetPtr(file
->fNewSymbols
);
541 count
= DataGetLength(file
->fNewSymbols
) / sizeof(struct nlist
*);
543 for (i
= 0; i
< count
; i
++) {
546 DataRelease(file
->fNewSymbols
);
547 file
->fNewSymbols
= 0;
550 if (file
->fNewStringBlocks
) {
551 DataRef
* stringBlocks
= (DataRef
*)DataGetPtr(file
->fNewStringBlocks
);
552 count
= DataGetLength(file
->fNewStringBlocks
) / sizeof(DataRef
);
554 for (i
= 0; i
< count
; i
++) {
555 DataRelease(stringBlocks
[i
]);
558 DataRelease(file
->fNewStringBlocks
);
559 file
->fNewStringBlocks
= 0;
562 // unmapFile() releases file->fSym2Strings
572 mapObjectFile(struct fileRecord
*file
, const char *pathName
)
574 Boolean result
= false;
575 static unsigned char *sFileMapBaseAddr
= 0;
579 if (!sFileMapBaseAddr
) {
581 vm_address_t probeAddr
;
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);
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
;
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
)));
606 break_if(fstat(fd
, &sb
) == -1,
607 ("Can't stat %s - %s\n", file
->fPath
, strerror(errno
)));
609 file
->fMapSize
= sb
.st_size
;
610 file
->fMap
= sFileMapBaseAddr
;
612 while (file
->fMap
< kTopAddr
) {
614 vm_address_t padVMEnd
;
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
,
623 break_if(ENOMEM
!= errno
,
624 ("mmap failed %d - %s\n", errno
, strerror(errno
)));
626 file
->fMap
= (unsigned char *) padVM
;
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
634 padVMEnd
= round_page(padVM
+ file
->fMapSize
);
635 padSize
= padVMEnd
- padVM
;
637 mach_task_self(), &padVM
, padSize
, VM_FLAGS_FIXED
);
638 if (KERN_SUCCESS
== ret
) {
639 file
->fPadEnd
= (unsigned char *) padVMEnd
;
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
)));
648 file
->fMap
= (unsigned char *) padVMEnd
;
649 continue; // try again wherever the vm system wants
653 if (-1 == retaddr
|| KERN_SUCCESS
!= ret
)
656 break_if(file
->fMap
>= kTopAddr
,
657 ("Unable to map memory %s\n", file
->fPath
));
659 sFileMapBaseAddr
= file
->fPadEnd
;
668 kld_set_architecture(const NXArchInfo
* arch
)
670 sPreferArchInfo
= arch
;
673 // This function can only operate on 32 bit mach-o files
675 kld_macho_swap(struct mach_header
* mh
)
677 struct segment_command
* seg
;
678 struct section
* section
;
679 CFIndex ncmds
, cmd
, sect
;
680 enum NXByteOrder hostOrder
= NXHostByteOrder();
682 if (MH_CIGAM
!= mh
->magic
)
685 swap_mach_header(mh
, hostOrder
);
688 seg
= (struct segment_command
*)(mh
+ 1);
691 cmd
++, seg
= (struct segment_command
*)(((vm_offset_t
)seg
) + seg
->cmdsize
))
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
);
699 if (OSSwapConstInt32(LC_SEGMENT
) != seg
->cmd
) {
700 swap_load_command((struct load_command
*) seg
, hostOrder
);
703 swap_segment_command(seg
, hostOrder
);
704 swap_section((struct section
*) (seg
+ 1), seg
->nsects
, hostOrder
);
706 section
= (struct section
*) (seg
+ 1);
707 for (sect
= 0; sect
< seg
->nsects
; sect
++, section
++) {
709 swap_relocation_info((struct relocation_info
*) (((vm_offset_t
) mh
) + section
->reloff
),
710 section
->nreloc
, hostOrder
);
717 // This function can only operate on 32 bit mach-o files
719 kld_macho_unswap(struct mach_header
* mh
, Boolean didSwap
, int symbols
)
721 // symbols == 0 => everything
722 // symbols == 1 => just nlists
723 // symbols == -1 => everything but nlists
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
;
735 seg
= (struct segment_command
*)(mh
+ 1);
738 cmd
++, seg
= (struct segment_command
*)(((vm_offset_t
)seg
) + cmdsize
))
740 cmdsize
= seg
->cmdsize
;
741 if (LC_SYMTAB
== seg
->cmd
) {
743 swap_nlist((struct nlist
*) (((vm_offset_t
) mh
) + ((struct symtab_command
*) seg
)->symoff
),
744 ((struct symtab_command
*) seg
)->nsyms
, hostOrder
);
747 swap_symtab_command((struct symtab_command
*) seg
, hostOrder
);
752 if (LC_SEGMENT
!= seg
->cmd
) {
753 swap_load_command((struct load_command
*) seg
, hostOrder
);
757 section
= (struct section
*) (seg
+ 1);
758 for (sect
= 0; sect
< seg
->nsects
; sect
++, section
++) {
760 swap_relocation_info((struct relocation_info
*) (((vm_offset_t
) mh
) + section
->reloff
),
761 section
->nreloc
, hostOrder
);
763 swap_section((struct section
*) (seg
+ 1), seg
->nsects
, hostOrder
);
764 swap_segment_command(seg
, hostOrder
);
767 swap_mach_header(mh
, hostOrder
);
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
)
777 struct fat_header
*fat
;
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
;
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
));
791 // CIGAM is byte-swapped MAGIC
792 if (magic
== FAT_MAGIC
|| magic
== FAT_CIGAM
) {
794 load_return_t load_return
;
795 struct fat_arch fatinfo
;
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
));
801 file
->fMachO
= file
->fMap
+ fatinfo
.offset
;
802 file
->fMachOSize
= fatinfo
.size
;
803 magic
= ((const struct mach_header
*) file
->fMachO
)->magic
;
808 // Do we need to in-place swap the endianness of the fat header?
809 if (magic
== FAT_CIGAM
) {
811 struct fat_arch
*arch
;
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
));
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
);
827 magic
= OSSwapBigToHostInt32(fat
->magic
);
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
;
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
));
842 myArch
= sPreferArchInfo
;
844 myArch
= NXGetLocalArchInfo();
846 arch
= NXFindBestFatArch(myArch
->cputype
, myArch
->cpusubtype
,
847 (struct fat_arch
*) &fat
[1], fat
->nfat_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
;
857 file
->fSwapped
= kld_macho_swap((struct mach_header
*) file
->fMachO
);
859 magic
= ((const struct mach_header
*) file
->fMachO
)->magic
;
863 return_if(magic
!= MH_MAGIC
,
864 false, ("%s isn't a valid mach-o (magic is %08x)\n", pathName
, magic
));
869 // This function can only operate on segments from 32 bit mach-o files
871 parseSegments(struct fileRecord
*file
, struct segment_command
*seg
)
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];
880 if (!file
->fSectData
) {
881 file
->fSectData
= DataCreate(0);
882 if (!file
->fSectData
)
886 // Increase length of section DataRef and cache data pointer
887 if (!DataAddLength(file
->fSectData
, nsects
* sizeof(struct sectionRecord
)))
889 file
->fSections
= (struct sectionRecord
*) DataGetPtr(file
->fSectData
);
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
++)
896 sections
[i
].fSection
= &segMap
->sect
[i
];
897 file
->fIsReloc
|= (0 != segMap
->sect
[i
].nreloc
);
904 remangleExternSymbols(struct fileRecord
*file
, const char *pathName
)
906 const struct nlist
*sym
;
908 DataRef strings
= NULL
;
910 DEBUG_LOG(("Remangling %s\n", pathName
));
912 file
->fNewStringBlocks
= DataCreate(0);
913 return_if(!file
->fNewStringBlocks
, false,
914 ("Unable to allocate new string table for %s\n", pathName
));
916 nsyms
= file
->fSymtab
->nsyms
;
917 for (i
= 0, sym
= file
->fSymbolBase
; i
< nsyms
; i
++, sym
++) {
921 unsigned char n_type
= sym
->n_type
;
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
))
927 symname
= symNameByIndex(file
, i
);
931 strings
= DataCreate(16 * 1024); // Arbitrary block size
932 return_if(!strings
, false,
933 ("Unable to allocate new string block for %s\n", pathName
));
936 len
= DataRemaining(strings
);
937 newname
= DataGetEndPtr(strings
);
938 ret
= rem3_remangle_name(newname
, &len
, symname
);
940 case kR3InternalNotRemangled
:
941 errprintf("Remangler fails on %s in %s\n", symname
, pathName
);
943 case kR3NotRemangled
:
947 file
->fSymbToStringTable
[i
] = newname
;
948 file
->fRemangled
= file
->fSymbolsDirty
= true;
949 DataAddLength(strings
, len
+ 1); // returns strlen
952 case kR3BufferTooSmallRemangled
:
953 return_if(!DataAppendBytes
954 (file
->fNewStringBlocks
, &strings
, sizeof(strings
)),
955 false, ("Unable to allocate string table for %s\n", pathName
));
957 goto tryRemangleAgain
;
961 return_if(true, false,
962 ("Internal error - remangle of %s\n", pathName
));
967 return_if(!DataAppendBytes
968 (file
->fNewStringBlocks
, &strings
, sizeof(strings
)),
969 false, ("Unable to allocate string table for %s\n", pathName
));
975 // This function can only operate on symbol table files from 32 bit
977 static Boolean
parseSymtab(struct fileRecord
*file
, const char *pathName
)
980 unsigned int i
, firstlocal
, nsyms
;
981 unsigned long strsize
;
983 Boolean foundOSObject
, found295CPP
, havelocal
;
985 // we found a link edit segment so recompute the bases
986 if (file
->fLinkEditSeg
) {
987 struct segment_command
*link
= file
->fLinkEditSeg
;
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
));
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
));
1007 nsyms
= file
->fSymtab
->nsyms
;
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);
1013 // Generate a table of pointers to strings indexed by the symbol number
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
);
1021 // Search for the first non-stab symbol in table
1022 strsize
= file
->fSymtab
->strsize
;
1023 strbase
= file
->fStringBase
;
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
;
1032 return_if(((unsigned long) strx
> strsize
), false,
1033 ("%s has an illegal string offset in symbol %d\n", pathName
, i
));
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
;
1044 if (file
->fIsIncrLink
&& !file
->fNSects
)
1047 struct nlist
*patchsym
= sym
;
1048 const char * lookname
;
1049 const struct nlist
* realsym
;
1051 if ( (patchsym
->n_type
& N_TYPE
) == N_INDR
)
1052 lookname
= strbase
+ patchsym
->n_value
;
1055 realsym
= findSymbolByName(sKernelFile
, lookname
);
1057 patchsym
->n_sect
= NO_SECT
;
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
;
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;
1075 if (!havelocal
&& (patchsym
->n_type
& N_EXT
)) {
1078 file
->fLocalSyms
= patchsym
;
1083 // Load up lookup symbol look table with sym names
1084 file
->fSymbToStringTable
[i
] = symname
;
1086 n_type
= sym
->n_type
& (N_TYPE
| N_EXT
);
1088 // Find the first exported symbol
1089 if ( !firstlocal
&& (n_type
& N_EXT
) ) {
1092 file
->fLocalSyms
= sym
;
1095 // Find the a OSObject based subclass by searching for symbols
1096 // that have a suffix of '10superClassE'
1097 symname
++; // Skip leading '_'
1100 && (n_type
== (N_SECT
| N_EXT
) || n_type
== (N_ABS
| N_EXT
))
1102 const char *suffix
, *endSym
;
1104 endSym
= symname
+ strlen(symname
);
1106 // Find out if this symbol has the superclass suffix.
1107 if (symname
[0] == kCPPSymbolPrefix
[0]
1108 && symname
[1] == kCPPSymbolPrefix
[1]) {
1110 suffix
= endSym
- sizeof(k31SuperClassSuffix
) + 1;
1112 // Check for a gcc3 OSObject subclass
1113 if (suffix
> symname
1114 && !strcmp(suffix
, k31SuperClassSuffix
))
1115 foundOSObject
= true;
1118 suffix
= endSym
- sizeof(k29SuperClassSuffix
);
1120 // Check for a gcc295 OSObject subclass
1121 if (suffix
> symname
1122 && ('.' == *suffix
|| '$' == *suffix
)
1123 && !strcmp(suffix
+1, k29SuperClassSuffix
)) {
1124 found295CPP
= foundOSObject
= true;
1126 else if (!found295CPP
) {
1127 // Finally just check if we need to remangle
1128 symname
++; // skip leading '__'
1130 if ('_' == symname
[0] && '_' == symname
[1]) {
1139 else if (sym
->n_type
== (N_EXT
| N_UNDF
)) {
1140 if ( !file
->fNLocal
) // Find the last local symbol
1141 file
->fNLocal
= i
- firstlocal
;
1143 symname
++; // Skip possible second '_' at start.
1145 if ('_' == symname
[0] && '_' == symname
[1]) {
1153 // Note symname is trashed at this point
1155 return_if(i
< nsyms
, false,
1156 ("%s isn't a valid mach-o, bad symbol strings\n", pathName
));
1158 return_if(!file
->fLocalSyms
, false, ("%s has no symbols?\n", pathName
));
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
;
1165 file
->fFoundOSObject
= foundOSObject
;
1167 if (found295CPP
&& !remangleExternSymbols(file
, pathName
))
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
)
1178 // not quite so dumb linear search of all symbols
1182 // First try to find the symbol in the most likely place which is the
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
) )
1190 // Didn't find it in the external symbols so try to local symbols before
1192 sym
= file
->fSymbolBase
;
1193 for (i
= 0, nsyms
= file
->fSymtab
->nsyms
; i
< nsyms
; i
++, sym
++) {
1194 if ( (sym
->n_type
& N_EXT
) )
1196 if ( sym
->n_value
== (unsigned long) entry
&& !(sym
->n_type
& N_STAB
) )
1203 static struct nlist
*
1204 findSymbolByAddressInAllFiles(__unused
const struct fileRecord
* fromFile
,
1205 void *entry
, const struct fileRecord
**resultFile
)
1208 struct fileRecord
**files
;
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
))
1219 struct nlist
* result
;
1221 *resultFile
= files
[i
];
1222 result
= findSymbolByAddress(files
[i
], entry
);
1231 struct searchContext
{
1232 const char *fSymname
;
1233 const struct fileRecord
*fFile
;
1236 static int symbolSearch(const void *vKey
, const void *vSym
)
1238 const struct searchContext
*key
= (const struct searchContext
*) vKey
;
1239 const struct nlist
*sym
= (const struct nlist
*) vSym
;
1241 return strcmp(key
->fSymname
, symbolname(key
->fFile
, sym
));
1244 static const struct nlist
*
1245 findSymbolByName(struct fileRecord
*file
, const char *symname
)
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
;
1254 for (sym
= file
->fLocalSyms
; i
< nLocal
; i
++, sym
++)
1255 if (!strcmp(symNameByIndex(file
, i
), symname
))
1260 struct searchContext context
;
1262 context
.fSymname
= symname
;
1263 context
.fFile
= file
;
1264 return (const struct nlist
*)
1266 file
->fLocalSyms
, file
->fNLocal
, sizeof(struct nlist
),
1272 relocateSection(struct fileRecord
*file
, struct sectionRecord
*sectionRec
)
1274 struct nlist
*symbol
;
1275 const struct section
*section
;
1276 struct relocRecord
*rec
;
1277 struct relocation_info
*rinfo
;
1279 unsigned long r_address
, r_symbolnum
, r_length
;
1280 enum reloc_type_generic r_type
;
1284 sectionRec
->fRelocCache
= DataCreate(
1285 sectionRec
->fSection
->nreloc
* sizeof(struct relocRecord
));
1286 if (!sectionRec
->fRelocCache
)
1289 section
= sectionRec
->fSection
;
1290 sectionBase
= file
->fMachO
+ section
->offset
;
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
++) {
1296 // Totally uninterested in scattered relocation entries
1297 if ( (rinfo
->r_address
& R_SCATTERED
) )
1300 r_address
= rinfo
->r_address
;
1301 entry
= (void **) (sectionBase
+ r_address
);
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).
1309 return_if(r_address
>= section
->size
, false,
1310 ("Invalid relocation entry in %s - not in section\n", file
->fPath
));
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)
1319 r_symbolnum
= rinfo
->r_symbolnum
;
1322 * If rinfo->r_extern is set this relocation entry is an external entry
1323 * else it is a local entry.
1325 if (rinfo
->r_extern
) {
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.
1332 return_if(r_symbolnum
>= file
->fSymtab
->nsyms
, false,
1333 ("Invalid relocation entry in %s - no symbol\n", file
->fPath
));
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).
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
];
1345 return_if(symbol
->n_type
!= (N_EXT
| N_UNDF
), false,
1346 ("Invalid relocation entry in %s - extern\n", file
->fPath
));
1349 void * addr
= *entry
;
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.
1354 if (r_symbolnum
== R_ABS
)
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
));
1361 // Find the symbol, if any, that backs this entry
1364 addr
= (void *) OSSwapInt32((uint32_t) addr
);
1366 symbol
= findSymbolByAddress(file
, addr
);
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
1373 *entry
= (void *) rec
; // Save pointer to record in object image
1376 DataSetLength(sectionRec
->fRelocCache
, i
* sizeof(struct relocRecord
));
1377 file
->fImageDirty
= true;
1382 static const struct nlist
*
1383 findSymbolRefAtLocation(struct fileRecord
*file
,
1384 struct sectionRecord
*sctn
, void **loc
, const struct fileRecord
**foundInFile
)
1386 const struct nlist
* result
;
1388 *foundInFile
= file
;
1390 if (!file
->fIsReloc
) {
1395 addr
= (void *) OSSwapInt32((uint32_t) addr
);
1397 result
= findSymbolByAddress(file
, addr
);
1399 result
= findSymbolByAddressInAllFiles(file
, addr
, foundInFile
);
1403 else if (sctn
->fRelocCache
|| relocateSection(file
, sctn
)) {
1404 struct relocRecord
*reloc
= (struct relocRecord
*) *loc
;
1406 if (DataContainsAddr(sctn
->fRelocCache
, reloc
))
1407 return reloc
->fSymbol
;
1414 addClass(struct fileRecord
*file
,
1415 struct metaClassRecord
*inClass
,
1418 Boolean result
= false;
1419 struct metaClassRecord
*newClass
= NULL
;
1420 struct metaClassRecord
**fileClasses
= NULL
;
1423 if (!file
->fClassList
) {
1424 file
->fClassList
= DataCreate(0);
1425 if (!file
->fClassList
)
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
);
1437 if (!DataAddLength(file
->fClassList
, sizeof(struct metaClassRecord
*)))
1439 fileClasses
= (struct metaClassRecord
**)
1440 (DataGetPtr(file
->fClassList
) + DataGetLength(file
->fClassList
));
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
;
1453 DataAddLength(file
->fClassList
, -sizeof(struct metaClassRecord
*));
1461 static struct metaClassRecord
*getClass(DataRef classList
, const char *cname
)
1465 struct metaClassRecord
**classes
, *thisClass
;
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
))
1479 // Add the class 'cname' to the list of known OSObject based classes
1480 // Note 'sym' is the <cname>10superClassE symbol.
1482 recordClass(struct fileRecord
*file
, const char *cname
, const struct nlist
*sym
)
1484 Boolean result
= false;
1485 char *supername
= NULL
;
1486 const char *classname
= NULL
;
1487 struct metaClassRecord newClass
;
1488 char strbuffer
[1024];
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
) {
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
;
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
) {
1513 sectionRec
= file
->fSections
+ sectind
- 1;
1514 section
= sectionRec
->fSection
;
1515 location
= (void **) ( file
->fMachO
+ section
->offset
1516 + sym
->n_value
- section
->addr
);
1518 supersym
= findSymbolRefAtLocation(file
, sectionRec
, location
, &superfile
);
1520 result
= true; // No superclass symbol then it isn't an OSObject.
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..
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';
1540 break_if(getClass(file
->fClassList
, cname
),
1541 ("Duplicate class %s in %s\n", cname
, file
->fPath
));
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
));
1548 newClass
.fFile
= file
;
1549 newClass
.fSuperName
= supername
;
1550 newClass
.fPatchedVTable
= NULL
;
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"));
1572 static Boolean
getMetaClassGraph(struct fileRecord
*file
)
1574 const struct nlist
*sym
;
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.
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>.
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
;
1594 char classname
[1024];
1595 unsigned char n_type
= sym
->n_type
& (N_TYPE
| N_EXT
);
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
)
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])
1610 suffix
= symname
+ strlen(symname
) - sizeof(k31SuperClassSuffix
) + 1;
1611 if (suffix
<= symname
|| strcmp(suffix
, k31SuperClassSuffix
))
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
));
1619 bcopy(symname
+ sizeof(kOSObjPrefix
) - 2, classname
, cnamelen
);
1620 classname
[cnamelen
] = '\0';
1621 if (!recordClass(file
, classname
, sym
))
1625 return_if(!file
->fClassList
, false, ("Internal error, "
1626 "getMetaClassGraph(%s) found no classes", file
->fPath
));
1628 DEBUG_LOG(("Found %ld classes in %p for %s\n",
1629 DataGetLength(file
->fClassList
)/sizeof(void*),
1630 file
->fClassList
, file
->fPath
));
1635 static Boolean
mergeOSObjectsForFile(const struct fileRecord
*file
)
1638 Boolean foundDuplicates
= false;
1640 DEBUG_LOG(("Merging file %s\n", file
->fPath
)); // @@@ gvdl:
1642 if (!file
->fClassList
)
1645 if (!sMergedFiles
) {
1646 sMergedFiles
= DataCreate(0);
1647 return_if(!sMergedFiles
, false,
1648 ("Unable to allocate memory metaclass list\n", file
->fPath
));
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
])
1658 if (!sMergeMetaClasses
) {
1659 sMergeMetaClasses
= DataCreate(0);
1660 return_if(!sMergeMetaClasses
, false,
1661 ("Unable to allocate memory metaclass list\n", file
->fPath
));
1663 else { /* perform a duplicate check */
1664 int k
, j
, cnt1
, cnt2
;
1665 struct metaClassRecord
**list1
, **list2
;
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
);
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
);
1679 foundDuplicates
= true;
1684 if (foundDuplicates
)
1687 return_if(!DataAppendBytes(sMergedFiles
, &file
, sizeof(file
)), false,
1688 ("Unable to allocate memory to merge %s\n", file
->fPath
));
1690 return_if(!DataAppendData(sMergeMetaClasses
, file
->fClassList
), false,
1691 ("Unable to allocate memory to merge %s\n", file
->fPath
));
1693 if (file
== sKernelFile
)
1694 sMergedKernel
= true;
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
,
1706 const struct section
*section
;
1707 unsigned char sectind
;
1708 unsigned char *base
;
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
;
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
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
));
1731 section
= file
->fSections
[sectind
- 1].fSection
;
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
);
1737 return base
- section
->addr
; // return with addr offset
1740 static Boolean
resolveKernelVTable(struct metaClassRecord
*metaClass
)
1742 const struct fileRecord
*file
;
1743 struct patchRecord
*patchedVTable
;
1744 void **curEntry
, **vtableEntries
, **endSection
;
1745 unsigned char *sectionBase
;
1746 struct patchRecord
*curPatch
;
1749 // Should never occur but it doesn't cost us anything to check.
1750 if (metaClass
->fPatchedVTable
)
1753 DEBUG_LOG(("Kernel vtable %s\n", metaClass
->fClassName
)); // @@@ gvdl:
1755 // Do we have a valid vtable to patch?
1756 return_if(!metaClass
->fVTableSym
,
1757 false, ("Internal error - no class vtable symbol?\n"));
1759 file
= metaClass
->fFile
;
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"));
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"));
1775 // We are going to need the base and the end
1776 sectionBase
= getSectionForSymbol(file
, metaClass
->fVTableSym
, &endSection
);
1777 if (-1 == (long) sectionBase
)
1780 vtableEntries
= (void **) (sectionBase
+ metaClass
->fVTableSym
->n_value
);
1781 curEntry
= vtableEntries
+ kVTablePreambleLen
;
1782 for (classSize
= 0; curEntry
< endSection
&& *curEntry
; classSize
++)
1785 return_if(*curEntry
, false, ("Bad kernel image, short section\n"));
1787 patchedVTable
= (struct patchRecord
*)
1788 malloc((classSize
+ 1) * sizeof(struct patchRecord
));
1789 return_if(!patchedVTable
, false, ("resolveKernelVTable - no memory\n"));
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
;
1798 addr
= (void *) OSSwapInt32((uint32_t) addr
);
1801 findSymbolByAddress(file
, addr
);
1802 if (curPatch
->fSymbol
)
1804 curPatch
->fType
= kSymbolLocal
;
1805 curPatch
->fFile
= file
;
1810 findSymbolByAddressInAllFiles(file
, addr
, &curPatch
->fFile
);
1811 if (!curPatch
->fSymbol
) {
1812 errprintf("%s: !findSymbolByAddressInAllFiles(%p)\n",
1816 curPatch
->fType
= kSymbolLocal
;
1820 // Tag the end of the patch vtable
1821 curPatch
->fSymbol
= NULL
;
1822 metaClass
->fPatchedVTable
= patchedVTable
;
1827 static char *addNewString(struct fileRecord
*file
,
1828 const char *strname
, unsigned int namelen
)
1830 DataRef strings
= 0;
1833 namelen
++; // Include terminating '\0';
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
)
1845 file
->fNewStringBlocks
= DataCreate(0);
1846 return_if(!file
->fNewStringBlocks
, NULL
,
1847 ("Unable to allocate new string table %s\n", file
->fPath
));
1851 int size
= (namelen
+ 1023) & ~1023;
1852 if (size
< 16 * 1024)
1854 strings
= DataCreate(size
);
1855 return_if(!strings
, NULL
,
1856 ("Unable to allocate new string block %s\n", file
->fPath
));
1858 !DataAppendBytes(file
->fNewStringBlocks
, &strings
, sizeof(strings
)),
1859 false, ("Unable to allocate string table for %s\n", file
->fPath
));
1862 newStr
= DataGetEndPtr(strings
);
1863 DataAppendBytes(strings
, strname
, namelen
);
1867 // reloc->fPatch must contain a valid pointer
1868 static struct nlist
*
1869 getNewSymbol(struct fileRecord
*file
,
1870 struct relocRecord
*reloc
, const char *supername
)
1872 unsigned int size
, i
;
1875 struct relocation_info
*rinfo
;
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
));
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;
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.
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
)));
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
;
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;
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
));
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
));
1927 newStr
= addNewString(file
, supername
, strlen(supername
));
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
);
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
;
1942 msym
->n_value
= (unsigned long) newStr
;
1944 rinfo
->r_symbolnum
= i
+ file
->fSymtab
->nsyms
;
1945 file
->fSymbolsDirty
= true;
1949 static struct nlist
*
1950 fixOldSymbol(struct fileRecord
*file
,
1951 const struct relocRecord
*reloc
, const char *supername
)
1953 unsigned int namelen
, oldnamelen
;
1954 struct nlist
*sym
= (struct nlist
*) reloc
->fSymbol
;
1955 char *oldname
= symbolname(file
, sym
);
1957 // assert(sym->n_un.n_strx >= 0);
1959 namelen
= strlen(supername
);
1961 sym
->n_un
.n_strx
= -sym
->n_un
.n_strx
;
1962 if (oldname
&& namelen
< (oldnamelen
= strlen(oldname
)))
1964 // Overwrite old string in string table
1965 strlcpy((char *) oldname
, supername
, oldnamelen
+ 1);
1966 file
->fSymbolsDirty
= true;
1970 oldname
= addNewString(file
, supername
, namelen
);
1974 file
->fSymbToStringTable
[sym
- file
->fSymbolBase
] = oldname
;
1975 file
->fSymbolsDirty
= true;
1979 static enum patchState
1980 symbolCompare(const struct fileRecord
*file
,
1981 const struct nlist
*classsym
,
1982 const char *supername
)
1984 const char *classname
;
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
;
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
;
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
;
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
;
2011 return kSymbolSuperUpdate
;
2014 static Boolean
patchVTable(struct metaClassRecord
*metaClass
)
2016 struct metaClassRecord
*super
= NULL
;
2017 struct fileRecord
*file
;
2018 struct patchRecord
*patchedVTable
;
2019 struct relocRecord
**curReloc
, **vtableRelocs
, **endSection
;
2020 unsigned char *sectionBase
;
2023 // Should never occur but it doesn't cost us anything to check.
2024 if (metaClass
->fPatchedVTable
)
2027 // Do we have a valid vtable to patch?
2028 return_if(!metaClass
->fVTableSym
,
2029 false, ("Internal error - no class vtable symbol?\n"));
2031 file
= metaClass
->fFile
;
2033 if (!file
->fIsReloc
)
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.
2041 res
= resolveKernelVTable(metaClass
);
2045 if (!metaClass
->fSuperName
)
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
));
2054 // Superclass recursion if necessary
2055 if (!super
->fPatchedVTable
) {
2057 res
= patchVTable(super
);
2062 DEBUG_LOG(("Patching %s\n", metaClass
->fClassName
)); // @@@ gvdl:
2064 // We are going to need the base and the end
2066 sectionBase
= getSectionForSymbol(file
,
2067 metaClass
->fVTableSym
, (void ***) &endSection
);
2068 if (-1 == (long) sectionBase
)
2071 vtableRelocs
= (struct relocRecord
**)
2072 (sectionBase
+ metaClass
->fVTableSym
->n_value
);
2073 curReloc
= vtableRelocs
+ kVTablePreambleLen
;
2074 for (classSize
= 0; curReloc
< endSection
&& *curReloc
; classSize
++)
2077 return_if(*curReloc
, false,
2078 ("%s isn't a valid kext, short section\n", file
->fPath
));
2080 patchedVTable
= (struct patchRecord
*)
2081 malloc((classSize
+ 1) * sizeof(struct patchRecord
));
2082 return_if(!patchedVTable
, false, ("patchedVTable - no memory\n"));
2085 struct patchRecord
*curPatch
;
2086 struct nlist
*symbol
;
2088 curPatch
= patchedVTable
;
2089 curReloc
= vtableRelocs
+ kVTablePreambleLen
;
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
;
2097 spp
= super
->fPatchedVTable
;
2099 for ( ; spp
->fSymbol
; curReloc
++, spp
++, curPatch
++) {
2100 const char *supername
=
2101 symbolname(spp
->fFile
, spp
->fSymbol
);
2103 symbol
= (struct nlist
*) (*curReloc
)->fSymbol
;
2105 curPatch
->fType
= symbolCompare(file
, symbol
, supername
);
2106 switch (curPatch
->fType
) {
2107 case kSymbolIdentical
:
2111 case kSymbolSuperUpdate
:
2112 symbol
= getNewSymbol(file
, (*curReloc
), supername
);
2115 case kSymbolPadUpdate
:
2116 symbol
= fixOldSymbol(file
, (*curReloc
), supername
);
2119 case kSymbolMismatch
:
2120 errprintf("%s is not compatible with its superclass, "
2121 "%s superclass changed?\n",
2122 metaClass
->fClassName
, super
->fClassName
);
2126 errprintf("Internal error - unknown patch type\n");
2130 curPatch
->fSymbol
= symbol
;
2131 (*curReloc
)->fSymbol
= symbol
;
2132 curPatch
->fFile
= file
;
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
;
2147 // Tag the end of the patch vtable
2148 curPatch
->fSymbol
= NULL
;
2150 metaClass
->fPatchedVTable
= patchedVTable
;
2156 free(patchedVTable
);
2161 static Boolean
growImage(struct fileRecord
*file
, vm_size_t delta
)
2164 file
->fMachOSize
+= delta
;
2165 return (file
->fMachO
+ file
->fMachOSize
<= file
->fPadEnd
);
2167 vm_address_t startMachO
, endMachO
, endMap
;
2168 vm_offset_t newMachO
;
2170 unsigned long i
, last
= 0;
2171 struct metaClassRecord
**classes
= NULL
;
2172 struct sectionRecord
*section
;
2175 startMachO
= (vm_address_t
) file
->fMachO
;
2176 endMachO
= startMachO
+ file
->fMachOSize
+ delta
;
2177 endMap
= (vm_address_t
) file
->fMap
+ file
->fMapSize
;
2179 // Do we have room in the current mapped image
2180 if (endMachO
< round_page_32(endMap
)) {
2181 file
->fMachOSize
+= delta
;
2185 newsize
= endMachO
- startMachO
;
2186 if (newsize
< round_page_32(file
->fMapSize
)) {
2187 DEBUG_LOG(("Growing image %s by moving\n", file
->fPath
));
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
);
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
,
2201 if (KERN_SUCCESS
!= ret
)
2204 // If the mapping didn't move then just return
2205 if ((vm_address_t
) file
->fMap
== newMachO
) {
2206 file
->fMachOSize
= file
->fMapSize
= newsize
;
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.
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
);
2221 if (KERN_SUCCESS
!= ret
)
2223 bcopy((char *) startMachO
, (void *) newMachO
, file
->fMachOSize
);
2224 file
->fIsKmem
= true;
2228 file
->fMap
= file
->fMachO
= (unsigned char *) newMachO
;
2229 file
->fMapSize
= newsize
;
2230 file
->fMachOSize
+= delta
; // Increment the image size
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.
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
;
2246 // Rebase the cached-in object 'struct symtab_command' pointer
2247 REBASE(file
->fSymtab
, delta
);
2249 // Rebase the cached-in object 'struct nlist' pointer for all symbols
2250 REBASE(file
->fSymbolBase
, delta
);
2252 // Rebase the cached-in object 'struct nlist' pointer for local symbols
2253 REBASE(file
->fLocalSyms
, delta
);
2255 // Rebase the cached-in object 'char' pointer for the string table
2256 REBASE(file
->fStringBase
, delta
);
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
);
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
;
2274 for (patch
= classes
[i
]->fPatchedVTable
; patch
->fSymbol
; patch
++) {
2275 vm_address_t symAddr
= (vm_address_t
) patch
->fSymbol
;
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
);
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
);
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
2299 prepareFileForLink(struct fileRecord
*file
)
2301 unsigned long i
, last
, numnewsyms
, newsymsize
, newstrsize
;
2302 struct sectionRecord
*section
;
2303 struct nlist
**symp
, *sym
;
2304 DataRef newStrings
, *stringBlocks
;
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
) {
2310 if (file
->fSwapped
) {
2311 kld_macho_unswap((struct mach_header
*) file
->fMachO
, file
->fSwapped
, false);
2312 file
->fSwapped
= false;
2318 DEBUG_LOG(("Linking 2 %s\n", file
->fPath
)); // @@@ gvdl:
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
;
2328 if (section
->fRelocCache
) {
2329 sectionBase
= file
->fMachO
+ section
->fSection
->offset
;
2330 nreloc
= section
->fSection
->nreloc
;
2331 rec
= (struct relocRecord
*) DataGetPtr(section
->fRelocCache
);
2333 // We will need to repair the reloc list
2334 for (j
= 0; j
< nreloc
; j
++, rec
++) {
2336 struct nlist
*repairSym
;
2338 return_if(!rec
->fRInfo
, false,
2339 ("Bad Mach-O file; cannot link\n"));
2341 // Repair Damage to object image
2342 entry
= (void **) (sectionBase
+ rec
->fRInfo
->r_address
);
2343 *entry
= rec
->fValue
;
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
;
2356 // Clean up the fRelocCache we don't need it any more.
2357 DataRelease(section
->fRelocCache
);
2358 section
->fRelocCache
= 0;
2361 file
->fImageDirty
= false; // Image is clean
2363 // If we didn't dirty the symbol table then just return
2364 if (!file
->fSymbolsDirty
) {
2366 if (file
->fSwapped
) {
2367 kld_macho_unswap((struct mach_header
*) file
->fMachO
, file
->fSwapped
, false);
2368 file
->fSwapped
= false;
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
);
2383 numnewsyms
/= sizeof(struct nlist
*);
2384 file
->fSymtab
->nsyms
+= numnewsyms
;
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"));
2393 newsymsize
= numnewsyms
* sizeof(struct nlist
);
2394 file
->fStringBase
+= newsymsize
;
2395 file
->fSymtab
->stroff
+= newsymsize
;
2397 last
= file
->fSymtab
->nsyms
- numnewsyms
;
2399 DataAppendBytes(newStrings
, &newstrsize
, 4); // Leading nuls
2400 sym
= file
->fSymbolBase
;
2402 // Pre-compute an already offset new symbol pointer. The offset is the
2403 // orignal symbol table.
2405 for (i
= 0; i
< file
->fSymtab
->nsyms
; i
++, sym
++) {
2406 const char *str
= symNameByIndex(file
, i
);
2407 int len
= strlen(str
) + 1;
2410 // Rebase sym in the new symbol region
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
;
2423 // Repair the symbol for the getNewSymbol case.
2424 if (-1 == sym
->n_un
.n_strx
)
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"));
2432 sym
->n_un
.n_strx
= strx
;
2433 file
->fSymbToStringTable
[i
] = file
->fStringBase
+ strx
;
2437 // Don't need the new strings any more
2439 if (file
->fNewStringBlocks
){
2440 last
= DataGetLength(file
->fNewStringBlocks
) / sizeof(DataRef
);
2441 stringBlocks
= (DataRef
*) DataGetPtr(file
->fNewStringBlocks
);
2448 for (i
= 0; i
< last
; i
++)
2449 DataRelease(stringBlocks
[i
]);
2451 DataRelease(file
->fNewStringBlocks
);
2452 file
->fNewStringBlocks
= 0;
2454 newstrsize
= DataGetLength(newStrings
);
2455 newstrsize
= (newstrsize
+ 3) & ~3; // Round to nearest word
2457 !growImage(file
, newsymsize
+ newstrsize
- file
->fSymtab
->strsize
),
2458 false, ("Unable to patch the extension, no memory\n", file
->fPath
));
2460 // Push out the new symbol table if necessary
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
));
2471 DataRelease(file
->fNewSymbols
);
2472 file
->fNewSymbols
= 0;
2475 // Push out the new string table if necessary
2477 unsigned long *base
= (unsigned long *) file
->fStringBase
;
2478 unsigned long actuallen
= DataGetLength(newStrings
);
2480 // Set the last word in string table to zero before copying data
2481 base
[(newstrsize
/ sizeof(unsigned long)) - 1] = 0;
2483 // Now copy the new strings back to the end of the file
2484 bcopy((caddr_t
) DataGetPtr(newStrings
), file
->fStringBase
, actuallen
);
2486 file
->fSymtab
->strsize
= newstrsize
;
2488 DataRelease(newStrings
);
2491 file
->fSymbolsDirty
= false;
2493 if (file
->fSwapped
) {
2494 kld_macho_unswap((struct mach_header
*) file
->fMachO
, file
->fSwapped
, false);
2495 file
->fSwapped
= false;
2501 // This function can only operate on 32 bit mach-o files
2504 kld_file_map(const char *pathName
,
2509 kld_file_map(const char *pathName
)
2512 struct fileRecord file
, *fp
= 0;
2514 // Already done no need to repeat
2515 fp
= getFile(pathName
);
2519 bzero(&file
, sizeof(file
));
2523 file
.fMapSize
= mapSize
;
2524 file
.fIsKmem
= isKmem
;
2526 if (!mapObjectFile(&file
, pathName
))
2531 struct machOMapping
{
2532 struct mach_header h
;
2533 struct load_command c
[1];
2535 struct load_command
*cmd
;
2536 boolean_t lookVMRange
;
2539 if (!findBestArch(&file
, pathName
))
2542 machO
= (struct machOMapping
*) file
.fMachO
;
2543 if (file
.fMachOSize
< machO
->h
.sizeofcmds
)
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
);
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
;
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
;
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
;
2573 return_if(!parseSegments(&file
, seg
),
2574 false, ("%s isn't a valid mach-o, bad segment",
2577 if (file
.fIsKernel
) {
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
;
2586 cmd
= (struct load_command
*) ((UInt8
*) cmd
+ cmd
->cmdsize
);
2588 break_if(!file
.fSymtab
,
2589 ("%s isn't a valid mach-o, no symbols\n", pathName
));
2591 if (machO
->h
.flags
& MH_INCRLINK
) {
2593 file
.fIsIncrLink
= true;
2594 machO
->h
.flags
&= ~MH_INCRLINK
;
2597 // the symtab fileoffset is the end of seg0's vmsize,
2598 // which can be (rarely) unaligned.
2600 align
= file
.fSymtab
->symoff
% sizeof(long);
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
;
2613 if (!parseSymtab(&file
, pathName
))
2616 fp
= addFile(&file
, pathName
);
2620 if (file
.fFoundOSObject
&& !getMetaClassGraph(fp
))
2627 // Automatically load the kernel's link edit segment if we are
2628 // attempting to load a driver.
2630 struct segment_command
*sg
;
2634 sg
= (struct segment_command
*) getsegbyname(kLinkEditSegName
);
2635 break_if(!sg
, ("Can't find kernel link edit segment\n"));
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"));
2648 // Failure path, then clean up
2650 // @@@ gvdl: for the time being leak the file ref in the file table
2658 void *kld_file_getaddr(const char *pathName
, unsigned long *size
)
2660 struct fileRecord
*file
= getFile(pathName
);
2666 *size
= file
->fMachOSize
;
2668 return file
->fMachO
;
2671 void *kld_file_lookupsymbol(const char *pathName
, const char *symname
)
2673 struct fileRecord
*file
= getFile(pathName
);
2674 const struct nlist
*sym
;
2675 const struct section
*section
;
2676 unsigned char *sectionBase
;
2677 unsigned char sectind
;
2680 NULL
, ("Unknown file %s\n", pathName
));
2682 sym
= findSymbolByName(file
, symname
);
2684 // May be a non-extern symbol so look for it there
2686 unsigned int i
, nsyms
;
2688 sym
= file
->fSymbolBase
;
2689 for (i
= 0, nsyms
= file
->fSymtab
->nsyms
; i
< nsyms
; i
++, sym
++) {
2690 if ( (sym
->n_type
& N_EXT
) ) {
2692 break; // Terminate search when we hit an extern
2694 if ( (sym
->n_type
& N_STAB
) )
2696 if ( !strcmp(symname
, symNameByIndex(file
, i
)) )
2702 NULL
, ("Unknown symbol %s in %s\n", symname
, pathName
));
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
));
2710 section
= file
->fSections
[sectind
- 1].fSection
;
2711 sectionBase
= file
->fMachO
+ section
->offset
- section
->addr
;
2713 return (void *) (sectionBase
+ sym
->n_value
);
2716 Boolean
kld_file_merge_OSObjects(const char *pathName
)
2718 struct fileRecord
*file
= getFile(pathName
);
2721 false, ("Internal error - unable to find file %s\n", pathName
));
2723 return mergeOSObjectsForFile(file
);
2726 Boolean
kld_file_patch_OSObjects(const char *pathName
)
2728 struct fileRecord
*file
= getFile(pathName
);
2729 struct metaClassRecord
**classes
;
2730 unsigned long i
, last
;
2733 false, ("Internal error - unable to find file %s\n", pathName
));
2735 DEBUG_LOG(("Patch file %s\n", pathName
)); // @@@ gvdl:
2737 // If we don't have any classes we can return now.
2738 if (!file
->fClassList
)
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"));
2746 if (!mergeOSObjectsForFile(file
))
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
;
2766 Boolean
kld_file_prepare_for_link(void)
2769 unsigned long i
, nmerged
= 0;
2770 struct fileRecord
**files
;
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
]))
2781 // Clear down the meta class table and merged file lists
2782 DataRelease(sMergeMetaClasses
);
2783 DataRelease(sMergedFiles
);
2784 sMergedFiles
= sMergeMetaClasses
= NULL
;
2785 sMergedKernel
= false;
2790 void kld_file_cleanup_all_resources(void)
2792 unsigned long i
, nfiles
;
2794 #if KERNEL // @@@ gvdl:
2795 // Debugger("kld_file_cleanup_all_resources");
2798 if (!sFilesTable
|| !(nfiles
= DataGetLength(sFilesTable
)))
2799 return; // Nothing to do just return now
2801 nfiles
/= sizeof(struct fileRecord
*);
2802 for (i
= 0; i
< nfiles
; i
++)
2803 removeFile(((void **) DataGetPtr(sFilesTable
))[i
]);
2805 DataRelease(sFilesTable
);
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.
2815 static const struct fileRecord
*sortFile
;
2816 static int symCompare(const void *vSym1
, const void *vSym2
)
2818 const struct nlist
*sym1
= vSym1
;
2819 const struct nlist
*sym2
= vSym2
;
2822 unsigned int ind1
, ind2
;
2824 ind1
= sym1
->n_type
& N_TYPE
;
2825 ind2
= sym2
->n_type
& N_TYPE
;
2827 // if sym1 is undefined then sym1 must come later than sym2
2830 // if sym2 is undefined then sym1 must come earlier than sym2
2833 /* drop out if neither are undefined */
2838 const struct fileRecord
*file
= sortFile
;
2839 const char *name1
, *name2
;
2841 name1
= file
->fStringBase
+ sym1
->n_un
.n_strx
;
2842 name2
= file
->fStringBase
+ sym2
->n_un
.n_strx
;
2843 return strcmp(name1
, name2
);
2848 Boolean
kld_file_debug_dump(const char *pathName
, const char *outName
)
2850 const struct fileRecord
*file
= getFile(pathName
);
2852 Boolean ret
= false;
2854 return_if(!file
, false, ("Unknown file %s for dumping\n", pathName
));
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
));
2862 // Sorting doesn't work until I fix the relocs too?
2864 // sort the symbol table appropriately
2865 unsigned int nsyms
= file
->fSymtab
->nsyms
2866 - (file
->fLocalSyms
- file
->fSymbolBase
);
2868 heapsort((void *) file
->fLocalSyms
, nsyms
, sizeof(struct nlist
),
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
));
2883 #endif /* !KERNEL */