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

Cache object: 95c03a14c727e332909bb2d9f6f393e6


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