The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/libsa/kld_patch.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 2bcc911fac619153dd955ce0be3d0fa1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.