]> git.saurik.com Git - apple/xnu.git/blobdiff - libkern/kxld/kxld_vtable.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / libkern / kxld / kxld_vtable.c
index 24408145b3d535ab83ab0e941ae8e4917507a403..634c19d4deafd78dc52f3bc98a05b3c31516738d 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 2008 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
- * 
+ *
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -22,7 +22,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 #include <string.h>
@@ -31,7 +31,7 @@
 
 #if KERNEL
     #ifdef MACH_ASSERT
-        #undef MACH_ASSERT
+       #undef MACH_ASSERT
     #endif
     #define MACH_ASSERT 1
     #include <kern/assert.h>
@@ -66,8 +66,8 @@ static void  get_vtable_base_sizes(boolean_t is_32_bit, u_int *vtable_entry_size
 static kern_return_t init_by_relocs(KXLDVTable *vtable, const KXLDSym *vtable_sym,
     const KXLDSect *sect, const KXLDRelocator *relocator);
 
-static kern_return_t init_by_entries_and_relocs(KXLDVTable *vtable, 
-    const KXLDSym *vtable_sym, const KXLDRelocator *relocator, 
+static kern_return_t init_by_entries_and_relocs(KXLDVTable *vtable,
+    const KXLDSym *vtable_sym, const KXLDRelocator *relocator,
     const KXLDArray *relocs, const KXLDDict *defined_cxx_symbols);
 
 static kern_return_t init_by_entries(KXLDVTable *vtable,
@@ -75,87 +75,91 @@ static kern_return_t init_by_entries(KXLDVTable *vtable,
 
 /*******************************************************************************
 *******************************************************************************/
-kern_return_t 
-kxld_vtable_init(KXLDVTable *vtable, const KXLDSym *vtable_sym, 
+kern_return_t
+kxld_vtable_init(KXLDVTable *vtable, const KXLDSym *vtable_sym,
     const KXLDObject *object, const KXLDDict *defined_cxx_symbols)
 {
-    kern_return_t rval = KERN_FAILURE;
-    const KXLDArray *extrelocs = NULL;
-    const KXLDRelocator *relocator = NULL;
-    const KXLDSect *vtable_sect = NULL;
-    char *demangled_name = NULL;
-    size_t demangled_length = 0;
-
-    check(vtable);
-    check(vtable_sym);
-    check(object);
-
-    relocator = kxld_object_get_relocator(object);
-
-    vtable_sect = kxld_object_get_section_by_index(object, 
-        vtable_sym->sectnum);
-    require_action(vtable_sect, finish, rval=KERN_FAILURE);
-
-    vtable->name = vtable_sym->name;
-    vtable->vtable = vtable_sect->data + 
-        kxld_sym_get_section_offset(vtable_sym, vtable_sect);
-
-    if (kxld_object_is_linked(object)) {
-        rval = init_by_entries(vtable, relocator, defined_cxx_symbols);
-        require_noerr(rval, finish);
-
-        vtable->is_patched = TRUE;
-    } else {
-        if (kxld_object_is_final_image(object)) {
-            extrelocs = kxld_object_get_extrelocs(object);
-            require_action(extrelocs, finish,
-                rval=KERN_FAILURE;
-                kxld_log(kKxldLogPatching, kKxldLogErr, 
-                    kKxldLogMalformedVTable, 
-                    kxld_demangle(vtable->name, 
-                        &demangled_name, &demangled_length)));
-
-            rval = init_by_entries_and_relocs(vtable, vtable_sym, 
-                relocator, extrelocs, defined_cxx_symbols);
-            require_noerr(rval, finish);
-        } else {
-            require_action(kxld_sect_get_num_relocs(vtable_sect) > 0, finish,
-                rval=KERN_FAILURE;
-                kxld_log(kKxldLogPatching, kKxldLogErr, 
-                    kKxldLogMalformedVTable, 
-                    kxld_demangle(vtable->name, 
-                        &demangled_name, &demangled_length)));
-
-            rval = init_by_relocs(vtable, vtable_sym, vtable_sect, relocator);
-            require_noerr(rval, finish);
-        }
-        
-        vtable->is_patched = FALSE;
-    }
-
-    rval = KERN_SUCCESS;
+       kern_return_t rval = KERN_FAILURE;
+       const KXLDArray *extrelocs = NULL;
+       const KXLDRelocator *relocator = NULL;
+       const KXLDSect *vtable_sect = NULL;
+       char *demangled_name = NULL;
+       size_t demangled_length = 0;
+
+       check(vtable);
+       check(vtable_sym);
+       check(object);
+
+       relocator = kxld_object_get_relocator(object);
+
+       vtable_sect = kxld_object_get_section_by_index(object,
+           vtable_sym->sectnum);
+       require_action(vtable_sect, finish, rval = KERN_FAILURE);
+
+       vtable->name = vtable_sym->name;
+       vtable->vtable = vtable_sect->data +
+           kxld_sym_get_section_offset(vtable_sym, vtable_sect);
+
+       if (kxld_object_is_linked(object)) {
+               rval = init_by_entries(vtable, relocator, defined_cxx_symbols);
+               require_noerr(rval, finish);
+
+               vtable->is_patched = TRUE;
+       } else {
+               if (kxld_object_is_final_image(object)) {
+                       extrelocs = kxld_object_get_extrelocs(object);
+
+                       require_action(extrelocs, finish,
+                           rval = KERN_FAILURE;
+                           kxld_log(kKxldLogPatching, kKxldLogErr,
+                           kKxldLogMalformedVTable,
+                           kxld_demangle(vtable->name,
+                           &demangled_name, &demangled_length)));
+
+                       rval = init_by_entries_and_relocs(vtable, vtable_sym,
+                           relocator, extrelocs, defined_cxx_symbols);
+                       require_noerr(rval, finish);
+               } else {
+                       require_action(kxld_sect_get_num_relocs(vtable_sect) > 0, finish,
+                           rval = KERN_FAILURE;
+                           kxld_log(kKxldLogPatching, kKxldLogErr,
+                           kKxldLogMalformedVTable,
+                           kxld_demangle(vtable->name,
+                           &demangled_name, &demangled_length)));
+
+                       rval = init_by_relocs(vtable, vtable_sym, vtable_sect, relocator);
+                       require_noerr(rval, finish);
+               }
+
+               vtable->is_patched = FALSE;
+       }
+
+       rval = KERN_SUCCESS;
 finish:
-    if (demangled_name) kxld_free(demangled_name, demangled_length);
 
-    return rval;
+       if (demangled_name) {
+               kxld_free(demangled_name, demangled_length);
+       }
+
+       return rval;
 }
 
 /*******************************************************************************
 *******************************************************************************/
-static void 
+static void
 get_vtable_base_sizes(boolean_t is_32_bit, u_int *vtable_entry_size,
     u_int *vtable_header_size)
 {
-    check(vtable_entry_size);
-    check(vtable_header_size);
-
-    if (is_32_bit) {
-        *vtable_entry_size = VTABLE_ENTRY_SIZE_32;
-        *vtable_header_size = VTABLE_HEADER_SIZE_32;
-    } else {
-        *vtable_entry_size = VTABLE_ENTRY_SIZE_64;
-        *vtable_header_size = VTABLE_HEADER_SIZE_64;
-    }
+       check(vtable_entry_size);
+       check(vtable_header_size);
+
+       if (is_32_bit) {
+               *vtable_entry_size = VTABLE_ENTRY_SIZE_32;
+               *vtable_header_size = VTABLE_HEADER_SIZE_32;
+       } else {
+               *vtable_entry_size = VTABLE_ENTRY_SIZE_64;
+               *vtable_header_size = VTABLE_HEADER_SIZE_64;
+       }
 }
 
 /*******************************************************************************
@@ -163,86 +167,88 @@ get_vtable_base_sizes(boolean_t is_32_bit, u_int *vtable_entry_size,
 * entries and finding the corresponding symbols.
 *******************************************************************************/
 static kern_return_t
-init_by_relocs(KXLDVTable *vtable, const KXLDSym *vtable_sym, 
+init_by_relocs(KXLDVTable *vtable, const KXLDSym *vtable_sym,
     const KXLDSect *sect, const KXLDRelocator *relocator)
 {
-    kern_return_t rval = KERN_FAILURE;
-    KXLDReloc *reloc = NULL;
-    KXLDVTableEntry *entry = NULL;
-    KXLDSym *sym = NULL;
-    kxld_addr_t vtable_base_offset = 0;
-    kxld_addr_t entry_offset = 0;
-    u_int i = 0;
-    u_int nentries = 0;
-    u_int vtable_entry_size = 0;
-    u_int vtable_header_size = 0;
-    u_int base_reloc_index = 0;
-    u_int reloc_index = 0;
-
-    check(vtable);
-    check(vtable_sym);
-    check(sect);
-    check(relocator);
-
-    /* Find the first entry past the vtable padding */
-
-    (void) get_vtable_base_sizes(relocator->is_32_bit, 
-        &vtable_entry_size, &vtable_header_size);
-
-    vtable_base_offset = kxld_sym_get_section_offset(vtable_sym, sect) + 
-        vtable_header_size;
-   
-    /* Find the relocation entry at the start of the vtable */
-
-    rval = kxld_reloc_get_reloc_index_by_offset(&sect->relocs, 
-        vtable_base_offset, &base_reloc_index);
-    require_noerr(rval, finish);
-
-    /* Count the number of consecutive relocation entries to find the number of
-     * vtable entries.  For some reason, the __TEXT,__const relocations are
-     * sorted in descending order, so we have to walk backwards.  Also, make
-     * sure we don't run off the end of the section's relocs.
-     */
-
-    reloc_index = base_reloc_index;
-    entry_offset = vtable_base_offset;
-    reloc = kxld_array_get_item(&sect->relocs, reloc_index);
-    while (reloc->address == entry_offset) {
-        ++nentries;
-        if (!reloc_index) break;
-
-        --reloc_index;
-
-        reloc = kxld_array_get_item(&sect->relocs, reloc_index);
-        entry_offset += vtable_entry_size;
-    }
-
-    /* Allocate the symbol index */
-
-    rval = kxld_array_init(&vtable->entries, sizeof(KXLDVTableEntry), nentries);
-    require_noerr(rval, finish);
-
-    /* Find the symbols for each vtable entry */
-
-    for (i = 0; i < vtable->entries.nitems; ++i) {
-        reloc = kxld_array_get_item(&sect->relocs, base_reloc_index - i);
-        entry = kxld_array_get_item(&vtable->entries, i);
-
-        /* If we can't find a symbol, it means it is a locally-defined,
-         * non-external symbol that has been stripped.  We don't patch over
-         * locally-defined symbols, so we leave the symbol as NULL and just
-         * skip it.  We won't be able to patch subclasses with this symbol,
-         * but there isn't much we can do about that.
-         */
-        sym = kxld_reloc_get_symbol(relocator, reloc, sect->data);
-
-        entry->unpatched.sym = sym;
-        entry->unpatched.reloc = reloc;
-    }
-
-    rval = KERN_SUCCESS;
+       kern_return_t rval = KERN_FAILURE;
+       KXLDReloc *reloc = NULL;
+       KXLDVTableEntry *entry = NULL;
+       KXLDSym *sym = NULL;
+       kxld_addr_t vtable_base_offset = 0;
+       kxld_addr_t entry_offset = 0;
+       u_int i = 0;
+       u_int nentries = 0;
+       u_int vtable_entry_size = 0;
+       u_int vtable_header_size = 0;
+       u_int base_reloc_index = 0;
+       u_int reloc_index = 0;
+
+       check(vtable);
+       check(vtable_sym);
+       check(sect);
+       check(relocator);
+
+       /* Find the first entry past the vtable padding */
+
+       (void) get_vtable_base_sizes(relocator->is_32_bit,
+           &vtable_entry_size, &vtable_header_size);
+
+       vtable_base_offset = kxld_sym_get_section_offset(vtable_sym, sect) +
+           vtable_header_size;
+
+       /* Find the relocation entry at the start of the vtable */
+
+       rval = kxld_reloc_get_reloc_index_by_offset(&sect->relocs,
+           vtable_base_offset, &base_reloc_index);
+       require_noerr(rval, finish);
+
+       /* Count the number of consecutive relocation entries to find the number of
+        * vtable entries.  For some reason, the __TEXT,__const relocations are
+        * sorted in descending order, so we have to walk backwards.  Also, make
+        * sure we don't run off the end of the section's relocs.
+        */
+
+       reloc_index = base_reloc_index;
+       entry_offset = vtable_base_offset;
+       reloc = kxld_array_get_item(&sect->relocs, reloc_index);
+       while (reloc->address == entry_offset) {
+               ++nentries;
+               if (!reloc_index) {
+                       break;
+               }
+
+               --reloc_index;
+
+               reloc = kxld_array_get_item(&sect->relocs, reloc_index);
+               entry_offset += vtable_entry_size;
+       }
+
+       /* Allocate the symbol index */
+
+       rval = kxld_array_init(&vtable->entries, sizeof(KXLDVTableEntry), nentries);
+       require_noerr(rval, finish);
+
+       /* Find the symbols for each vtable entry */
+
+       for (i = 0; i < vtable->entries.nitems; ++i) {
+               reloc = kxld_array_get_item(&sect->relocs, base_reloc_index - i);
+               entry = kxld_array_get_item(&vtable->entries, i);
+
+               /* If we can't find a symbol, it means it is a locally-defined,
+                * non-external symbol that has been stripped.  We don't patch over
+                * locally-defined symbols, so we leave the symbol as NULL and just
+                * skip it.  We won't be able to patch subclasses with this symbol,
+                * but there isn't much we can do about that.
+                */
+               sym = kxld_reloc_get_symbol(relocator, reloc, sect->data);
+
+               entry->unpatched.sym = sym;
+               entry->unpatched.reloc = reloc;
+       }
+
+       rval = KERN_SUCCESS;
 finish:
-    return rval;
+       return rval;
 }
 
 /*******************************************************************************
@@ -253,67 +259,68 @@ static kern_return_t
 init_by_entries(KXLDVTable *vtable, const KXLDRelocator *relocator,
     const KXLDDict *defined_cxx_symbols)
 {
-    kern_return_t rval = KERN_FAILURE;
-    KXLDVTableEntry *tmpentry = NULL;
-    KXLDSym *sym = NULL;
-    kxld_addr_t entry_value = 0;
-    u_long entry_offset;
-    u_int vtable_entry_size = 0;
-    u_int vtable_header_size = 0;
-    u_int nentries = 0;
-    u_int i = 0;
-
-    check(vtable);
-    check(relocator);
-
-    (void) get_vtable_base_sizes(relocator->is_32_bit, 
-        &vtable_entry_size, &vtable_header_size);
-
-    /* Count the number of entries (the vtable is null-terminated) */
-
-    entry_offset = vtable_header_size;
-    while (1) {
-        entry_value = kxld_relocator_get_pointer_at_addr(relocator,
-            vtable->vtable, entry_offset);
-        if (!entry_value) break;
-
-        entry_offset += vtable_entry_size;
-        ++nentries;
-    }
-
-    /* Allocate the symbol index */
-
-    rval = kxld_array_init(&vtable->entries, sizeof(KXLDVTableEntry), nentries);
-    require_noerr(rval, finish);
-
-    /* Look up the symbols for each entry */
-
-    for (i = 0, entry_offset = vtable_header_size; 
-         i < vtable->entries.nitems; 
-         ++i, entry_offset += vtable_entry_size) 
-    {
-        entry_value = kxld_relocator_get_pointer_at_addr(relocator,
-            vtable->vtable, entry_offset);
-
-        /* If we can't find the symbol, it means that the virtual function was
-         * defined inline.  There's not much I can do about this; it just means
-         * I can't patch this function.
-         */
-        tmpentry = kxld_array_get_item(&vtable->entries, i);
-        sym = kxld_dict_find(defined_cxx_symbols, &entry_value);
-
-        if (sym) {
-            tmpentry->patched.name = sym->name;
-            tmpentry->patched.addr = sym->link_addr;
-        } else {
-            tmpentry->patched.name = NULL;
-            tmpentry->patched.addr = 0;
-        }
-    }
-
-    rval = KERN_SUCCESS;
+       kern_return_t rval = KERN_FAILURE;
+       KXLDVTableEntry *tmpentry = NULL;
+       KXLDSym *sym = NULL;
+       kxld_addr_t entry_value = 0;
+       u_long entry_offset;
+       u_int vtable_entry_size = 0;
+       u_int vtable_header_size = 0;
+       u_int nentries = 0;
+       u_int i = 0;
+
+       check(vtable);
+       check(relocator);
+
+       (void) get_vtable_base_sizes(relocator->is_32_bit,
+           &vtable_entry_size, &vtable_header_size);
+
+       /* Count the number of entries (the vtable is null-terminated) */
+
+       entry_offset = vtable_header_size;
+       while (1) {
+               entry_value = kxld_relocator_get_pointer_at_addr(relocator,
+                   vtable->vtable, entry_offset);
+               if (!entry_value) {
+                       break;
+               }
+
+               entry_offset += vtable_entry_size;
+               ++nentries;
+       }
+
+       /* Allocate the symbol index */
+
+       rval = kxld_array_init(&vtable->entries, sizeof(KXLDVTableEntry), nentries);
+       require_noerr(rval, finish);
+
+       /* Look up the symbols for each entry */
+
+       for (i = 0, entry_offset = vtable_header_size;
+           i < vtable->entries.nitems;
+           ++i, entry_offset += vtable_entry_size) {
+               entry_value = kxld_relocator_get_pointer_at_addr(relocator,
+                   vtable->vtable, entry_offset);
+
+               /* If we can't find the symbol, it means that the virtual function was
+                * defined inline.  There's not much I can do about this; it just means
+                * I can't patch this function.
+                */
+               tmpentry = kxld_array_get_item(&vtable->entries, i);
+               sym = kxld_dict_find(defined_cxx_symbols, &entry_value);
+
+               if (sym) {
+                       tmpentry->patched.name = sym->name;
+                       tmpentry->patched.addr = sym->link_addr;
+               } else {
+                       tmpentry->patched.name = NULL;
+                       tmpentry->patched.addr = 0;
+               }
+       }
+
+       rval = KERN_SUCCESS;
 finish:
-    return rval;
+       return rval;
 }
 
 /*******************************************************************************
@@ -327,96 +334,98 @@ finish:
 * external symbols.
 *******************************************************************************/
 static kern_return_t
-init_by_entries_and_relocs(KXLDVTable *vtable, const KXLDSym *vtable_sym, 
+init_by_entries_and_relocs(KXLDVTable *vtable, const KXLDSym *vtable_sym,
     const KXLDRelocator *relocator, const KXLDArray *relocs,
     const KXLDDict *defined_cxx_symbols)
 {
-    kern_return_t rval = KERN_FAILURE;
-    KXLDReloc *reloc = NULL;
-    KXLDVTableEntry *tmpentry = NULL;
-    KXLDSym *sym = NULL;
-    u_int vtable_entry_size = 0;
-    u_int vtable_header_size = 0;
-    kxld_addr_t entry_value = 0;
-    u_long entry_offset = 0;
-    u_int nentries = 0;
-    u_int i = 0;
-    char *demangled_name1 = NULL;
-    size_t demangled_length1 = 0;
-
-    check(vtable);
-    check(vtable_sym);
-    check(relocator);
-    check(relocs);
-
-    /* Find the first entry and its offset past the vtable padding */
-
-    (void) get_vtable_base_sizes(relocator->is_32_bit, 
-        &vtable_entry_size, &vtable_header_size);
-
-    /* In a final linked image, a vtable slot is valid if it is nonzero
-     * (meaning the userspace linker has already resolved it) or if it has
-     * a relocation entry.  We'll know the end of the vtable when we find a
-     * slot that meets neither of these conditions.
-     */
-    entry_offset = vtable_header_size;
-    while (1) {
-        entry_value = kxld_relocator_get_pointer_at_addr(relocator,
-            vtable->vtable, entry_offset);
-        if (!entry_value) {
-            reloc = kxld_reloc_get_reloc_by_offset(relocs, 
-                vtable_sym->base_addr + entry_offset);
-            if (!reloc) break;
-        }
-
-        ++nentries;
-        entry_offset += vtable_entry_size;
-    }
-
-    /* Allocate the symbol index */
-
-    rval = kxld_array_init(&vtable->entries, sizeof(KXLDVTableEntry), nentries);
-    require_noerr(rval, finish);
-
-    /* Find the symbols for each vtable entry */
-
-    for (i = 0, entry_offset = vtable_header_size; 
-         i < vtable->entries.nitems; 
-         ++i, entry_offset += vtable_entry_size) 
-    {
-        entry_value = kxld_relocator_get_pointer_at_addr(relocator,
-            vtable->vtable, entry_offset);
-
-        /* If we can't find a symbol, it means it is a locally-defined,
-         * non-external symbol that has been stripped.  We don't patch over
-         * locally-defined symbols, so we leave the symbol as NULL and just
-         * skip it.  We won't be able to patch subclasses with this symbol,
-         * but there isn't much we can do about that.
-         */
-        if (entry_value) {
-            reloc = NULL;
-            sym = kxld_dict_find(defined_cxx_symbols, &entry_value);
-        } else {
-            reloc = kxld_reloc_get_reloc_by_offset(relocs,
-                vtable_sym->base_addr + entry_offset);
-            require_action(reloc, finish,
-                rval=KERN_FAILURE;
-                kxld_log(kKxldLogPatching, kKxldLogErr, 
-                    kKxldLogMalformedVTable, 
-                    kxld_demangle(vtable->name, &demangled_name1, 
-                        &demangled_length1)));
-        
-            sym = kxld_reloc_get_symbol(relocator, reloc, /* data */ NULL);
-        }
-
-        tmpentry = kxld_array_get_item(&vtable->entries, i);
-        tmpentry->unpatched.reloc = reloc;
-        tmpentry->unpatched.sym = sym;
-    }
-
-    rval = KERN_SUCCESS;
+       kern_return_t rval = KERN_FAILURE;
+       KXLDReloc *reloc = NULL;
+       KXLDVTableEntry *tmpentry = NULL;
+       KXLDSym *sym = NULL;
+       u_int vtable_entry_size = 0;
+       u_int vtable_header_size = 0;
+       kxld_addr_t entry_value = 0;
+       u_long entry_offset = 0;
+       u_int nentries = 0;
+       u_int i = 0;
+       char *demangled_name1 = NULL;
+       size_t demangled_length1 = 0;
+
+       check(vtable);
+       check(vtable_sym);
+       check(relocator);
+       check(relocs);
+
+       /* Find the first entry and its offset past the vtable padding */
+
+       (void) get_vtable_base_sizes(relocator->is_32_bit,
+           &vtable_entry_size, &vtable_header_size);
+
+       /* In a final linked image, a vtable slot is valid if it is nonzero
+        * (meaning the userspace linker has already resolved it) or if it has
+        * a relocation entry.  We'll know the end of the vtable when we find a
+        * slot that meets neither of these conditions.
+        */
+       entry_offset = vtable_header_size;
+       while (1) {
+               entry_value = kxld_relocator_get_pointer_at_addr(relocator,
+                   vtable->vtable, entry_offset);
+               if (!entry_value) {
+                       reloc = kxld_reloc_get_reloc_by_offset(relocs,
+                           vtable_sym->base_addr + entry_offset);
+                       if (!reloc) {
+                               break;
+                       }
+               }
+
+               ++nentries;
+               entry_offset += vtable_entry_size;
+       }
+
+       /* Allocate the symbol index */
+
+       rval = kxld_array_init(&vtable->entries, sizeof(KXLDVTableEntry), nentries);
+       require_noerr(rval, finish);
+
+       /* Find the symbols for each vtable entry */
+
+       for (i = 0, entry_offset = vtable_header_size;
+           i < vtable->entries.nitems;
+           ++i, entry_offset += vtable_entry_size) {
+               entry_value = kxld_relocator_get_pointer_at_addr(relocator,
+                   vtable->vtable, entry_offset);
+
+               /* If we can't find a symbol, it means it is a locally-defined,
+                * non-external symbol that has been stripped.  We don't patch over
+                * locally-defined symbols, so we leave the symbol as NULL and just
+                * skip it.  We won't be able to patch subclasses with this symbol,
+                * but there isn't much we can do about that.
+                */
+               if (entry_value) {
+                       reloc = NULL;
+                       sym = kxld_dict_find(defined_cxx_symbols, &entry_value);
+               } else {
+                       reloc = kxld_reloc_get_reloc_by_offset(relocs,
+                           vtable_sym->base_addr + entry_offset);
+
+                       require_action(reloc, finish,
+                           rval = KERN_FAILURE;
+                           kxld_log(kKxldLogPatching, kKxldLogErr,
+                           kKxldLogMalformedVTable,
+                           kxld_demangle(vtable->name, &demangled_name1,
+                           &demangled_length1)));
+
+                       sym = kxld_reloc_get_symbol(relocator, reloc, /* data */ NULL);
+               }
+
+               tmpentry = kxld_array_get_item(&vtable->entries, i);
+               tmpentry->unpatched.reloc = reloc;
+               tmpentry->unpatched.sym = sym;
+       }
+
+       rval = KERN_SUCCESS;
 finish:
-    return rval;
+       return rval;
 }
 
 /*******************************************************************************
@@ -424,12 +433,12 @@ finish:
 void
 kxld_vtable_clear(KXLDVTable *vtable)
 {
-    check(vtable);
+       check(vtable);
 
-    vtable->vtable = NULL;
-    vtable->name = NULL;
-    vtable->is_patched = FALSE;
-    kxld_array_clear(&vtable->entries);
+       vtable->vtable = NULL;
+       vtable->name = NULL;
+       vtable->is_patched = FALSE;
+       kxld_array_clear(&vtable->entries);
 }
 
 /*******************************************************************************
@@ -437,34 +446,34 @@ kxld_vtable_clear(KXLDVTable *vtable)
 void
 kxld_vtable_deinit(KXLDVTable *vtable)
 {
-    check(vtable);
+       check(vtable);
 
-    kxld_array_deinit(&vtable->entries);
-    bzero(vtable, sizeof(*vtable));
+       kxld_array_deinit(&vtable->entries);
+       bzero(vtable, sizeof(*vtable));
 }
 
 /*******************************************************************************
 *******************************************************************************/
-KXLDVTableEntry * 
-kxld_vtable_get_entry_for_offset(const KXLDVTable *vtable, u_long offset, 
+KXLDVTableEntry *
+kxld_vtable_get_entry_for_offset(const KXLDVTable *vtable, u_long offset,
     boolean_t is_32_bit)
 {
-    KXLDVTableEntry *rval = NULL;
-    u_int vtable_entry_size = 0;
-    u_int vtable_header_size = 0;
-    u_int vtable_entry_idx = 0;
+       KXLDVTableEntry *rval = NULL;
+       u_int vtable_entry_size = 0;
+       u_int vtable_header_size = 0;
+       u_int vtable_entry_idx = 0;
 
-    (void) get_vtable_base_sizes(is_32_bit, 
-        &vtable_entry_size, &vtable_header_size);
+       (void) get_vtable_base_sizes(is_32_bit,
+           &vtable_entry_size, &vtable_header_size);
 
-    if (offset % vtable_entry_size) {
-        goto finish;
-    }
+       if (offset % vtable_entry_size) {
+               goto finish;
+       }
 
-    vtable_entry_idx = (u_int) ((offset - vtable_header_size) / vtable_entry_size);
-    rval = kxld_array_get_item(&vtable->entries, vtable_entry_idx);
+       vtable_entry_idx = (u_int) ((offset - vtable_header_size) / vtable_entry_size);
+       rval = kxld_array_get_item(&vtable->entries, vtable_entry_idx);
 finish:
-    return rval;
+       return rval;
 }
 
 /*******************************************************************************
@@ -474,207 +483,218 @@ kern_return_t
 kxld_vtable_patch(KXLDVTable *vtable, const KXLDVTable *super_vtable,
     KXLDObject *object)
 {
-    kern_return_t rval = KERN_FAILURE;
-    const KXLDSymtab *symtab = NULL;
-    const KXLDSym *sym = NULL;
-    KXLDVTableEntry *child_entry = NULL;
-    KXLDVTableEntry *parent_entry = NULL;
-    u_int symindex = 0;
-    u_int i = 0;
-    char *demangled_name1 = NULL;
-    char *demangled_name2 = NULL;
-    char *demangled_name3 = NULL;
-    size_t demangled_length1 = 0;
-    size_t demangled_length2 = 0;
-    size_t demangled_length3 = 0;
-    boolean_t failure = FALSE;
-
-    check(vtable);
-    check(super_vtable);
-
-    symtab = kxld_object_get_symtab(object);
-
-    require_action(!vtable->is_patched, finish, rval=KERN_SUCCESS);
-    require_action(super_vtable->is_patched, finish, rval=KERN_FAILURE);
-    require_action(vtable->entries.nitems >= super_vtable->entries.nitems, finish,
-        rval=KERN_FAILURE;
-        kxld_log(kKxldLogPatching, kKxldLogErr, kKxldLogMalformedVTable, 
-            kxld_demangle(vtable->name, &demangled_name1, &demangled_length1)));
-
-    for (i = 0; i < super_vtable->entries.nitems; ++i) {
-        child_entry = kxld_array_get_item(&vtable->entries, i);
-        parent_entry = kxld_array_get_item(&super_vtable->entries, i);
-
-        /* The child entry can be NULL when a locally-defined, non-external
-         * symbol is stripped.  We wouldn't patch this entry anyway, so we
-         * just skip it.
-         */
-
-        if (!child_entry->unpatched.sym) continue;
-
-        /* It's possible for the patched parent entry not to have a symbol
-         * (e.g. when the definition is inlined).  We can't patch this entry no
-         * matter what, so we'll just skip it and die later if it's a problem
-         * (which is not likely).
-         */
-
-        if (!parent_entry->patched.name) continue;
-        
-        /* 1) If the symbol is defined locally, do not patch */
-
-        if (kxld_sym_is_defined_locally(child_entry->unpatched.sym)) continue;
-
-        /* 2) If the child is a pure virtual function, do not patch.
-         * In general, we want to proceed with patching when the symbol is 
-         * externally defined because pad slots fall into this category.
-         * The pure virtual function symbol is special case, as the pure
-         * virtual property itself overrides the parent's implementation.
-         */
-
-        if (kxld_sym_is_pure_virtual(child_entry->unpatched.sym)) continue;
-
-        /* 3) If the symbols are the same, do not patch */
-
-        if (streq(child_entry->unpatched.sym->name, 
-                  parent_entry->patched.name)) 
-        {
-            continue;
-        }
-
-        /* 4) If the parent vtable entry is a pad slot, and the child does not
-         * match it, then the child was built against a newer version of the
-         * libraries, so it is binary-incompatible.
-         */
-
-        require_action(!kxld_sym_name_is_padslot(parent_entry->patched.name),
-            finish, rval=KERN_FAILURE;
-            kxld_log(kKxldLogPatching, kKxldLogErr, 
-                kKxldLogParentOutOfDate, 
-                kxld_demangle(super_vtable->name, &demangled_name1, 
-                    &demangled_length1), 
-                kxld_demangle(vtable->name, &demangled_name2, 
-                    &demangled_length2)));
+       kern_return_t rval = KERN_FAILURE;
+       const KXLDSymtab *symtab = NULL;
+       const KXLDSym *sym = NULL;
+       KXLDVTableEntry *child_entry = NULL;
+       KXLDVTableEntry *parent_entry = NULL;
+       u_int symindex = 0;
+       u_int i = 0;
+       char *demangled_name1 = NULL;
+       char *demangled_name2 = NULL;
+       char *demangled_name3 = NULL;
+       size_t demangled_length1 = 0;
+       size_t demangled_length2 = 0;
+       size_t demangled_length3 = 0;
+       boolean_t failure = FALSE;
+
+       check(vtable);
+       check(super_vtable);
+
+       symtab = kxld_object_get_symtab(object);
+
+       require_action(!vtable->is_patched, finish, rval = KERN_SUCCESS);
+       require_action(super_vtable->is_patched, finish, rval = KERN_FAILURE);
+       require_action(vtable->entries.nitems >= super_vtable->entries.nitems, finish,
+           rval = KERN_FAILURE;
+           kxld_log(kKxldLogPatching, kKxldLogErr, kKxldLogMalformedVTable,
+           kxld_demangle(vtable->name, &demangled_name1, &demangled_length1)));
+
+       for (i = 0; i < super_vtable->entries.nitems; ++i) {
+               child_entry = kxld_array_get_item(&vtable->entries, i);
+               parent_entry = kxld_array_get_item(&super_vtable->entries, i);
+
+               /* The child entry can be NULL when a locally-defined, non-external
+                * symbol is stripped.  We wouldn't patch this entry anyway, so we
+                * just skip it.
+                */
+
+               if (!child_entry->unpatched.sym) {
+                       continue;
+               }
+
+               /* It's possible for the patched parent entry not to have a symbol
+                * (e.g. when the definition is inlined).  We can't patch this entry no
+                * matter what, so we'll just skip it and die later if it's a problem
+                * (which is not likely).
+                */
+
+               if (!parent_entry->patched.name) {
+                       continue;
+               }
+
+               /* 1) If the symbol is defined locally, do not patch */
+
+               if (kxld_sym_is_defined_locally(child_entry->unpatched.sym)) {
+                       continue;
+               }
+
+               /* 2) If the child is a pure virtual function, do not patch.
+                * In general, we want to proceed with patching when the symbol is
+                * externally defined because pad slots fall into this category.
+                * The pure virtual function symbol is special case, as the pure
+                * virtual property itself overrides the parent's implementation.
+                */
+
+               if (kxld_sym_is_pure_virtual(child_entry->unpatched.sym)) {
+                       continue;
+               }
+
+               /* 3) If the symbols are the same, do not patch */
+
+               if (streq(child_entry->unpatched.sym->name,
+                   parent_entry->patched.name)) {
+                       continue;
+               }
+
+               /* 4) If the parent vtable entry is a pad slot, and the child does not
+                * match it, then the child was built against a newer version of the
+                * libraries, so it is binary-incompatible.
+                */
+
+               require_action(!kxld_sym_name_is_padslot(parent_entry->patched.name),
+                   finish, rval = KERN_FAILURE;
+                   kxld_log(kKxldLogPatching, kKxldLogErr,
+                   kKxldLogParentOutOfDate,
+                   kxld_demangle(super_vtable->name, &demangled_name1,
+                   &demangled_length1),
+                   kxld_demangle(vtable->name, &demangled_name2,
+                   &demangled_length2)));
 
 #if KXLD_USER_OR_STRICT_PATCHING
-        /* 5) If we are doing strict patching, we prevent kexts from declaring
-         * virtual functions and not implementing them.  We can tell if a
-         * virtual function is declared but not implemented because we resolve
-         * symbols before patching; an unimplemented function will still be
-         * undefined at this point.  We then look at whether the symbol has
-         * the same class prefix as the vtable.  If it does, the symbol was
-         * declared as part of the class and not inherited, which means we
-         * should not patch it.
-         */
-
-        if (kxld_object_target_supports_strict_patching(object) && 
-            !kxld_sym_is_defined(child_entry->unpatched.sym))
-        {
-            char class_name[KXLD_MAX_NAME_LEN];
-            char function_prefix[KXLD_MAX_NAME_LEN];
-            u_long function_prefix_len = 0;
-
-            rval = kxld_sym_get_class_name_from_vtable_name(vtable->name,
-                class_name, sizeof(class_name));
-            require_noerr(rval, finish);
-
-            function_prefix_len = 
-                kxld_sym_get_function_prefix_from_class_name(class_name,
-                    function_prefix, sizeof(function_prefix));
-            require(function_prefix_len, finish);
-
-            if (!strncmp(child_entry->unpatched.sym->name, 
-                    function_prefix, function_prefix_len)) 
-            {
-                failure = TRUE;
-                kxld_log(kKxldLogPatching, kKxldLogErr,
-                    "The %s is unpatchable because its class declares the "
-                    "method '%s' without providing an implementation.",
-                    kxld_demangle(vtable->name,
-                        &demangled_name1, &demangled_length1),
-                    kxld_demangle(child_entry->unpatched.sym->name,
-                        &demangled_name2, &demangled_length2));
-                continue;
-            }
-        }
+               /* 5) If we are doing strict patching, we prevent kexts from declaring
+                * virtual functions and not implementing them.  We can tell if a
+                * virtual function is declared but not implemented because we resolve
+                * symbols before patching; an unimplemented function will still be
+                * undefined at this point.  We then look at whether the symbol has
+                * the same class prefix as the vtable.  If it does, the symbol was
+                * declared as part of the class and not inherited, which means we
+                * should not patch it.
+                */
+
+               if (kxld_object_target_supports_strict_patching(object) &&
+                   !kxld_sym_is_defined(child_entry->unpatched.sym)) {
+                       char class_name[KXLD_MAX_NAME_LEN];
+                       char function_prefix[KXLD_MAX_NAME_LEN];
+                       u_long function_prefix_len = 0;
+
+                       rval = kxld_sym_get_class_name_from_vtable_name(vtable->name,
+                           class_name, sizeof(class_name));
+                       require_noerr(rval, finish);
+
+                       function_prefix_len =
+                           kxld_sym_get_function_prefix_from_class_name(class_name,
+                           function_prefix, sizeof(function_prefix));
+                       require(function_prefix_len, finish);
+
+                       if (!strncmp(child_entry->unpatched.sym->name,
+                           function_prefix, function_prefix_len)) {
+                               failure = TRUE;
+                               kxld_log(kKxldLogPatching, kKxldLogErr,
+                                   "The %s is unpatchable because its class declares the "
+                                   "method '%s' without providing an implementation.",
+                                   kxld_demangle(vtable->name,
+                                   &demangled_name1, &demangled_length1),
+                                   kxld_demangle(child_entry->unpatched.sym->name,
+                                   &demangled_name2, &demangled_length2));
+                               continue;
+                       }
+               }
 #endif /* KXLD_USER_OR_STRICT_PATCHING */
-    
-        /* 6) The child symbol is unresolved and different from its parent, so
-         * we need to patch it up.  We do this by modifying the relocation
-         * entry of the vtable entry to point to the symbol of the parent
-         * vtable entry.  If that symbol does not exist (i.e. we got the data
-         * from a link state object's vtable representation), then we create a
-         * new symbol in the symbol table and point the relocation entry to
-         * that.
-         */
-
-        sym = kxld_symtab_get_locally_defined_symbol_by_name(symtab, 
-            parent_entry->patched.name);
-        if (!sym) {
-            rval = kxld_object_add_symbol(object, parent_entry->patched.name,
-                parent_entry->patched.addr, &sym);
-            require_noerr(rval, finish);
-        }
-        require_action(sym, finish, rval=KERN_FAILURE);
-
-        rval = kxld_symtab_get_sym_index(symtab, sym, &symindex);
-        require_noerr(rval, finish);
-
-        rval = kxld_reloc_update_symindex(child_entry->unpatched.reloc, symindex);
-        require_noerr(rval, finish);
-        kxld_log(kKxldLogPatching, kKxldLogDetail,
-            "In vtable '%s', patching '%s' with '%s'.", 
-            kxld_demangle(vtable->name, &demangled_name1, &demangled_length1),
-            kxld_demangle(child_entry->unpatched.sym->name, 
-                &demangled_name2, &demangled_length2), 
-            kxld_demangle(sym->name, &demangled_name3, &demangled_length3));
-
-        rval = kxld_object_patch_symbol(object, child_entry->unpatched.sym);
-        require_noerr(rval, finish);
-
-        child_entry->unpatched.sym = sym;
-
-        /*
-         * The C++ ABI requires that functions be aligned on a 2-byte boundary:
-         * http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers
-         * If the LSB of any virtual function's link address is 1, then the
-         * compiler has violated that part of the ABI, and we're going to panic
-         * in _ptmf2ptf() (in OSMetaClass.h). Better to panic here with some
-         * context.
-         */
-        assert(kxld_sym_is_pure_virtual(sym) || !(sym->link_addr & 1)); 
-    }
-
-    require_action(!failure, finish, rval=KERN_FAILURE);
-
-    /* Change the vtable representation from the unpatched layout to the
-     * patched layout.
-     */
-
-    for (i = 0; i < vtable->entries.nitems; ++i) {
-        char *name;
-        kxld_addr_t addr;
-
-        child_entry = kxld_array_get_item(&vtable->entries, i);
-        if (child_entry->unpatched.sym) {
-            name = child_entry->unpatched.sym->name;
-            addr = child_entry->unpatched.sym->link_addr;
-        } else {
-            name = NULL;
-            addr = 0;
-        }
-
-        child_entry->patched.name = name;
-        child_entry->patched.addr = addr;
-    }
-
-    vtable->is_patched = TRUE;
-    rval = KERN_SUCCESS;
+
+               /* 6) The child symbol is unresolved and different from its parent, so
+                * we need to patch it up.  We do this by modifying the relocation
+                * entry of the vtable entry to point to the symbol of the parent
+                * vtable entry.  If that symbol does not exist (i.e. we got the data
+                * from a link state object's vtable representation), then we create a
+                * new symbol in the symbol table and point the relocation entry to
+                * that.
+                */
+
+               sym = kxld_symtab_get_locally_defined_symbol_by_name(symtab,
+                   parent_entry->patched.name);
+               if (!sym) {
+                       rval = kxld_object_add_symbol(object, parent_entry->patched.name,
+                           parent_entry->patched.addr, &sym);
+                       require_noerr(rval, finish);
+               }
+               require_action(sym, finish, rval = KERN_FAILURE);
+
+               rval = kxld_symtab_get_sym_index(symtab, sym, &symindex);
+               require_noerr(rval, finish);
+
+               rval = kxld_reloc_update_symindex(child_entry->unpatched.reloc, symindex);
+               require_noerr(rval, finish);
+
+               kxld_log(kKxldLogPatching, kKxldLogDetail,
+                   "In vtable '%s', patching '%s' with '%s'.",
+                   kxld_demangle(vtable->name, &demangled_name1, &demangled_length1),
+                   kxld_demangle(child_entry->unpatched.sym->name,
+                   &demangled_name2, &demangled_length2),
+                   kxld_demangle(sym->name, &demangled_name3, &demangled_length3));
+
+               rval = kxld_object_patch_symbol(object, child_entry->unpatched.sym);
+               require_noerr(rval, finish);
+
+               child_entry->unpatched.sym = sym;
+
+               /*
+                * The C++ ABI requires that functions be aligned on a 2-byte boundary:
+                * http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers
+                * If the LSB of any virtual function's link address is 1, then the
+                * compiler has violated that part of the ABI, and we're going to panic
+                * in _ptmf2ptf() (in OSMetaClass.h). Better to panic here with some
+                * context.
+                */
+               assert(kxld_sym_is_pure_virtual(sym) || !(sym->link_addr & 1));
+       }
+
+       require_action(!failure, finish, rval = KERN_FAILURE);
+
+       /* Change the vtable representation from the unpatched layout to the
+        * patched layout.
+        */
+
+       for (i = 0; i < vtable->entries.nitems; ++i) {
+               char *name;
+               kxld_addr_t addr;
+
+               child_entry = kxld_array_get_item(&vtable->entries, i);
+               if (child_entry->unpatched.sym) {
+                       name = child_entry->unpatched.sym->name;
+                       addr = child_entry->unpatched.sym->link_addr;
+               } else {
+                       name = NULL;
+                       addr = 0;
+               }
+
+               child_entry->patched.name = name;
+               child_entry->patched.addr = addr;
+       }
+
+       vtable->is_patched = TRUE;
+       rval = KERN_SUCCESS;
 
 finish:
-    if (demangled_name1) kxld_free(demangled_name1, demangled_length1);
-    if (demangled_name2) kxld_free(demangled_name2, demangled_length2);
-    if (demangled_name3) kxld_free(demangled_name3, demangled_length3);
-    
-    return rval;
+       if (demangled_name1) {
+               kxld_free(demangled_name1, demangled_length1);
+       }
+       if (demangled_name2) {
+               kxld_free(demangled_name2, demangled_length2);
+       }
+       if (demangled_name3) {
+               kxld_free(demangled_name3, demangled_length3);
+       }
+
+       return rval;
 }
-