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

Cache object: 3fc3705439dc6023a6a8632f0e426b73


[ 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.