]> git.saurik.com Git - apple/xnu.git/blobdiff - libkern/c++/OSKext.cpp
xnu-4570.1.46.tar.gz
[apple/xnu.git] / libkern / c++ / OSKext.cpp
index acc3e3e98e128f2cd1affa85e865b2fba80c2000..797fd38a25101b6ee998442653c8c53733c0c87a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
  */
 
 extern "C" {
+#include <string.h>
 #include <kern/clock.h>
 #include <kern/host.h>
 #include <kern/kext_alloc.h>
+#include <firehose/tracepoint_private.h>
+#include <firehose/chunk_private.h>
+#include <os/firehose_buffer_private.h>
+#include <vm/vm_kern.h>
 #include <kextd/kextd_mach.h>
 #include <libkern/kernel_mach_header.h>
 #include <libkern/kext_panic_report.h>
@@ -38,8 +43,20 @@ extern "C" {
 #include <libkern/prelink.h>
 #include <libkern/version.h>
 #include <libkern/zlib.h>
+#include <mach/host_special_ports.h>
 #include <mach/mach_vm.h>
+#include <mach/mach_time.h>
 #include <sys/sysctl.h>
+#include <uuid/uuid.h>
+// 04/18/11 - gab: <rdar://problem/9236163>
+#include <sys/random.h>
+
+#include <sys/pgo.h>
+
+#if CONFIG_MACF
+#include <sys/kauth.h>
+#include <security/mac_framework.h>
+#endif
 };
 
 #include <libkern/OSKextLibPrivate.h>
@@ -51,15 +68,17 @@ extern "C" {
 #include <IOKit/IORegistryEntry.h>
 #include <IOKit/IOService.h>
 
+#include <IOKit/IOStatisticsPrivate.h>
+#include <IOKit/IOBSD.h>
+
+#include <san/kasan.h>
+
 #if PRAGMA_MARK
 #pragma mark External & Internal Function Protos
 #endif
 /*********************************************************************
 *********************************************************************/
 extern "C" {
-// in libkern/OSKextLib.cpp, not in header for a reason.
-extern kern_return_t OSKextPingKextd(void);
-
 extern int  IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
 extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
 extern void OSRuntimeUnloadCPPForSegment(kernel_segment_command_t * segment);
@@ -84,11 +103,32 @@ static OSReturn _OSDictionarySetCStringValue(
     OSDictionary * dict,
     const char   * key,
     const char   * value);
-#if CONFIG_MACF_KEXT
-static void * MACFCopyModuleDataForKext(
-    OSKext                 * theKext,
-    mach_msg_type_number_t * datalen);
-#endif /* CONFIG_MACF_KEXT */
+static bool _OSKextInPrelinkRebuildWindow(void);
+static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
+    
+// We really should add containsObject() & containsCString to OSCollection & subclasses.
+// So few pad slots, though....
+static bool _OSArrayContainsCString(OSArray * array, const char * cString);
+
+#if CONFIG_KEC_FIPS
+static void * GetAppleTEXTHashForKext(OSKext * theKext, OSDictionary *theInfoDict);
+#endif // CONFIG_KEC_FIPS
+
+/* Prelinked arm kexts do not have VM entries because the method we use to
+ * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
+ * not work on ARM.  To get around that, we must free prelinked kext
+ * executables with ml_static_mfree() instead of kext_free().
+ */
+#if __i386__ || __x86_64__
+#define VM_MAPPED_KEXTS 1
+#define KASLR_KEXT_DEBUG 0
+#define KASLR_IOREG_DEBUG 0
+#elif __arm__ || __arm64__
+#define VM_MAPPED_KEXTS 0
+#define KASLR_KEXT_DEBUG 0
+#else
+#error Unsupported architecture
+#endif
 
 #if PRAGMA_MARK
 #pragma mark Constants & Macros
@@ -97,10 +137,9 @@ static void * MACFCopyModuleDataForKext(
 * Constants & Macros
 *********************************************************************/
 
-/* A typical Snow Leopard system has a bit under 120 kexts loaded.
- * Use this number to create containers.
+/* Use this number to create containers.
  */
-#define kOSKextTypicalLoadCount      (120)
+#define kOSKextTypicalLoadCount      (150)
 
 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
  * A loaded kext will no dependents or external retains will have 2 retains.
@@ -127,6 +166,9 @@ static void * MACFCopyModuleDataForKext(
 
 #define STRING_HAS_PREFIX(s, p)      (strncmp((s), (p), strlen(p)) == 0)
 
+#define REBUILD_MAX_TIME (60 * 5) // 5 minutes
+#define MINIMUM_WAKEUP_SECONDS (30)
+
 /*********************************************************************
 * infoDict keys for internally-stored data. Saves on ivar slots for
 * objects we don't keep around past boot time or during active load.
@@ -147,6 +189,12 @@ static void * MACFCopyModuleDataForKext(
  */
 #define _kOSKextExecutableExternalDataKey    "_OSKextExecutableExternalData"
 
+#define OS_LOG_HDR_VERSION  1
+#define NUM_OS_LOG_SECTIONS 2
+
+#define OS_LOG_SECT_IDX     0
+#define CSTRING_SECT_IDX    1
+
 #if PRAGMA_MARK
 #pragma mark Typedefs
 #endif
@@ -154,6 +202,22 @@ static void * MACFCopyModuleDataForKext(
 * Typedefs
 *********************************************************************/
 
+/*********************************************************************
+* osLogDataHeaderRef describes the header information of an OSData
+* object that is returned when querying for kOSBundleLogStringsKey.
+* We currently return information regarding 2 sections - os_log and
+* cstring. In the case that the os_log section doesn't exist, we just
+* return an offset and length of 0 for that section.
+*********************************************************************/
+typedef struct osLogDataHeader {
+    uint32_t version;
+    uint32_t sect_count;
+    struct {
+         uint32_t sect_offset;
+         uint32_t sect_size;
+    } sections[0];
+} osLogDataHeaderRef;
+
 /*********************************************************************
 * MkextEntryRef describes the contents of an OSData object
 * referencing a file entry from an mkext so that we can uncompress
@@ -177,18 +241,33 @@ typedef struct MkextEntryRef {
 
 static  bool                sPrelinkBoot               = false;
 static  bool                sSafeBoot                  = false;
+static  bool                sKeepSymbols               = false;
 
-/******
-* sKextLock is the principal lock for OSKext. Below, there is also an
-* sKextInnerLock used to guard access to data accessed on in-calls from
-* IOService. This 2nd lock is required to prevent a deadlock
-* with IOService calling back into OSKext::considerUnloads()
-* on a separate thread during a kext load operation.
+/*********************************************************************
+* sKextLock is the principal lock for OSKext, and guards all static
+* and global variables not owned by other locks (declared further
+* below). It must be taken by any entry-point method or function,
+* including internal functions called on scheduled threads.
+*
+* sKextLock and sKextInnerLock are recursive due to multiple functions
+* that are called both externally and internally. The other locks are
+* nonrecursive.
+*
+* Which locks are taken depends on what they protect, but if more than
+* one must be taken, they must always be locked in this order
+* (and unlocked in reverse order) to prevent deadlocks:
+*
+*    1. sKextLock
+*    2. sKextInnerLock
+*    3. sKextSummariesLock
+*    4. sKextLoggingLock
 */
 static IORecursiveLock    * sKextLock                  = NULL;
 
 static OSDictionary       * sKextsByID                 = NULL;
+static OSDictionary       * sExcludeListByID           = NULL;
 static OSArray            * sLoadedKexts               = NULL;
+static OSArray            * sUnloadedPrelinkedKexts    = NULL;
 
 // Requests to kextd waiting to be picked up.
 static OSArray            * sKernelRequests            = NULL;
@@ -207,7 +286,11 @@ static bool                 sKextdActive               = false;
 static bool                 sDeferredLoadSucceeded     = false;
 static bool                 sConsiderUnloadsExecuted   = false;
 
+#if NO_KEXTD
+static bool                 sKernelRequestsEnabled     = false;
+#else
 static bool                 sKernelRequestsEnabled     = true;
+#endif
 static bool                 sLoadEnabled               = true;
 static bool                 sUnloadEnabled             = true;
 
@@ -236,7 +319,7 @@ kmod_info_t g_kernel_kmod_info = {
     /* version         */ "0",               // filled in in OSKext::initialize()
     /* reference_count */ -1,                // never adjusted; kernel never unloads
     /* reference_list  */ NULL,
-    /* address         */ (vm_address_t)&_mh_execute_header,
+    /* address         */ 0,
     /* size            */ 0,                 // filled in in OSKext::initialize()
     /* hdr_size        */ 0,
     /* start           */ 0,
@@ -252,32 +335,25 @@ kmod_info_t * kmod = NULL;
 
 #define KEXT_PANICLIST_SIZE  (2 * PAGE_SIZE)
 
-static char     * unloaded_kext_paniclist        = NULL;
-static uint32_t   unloaded_kext_paniclist_size   = 0;
-static uint32_t   unloaded_kext_paniclist_length = 0;
+
+static char     * loaded_kext_paniclist         = NULL;
+static uint32_t   loaded_kext_paniclist_size    = 0;
+    
 AbsoluteTime      last_loaded_timestamp;
+static char       last_loaded_str_buf[2*KMOD_MAX_NAME];
+static u_long     last_loaded_strlen            = 0;
+static void     * last_loaded_address           = NULL;
+static u_long     last_loaded_size              = 0;
 
-static char     * loaded_kext_paniclist          = NULL;
-static uint32_t   loaded_kext_paniclist_size     = 0;
-static uint32_t   loaded_kext_paniclist_length   = 0;
 AbsoluteTime      last_unloaded_timestamp;
-static void     * last_unloaded_address          = NULL;
-#if __LP64__
-static uint64_t   last_unloaded_size             = 0;
-#else
-static uint32_t   last_unloaded_size             = 0;
-#endif /* __LP64__ */
-
-};
+static char       last_unloaded_str_buf[2*KMOD_MAX_NAME];
+static u_long     last_unloaded_strlen          = 0;
+static void     * last_unloaded_address         = NULL;
+static u_long     last_unloaded_size            = 0;
 
 /*********************************************************************
-* Because we can start IOService matching from OSKext (via IOCatalogue)
-* and IOService can call into OSKext, there is potential for cross-lock
-* contention, so OSKext needs two locks. The regular sKextLock above
-* guards most OSKext class/static variables, and sKextInnerLock guards
-* variables that can be accessed on in-calls from IOService, currently:
-*
-*   * OSKext::considerUnloads()
+* sKextInnerLock protects against cross-calls with IOService and
+* IOCatalogue, and owns the variables declared immediately below.
 *
 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
 *
@@ -286,9 +362,6 @@ static uint32_t   last_unloaded_size             = 0;
 * locks in an entry point to OSKext; if you need to do so, you must
 * spawn an independent thread to avoid potential deadlocks for threads
 * calling into OSKext.
-*
-* All static variables from here to the closing comment block fall
-* under sKextInnerLock.
 **********/
 static IORecursiveLock *    sKextInnerLock             = NULL;
 
@@ -300,13 +373,45 @@ static unsigned int         sConsiderUnloadDelay       = 60;     // seconds
 static thread_call_t        sUnloadCallout             = 0;
 static thread_call_t        sDestroyLinkContextThread  = 0;      // one-shot, one-at-a-time thread
 static bool                 sSystemSleep               = false;  // true when system going to sleep
+static AbsoluteTime         sLastWakeTime;                       // last time we woke up   
+
+/*********************************************************************
+* Backtraces can be printed at various times so we need a tight lock
+* on data used for that. sKextSummariesLock protects the variables
+* declared immediately below.
+*
+* gLoadedKextSummaries is accessed by other modules, but only during
+* a panic so the lock isn't needed then.
+*
+* gLoadedKextSummaries has the "used" attribute in order to ensure
+* that it remains visible even when we are performing extremely
+* aggressive optimizations, as it is needed to allow the debugger
+* to automatically parse the list of loaded kexts.
+**********/
+static IOLock                 * sKextSummariesLock                = NULL;
+extern "C" lck_spin_t           vm_allocation_sites_lock;
+static IOSimpleLock           * sKextAccountsLock = &vm_allocation_sites_lock;
+
+void (*sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
+OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
+uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
+static size_t sLoadedKextSummariesAllocSize = 0;
+
+static OSKextActiveAccount * sKextAccounts;
+static uint32_t                 sKextAccountsCount;
+};
+
+/*********************************************************************
+* sKextLoggingLock protects the logging variables declared immediately below.
+**********/
+static IOLock             * sKextLoggingLock           = NULL;
 
 static  const OSKextLogSpec kDefaultKernelLogFilter    = kOSKextLogBasicLevel |
                                                          kOSKextLogVerboseFlagsMask;
 static  OSKextLogSpec       sKernelLogFilter           = kDefaultKernelLogFilter;
 static  bool                sBootArgLogFilterFound     = false;
-SYSCTL_INT(_debug, OID_AUTO, kextlog, CTLFLAG_RW, &sKernelLogFilter,
-    sKernelLogFilter, "kernel kext logging");
+SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
+    0, "kernel kext logging");
 
 static  OSKextLogSpec       sUserSpaceKextLogFilter    = kOSKextLogSilentFilter;
 static  OSArray           * sUserSpaceLogSpecArray     = NULL;
@@ -316,6 +421,22 @@ static  OSArray           * sUserSpaceLogMessageArray  = NULL;
 * End scope for sKextInnerLock-protected variables.
 *********************************************************************/
 
+
+/*********************************************************************
+ helper function used for collecting PGO data upon unload of a kext
+ */
+
+static int OSKextGrabPgoDataLocked(OSKext *kext,
+                                   bool metadata,
+                                   uuid_t instance_uuid,
+                                   uint64_t *pSize,
+                                   char *pBuffer,
+                                   uint64_t bufferSize);
+
+/**********************************************************************/
+
+
+
 #if PRAGMA_MARK
 #pragma mark OSData callbacks (need to move to OSData)
 #endif
@@ -338,6 +459,12 @@ void osdata_vm_deallocate(void * ptr, unsigned int length)
     (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
     return;
 }
+
+void osdata_kext_free(void * ptr, unsigned int length)
+{
+    (void)kext_free((vm_offset_t)ptr, length);
+}
+
 };
 
 #if PRAGMA_MARK
@@ -370,9 +497,6 @@ kern_allocate(
     }
 
    /* Create an OSData wrapper for the allocated buffer.
-    * Note that we do not set a dealloc function on it here.
-    * We have to call vm_map_unwire() on it in OSKext::unload()
-    * and an OSData dealloc function can't take all those parameters.
     */
     linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
     if (!linkBuffer) {
@@ -383,7 +507,7 @@ kern_allocate(
             theKext->getIdentifierCString());
         goto finish;
     }
-
+    linkBuffer->setDeallocFunction(osdata_kext_free);
     OSKextLog(theKext,
         kOSKextLogProgressLevel |
         kOSKextLogLoadFlag | kOSKextLogLinkFlag,
@@ -402,7 +526,7 @@ finish:
         result = 0;
     }
 
-    OSSafeRelease(linkBuffer);
+    OSSafeReleaseNULL(linkBuffer);
 
     return (kxld_addr_t)result;
 }
@@ -453,6 +577,41 @@ kxld_log_callback(
     OSKextVLog(theKext, logSpec, format, argList);
 }
 
+#if PRAGMA_MARK
+#pragma mark IOStatistics defines
+#endif
+
+#if IOKITSTATS
+
+#define notifyKextLoadObservers(kext, kmod_info) \
+do { \
+    IOStatistics::onKextLoad(kext, kmod_info); \
+} while (0)
+
+#define notifyKextUnloadObservers(kext) \
+do { \
+    IOStatistics::onKextUnload(kext); \
+} while (0)
+
+#define notifyAddClassObservers(kext, addedClass, flags) \
+do { \
+    IOStatistics::onClassAdded(kext, addedClass); \
+} while (0)
+
+#define notifyRemoveClassObservers(kext, removedClass, flags) \
+do { \
+    IOStatistics::onClassRemoved(kext, removedClass); \
+} while (0)
+
+#else
+
+#define notifyKextLoadObservers(kext, kmod_info)
+#define notifyKextUnloadObservers(kext)
+#define notifyAddClassObservers(kext, addedClass, flags)
+#define notifyRemoveClassObservers(kext, removedClass, flags)
+
+#endif /* IOKITSTATS */
+
 #if PRAGMA_MARK
 #pragma mark Module Config (Startup & Shutdown)
 #endif
@@ -484,22 +643,27 @@ OSKext::initialize(void)
     */
     sKextLock = IORecursiveLockAlloc();
     sKextInnerLock = IORecursiveLockAlloc();
+    sKextSummariesLock = IOLockAlloc();
+    sKextLoggingLock = IOLockAlloc();
     assert(sKextLock);
     assert(sKextInnerLock);
+    assert(sKextSummariesLock);
+    assert(sKextLoggingLock);
 
     sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
     sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
+    sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
     sKernelRequests = OSArray::withCapacity(0);
     sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
     sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
     sRequestCallbackRecords = OSArray::withCapacity(0);
     assert(sKextsByID && sLoadedKexts && sKernelRequests &&
         sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
-        sRequestCallbackRecords);
+        sRequestCallbackRecords && sUnloadedPrelinkedKexts);
 
    /* Read the log flag boot-args and set the log flags.
     */
-    if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof("kextlog=0x00000000 "))) {
+    if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof(bootLogFilter))) {
         sBootArgLogFilterFound = true;
         sKernelLogFilter = bootLogFilter;
         // log this if any flags are set
@@ -521,6 +685,12 @@ OSKext::initialize(void)
             "only valid OSBundleRequired kexts will be loaded.");
     }
 
+    PE_parse_boot_argn("keepsyms", &sKeepSymbols, sizeof(sKeepSymbols));
+#if KASAN_DYNAMIC_BLACKLIST
+    /* needed for function lookup */
+    sKeepSymbols = true;
+#endif
+
    /* Set up an OSKext instance to represent the kernel itself.
     */
     sKernelKext = new OSKext;
@@ -532,13 +702,20 @@ OSKext::initialize(void)
         kernelStart, kernelLength);
     assert(kernelExecutable);
 
+#if KASLR_KEXT_DEBUG 
+    IOLog("kaslr: kernel start 0x%lx end 0x%lx length %lu vm_kernel_slide %llu (0x%016lx) \n",
+          (unsigned long)kernelStart, 
+          (unsigned long)getlastaddr(),
+          kernelLength,
+          vm_kernel_slide, vm_kernel_slide);
+#endif
+
     sKernelKext->loadTag = sNextLoadTag++;  // the kernel is load tag 0
     sKernelKext->bundleID = OSSymbol::withCString(kOSKextKernelIdentifier);
     
     sKernelKext->version = OSKextParseVersionString(osrelease);
     sKernelKext->compatibleVersion = sKernelKext->version;
     sKernelKext->linkedExecutable = kernelExecutable;
-    // linkState will be set first time we do a link
     
     sKernelKext->flags.hasAllDependencies = 1;
     sKernelKext->flags.kernelComponent = 1;
@@ -546,6 +723,7 @@ OSKext::initialize(void)
     sKernelKext->flags.loaded = 1;
     sKernelKext->flags.started = 1;
     sKernelKext->flags.CPPInitialized = 0;
+    sKernelKext->flags.jettisonLinkeditSeg = 0;
 
     sKernelKext->kmod_info = &g_kernel_kmod_info;
     strlcpy(g_kernel_kmod_info.version, osrelease,
@@ -601,19 +779,23 @@ OSKext::initialize(void)
     registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType);
     registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype);
 
-    OSSafeRelease(kernelCPUType);
-    OSSafeRelease(kernelCPUSubtype);
+    OSSafeReleaseNULL(kernelCPUType);
+    OSSafeReleaseNULL(kernelCPUSubtype);
 
     timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
     *timestamp = 0;
     timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
     *timestamp = 0;
+    timestamp = __OSAbsoluteTimePtr(&sLastWakeTime);
+    *timestamp = 0;
 
     OSKextLog(/* kext */ NULL,
         kOSKextLogProgressLevel |
         kOSKextLogGeneralFlag,
         "Kext system initialized.");
 
+    notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
+
     return;
 }
 
@@ -628,7 +810,6 @@ OSKext::removeKextBootstrap(void)
     OSReturn                   result                = kOSReturnError;
     
     static bool                alreadyDone           = false;
-    boolean_t                  keepsyms              = FALSE;
 
     const char               * dt_kernel_header_name = "Kernel-__HEADER";
     const char               * dt_kernel_symtab_name = "Kernel-__SYMTAB";
@@ -639,7 +820,8 @@ OSKext::removeKextBootstrap(void)
     int                        dt_result             = 0;
 
     kernel_segment_command_t * seg_to_remove         = NULL;
-#if __ppc__ || __arm__
+
+#if __arm__ || __arm64__
     const char               * dt_segment_name       = NULL;
     void                     * segment_paddress      = NULL;
     int                        segment_size          = 0;
@@ -661,8 +843,6 @@ OSKext::removeKextBootstrap(void)
         kOSKextLogGeneralFlag,
         "Jettisoning kext bootstrap segments.");
 
-    PE_parse_boot_argn("keepsyms", &keepsyms, sizeof(keepsyms));
    /*****
     * Dispose of unnecessary stuff that the booter didn't need to load.
     */
@@ -688,14 +868,20 @@ OSKext::removeKextBootstrap(void)
         OSRuntimeUnloadCPPForSegment(seg_to_remove);
     }
 
-#if __ppc__ || __arm__
+#if __arm__ || __arm64__
+#if !(defined(KERNEL_INTEGRITY_KTRR))
    /* Free the memory that was set up by bootx.
     */
     dt_segment_name = "Kernel-__KLD";
     if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
+       /* We cannot free this with KTRR enabled, as we cannot
+        * update the permissions on the KLD range this late
+        * in the boot process.
+        */
         IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
             (int)segment_size);
     }
+#endif /* !(defined(KERNEL_INTEGRITY_KTRR)) */
 #elif __i386__ || __x86_64__
    /* On x86, use the mapping data from the segment load command to
     * unload KLD directly.
@@ -703,6 +889,10 @@ OSKext::removeKextBootstrap(void)
     * defining the lower bound for valid physical addresses.
     */
     if (seg_to_remove && seg_to_remove->vmaddr && seg_to_remove->vmsize) {
+        // 04/18/11 - gab: <rdar://problem/9236163>
+        // overwrite memory occupied by KLD segment with random data before
+        // releasing it.
+        read_frandom((void *) seg_to_remove->vmaddr, seg_to_remove->vmsize);
         ml_static_mfree(seg_to_remove->vmaddr, seg_to_remove->vmsize);
     }
 #else
@@ -711,7 +901,7 @@ OSKext::removeKextBootstrap(void)
 
     seg_to_remove = NULL;
 
-   /*****
+    /*****
     * Prelinked kernel's symtab (if there is one).
     */
     kernel_section_t * sect;
@@ -720,36 +910,110 @@ OSKext::removeKextBootstrap(void)
         ml_static_mfree(sect->addr, sect->size);
     }
 
-   /*****
-    * Dump the LINKEDIT segment, unless keepsyms is set.
-    */
-    if (!keepsyms) {
-        seg_to_remove = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
-        if (seg_to_remove) {
-            OSRuntimeUnloadCPPForSegment(seg_to_remove);
+    seg_to_remove = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
+
+    /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
+     * pageable, unless keepsyms is set.  To do that, we have to copy it from
+     * its booter-allocated memory, free the booter memory, reallocate proper
+     * managed memory, then copy the segment back in.
+     */
+#if CONFIG_KXLD
+#if (__arm__ || __arm64__)
+#error CONFIG_KXLD not expected for this arch
+#endif
+    if (!sKeepSymbols) {
+        kern_return_t mem_result;
+        void *seg_copy = NULL;
+        void *seg_data = NULL;
+        vm_map_offset_t seg_offset = 0;
+        vm_map_offset_t seg_copy_offset = 0;
+        vm_map_size_t seg_length = 0;
+
+        seg_data = (void *) seg_to_remove->vmaddr;
+        seg_offset = (vm_map_offset_t) seg_to_remove->vmaddr;
+        seg_length = (vm_map_size_t) seg_to_remove->vmsize;
+
+       /* Allocate space for the LINKEDIT copy.
+        */
+        mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
+            seg_length, VM_KERN_MEMORY_KEXT);
+        if (mem_result != KERN_SUCCESS) {
+            OSKextLog(/* kext */ NULL,
+                kOSKextLogErrorLevel |
+                kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
+                "Can't copy __LINKEDIT segment for VM reassign.");
+            goto finish;
+        }
+        seg_copy_offset = (vm_map_offset_t) seg_copy;
+
+       /* Copy it out.
+        */
+        memcpy(seg_copy, seg_data, seg_length);
+
+       /* Dump the booter memory.
+        */
+        ml_static_mfree(seg_offset, seg_length);
+
+       /* Set up the VM region.
+        */
+        mem_result = vm_map_enter_mem_object(
+            kernel_map,
+            &seg_offset,
+            seg_length, /* mask */ 0, 
+            VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, 
+           VM_MAP_KERNEL_FLAGS_NONE,
+           VM_KERN_MEMORY_NONE,
+            (ipc_port_t)NULL,
+            (vm_object_offset_t) 0,
+            /* copy */ FALSE,
+            /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
+            /* max_protection */ VM_PROT_ALL,
+            /* inheritance */ VM_INHERIT_DEFAULT);
+        if ((mem_result != KERN_SUCCESS) || 
+            (seg_offset != (vm_map_offset_t) seg_data))
+        {
+            OSKextLog(/* kext */ NULL,
+                kOSKextLogErrorLevel |
+                kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
+                "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
+                seg_data, seg_length, mem_result);
+            goto finish;
         }
 
-#if __ppc__ || __arm__
+       /* And copy it back.
+        */
+        memcpy(seg_data, seg_copy, seg_length);
+
+       /* Free the copy.
+        */
+        kmem_free(kernel_map, seg_copy_offset, seg_length);
+    }
+#else /* we are not CONFIG_KXLD */
+#if !(__arm__ || __arm64__)
+#error CONFIG_KXLD is expected for this arch
+#endif
+
+    /*****
+    * Dump the LINKEDIT segment, unless keepsyms is set.
+    */
+    if (!sKeepSymbols) {
         dt_segment_name = "Kernel-__LINKEDIT";
         if (0 == IODTGetLoaderInfo(dt_segment_name,
             &segment_paddress, &segment_size)) {
-
+#ifdef SECURE_KERNEL
+            vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
+            bzero((void*)vmaddr, segment_size);
+#endif
             IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
                 (int)segment_size);
         }
-#elif __i386__ || __x86_64__
-        if (seg_to_remove && seg_to_remove->vmaddr && seg_to_remove->vmsize) {
-            ml_static_mfree(seg_to_remove->vmaddr, seg_to_remove->vmsize);
-        }
-#else
-#error arch
-#endif
     } else {
         OSKextLog(/* kext */ NULL,
-            kOSKextLogBasicLevel |
-            kOSKextLogGeneralFlag,
-            "keepsyms boot arg specified; keeping linkedit segment for symbols.");
+           kOSKextLogBasicLevel |
+           kOSKextLogGeneralFlag,
+           "keepsyms boot arg specified; keeping linkedit segment for symbols.");
     }
+#endif /* CONFIG_KXLD */
 
     seg_to_remove = NULL;
 
@@ -850,9 +1114,9 @@ OSKext::flushNonloadedKexts(
 finish:
     IORecursiveLockUnlock(sKextLock);
 
-    OSSafeRelease(prelinkedKexts);
-    OSSafeRelease(kextIterator);
-    OSSafeRelease(prelinkIterator);
+    OSSafeReleaseNULL(prelinkedKexts);
+    OSSafeReleaseNULL(kextIterator);
+    OSSafeReleaseNULL(prelinkIterator);
 
     return;
 }
@@ -866,13 +1130,61 @@ OSKext::setKextdActive(Boolean active)
     IORecursiveLockLock(sKextLock);
     sKextdActive = active;
     if (sKernelRequests->getCount()) {
-        OSKextPingKextd();
+        OSKext::pingKextd();
     }
     IORecursiveLockUnlock(sKextLock);
 
     return;
 }
 
+/*********************************************************************
+* OSKextLib.cpp might need access to this someday but for now it's
+* private.
+*********************************************************************/
+extern "C" {
+extern void ipc_port_release_send(ipc_port_t);
+};
+
+/* static */
+OSReturn
+OSKext::pingKextd(void)
+{
+    OSReturn    result     = kOSReturnError;
+#if !NO_KEXTD
+    mach_port_t kextd_port = IPC_PORT_NULL;
+
+    if (!sKextdActive) {
+        result = kOSKextReturnDisabled;  // basically unavailable
+        goto finish;
+    }
+
+    result = host_get_kextd_port(host_priv_self(), &kextd_port);
+    if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
+        OSKextLog(/* kext */ NULL,
+            kOSKextLogErrorLevel |
+            kOSKextLogIPCFlag,
+            "Can't get kextd port.");
+        goto finish;
+    }
+
+    result = kextd_ping(kextd_port);
+    if (result != KERN_SUCCESS) {
+        OSKextLog(/* kext */ NULL,
+            kOSKextLogErrorLevel |
+            kOSKextLogIPCFlag,
+            "kextd ping failed (0x%x).", (int)result);
+        goto finish;
+    }
+
+finish:
+    if (IPC_PORT_VALID(kextd_port)) {
+        ipc_port_release_send(kextd_port);
+    }
+#endif
+
+    return result;
+}
+
 /*********************************************************************
 *********************************************************************/
 /* static */
@@ -893,7 +1205,9 @@ OSKext::setDeferredLoadSucceeded(Boolean succeeded)
 void
 OSKext::willShutdown(void)
 {
+#if !NO_KEXTD
     OSReturn       checkResult = kOSReturnError;
+#endif
     OSDictionary * exitRequest = NULL;  // must release
 
     IORecursiveLockLock(sKextLock);
@@ -903,6 +1217,7 @@ OSKext::willShutdown(void)
     OSKext::setAutounloadsEnabled(false);
     OSKext::setKernelRequestsEnabled(false);
 
+#if !NO_KEXTD
     OSKextLog(/* kext */ NULL,
         kOSKextLogProgressLevel |
         kOSKextLogGeneralFlag,
@@ -917,12 +1232,14 @@ OSKext::willShutdown(void)
         goto finish;
     }
 
-    OSKextPingKextd();
+    OSKext::pingKextd();
 
 finish:
+#endif
+
     IORecursiveLockUnlock(sKextLock);
 
-    OSSafeRelease(exitRequest);
+    OSSafeReleaseNULL(exitRequest);
     return;
 }
 
@@ -1110,11 +1427,12 @@ OSKext::getKernelRequestsEnabled(void)
 *********************************************************************/
 OSKext *
 OSKext::withPrelinkedInfoDict(
-    OSDictionary * anInfoDict)
+    OSDictionary * anInfoDict,
+    bool doCoalesedSlides)
 {
     OSKext * newKext = new OSKext;
 
-    if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict)) {
+    if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalesedSlides)) {
         newKext->release();
         return NULL;
     }
@@ -1126,18 +1444,16 @@ OSKext::withPrelinkedInfoDict(
 *********************************************************************/
 bool
 OSKext::initWithPrelinkedInfoDict(
-    OSDictionary * anInfoDict)
+    OSDictionary * anInfoDict,
+    bool doCoalesedSlides)
 {
     bool            result              = false;
-    kern_return_t   alloc_result        = KERN_SUCCESS;
     OSString      * kextPath            = NULL;  // do not release
     OSNumber      * addressNum          = NULL;  // reused; do not release
     OSNumber      * lengthNum           = NULL;  // reused; do not release
     void          * data                = NULL;  // do not free
     void          * srcData             = NULL;  // do not free
     OSData        * prelinkedExecutable = NULL;  // must release
-    void          * linkStateCopy       = NULL;  // kmem_free on error
-    uint32_t        linkStateLength     = 0;
     uint32_t        length              = 0;     // reused
 
     if (!super::init()) {
@@ -1152,63 +1468,23 @@ OSKext::initWithPrelinkedInfoDict(
     if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
         goto finish;
     }
+#if KASLR_KEXT_DEBUG
+    IOLog("kaslr: doCoalesedSlides %d kext %s \n", doCoalesedSlides, getIdentifierCString());
+#endif
 
-   /* Don't need the path to be in the info dictionary any more.
+   /* Also get the executable's bundle-relative path if present.
+    * Don't look for an arch-specific path property.
     */
-    anInfoDict->removeObject(kPrelinkBundlePathKey);
+    executableRelPath = OSDynamicCast(OSString,
+        anInfoDict->getObject(kPrelinkExecutableRelativePathKey));
+    if (executableRelPath) {
+        executableRelPath->retain();
+    }
 
-   /* If we have a link state, create an OSData wrapper for it.
+   /* Don't need the paths to be in the info dictionary any more.
     */
-    addressNum = OSDynamicCast(OSNumber,
-        anInfoDict->getObject(kPrelinkLinkStateKey));
-    if (addressNum) {
-        lengthNum = OSDynamicCast(OSNumber, 
-            anInfoDict->getObject(kPrelinkLinkStateSizeKey));
-        if (!lengthNum) {
-            OSKextLog(this,
-                kOSKextLogErrorLevel |
-                kOSKextLogArchiveFlag,
-                "Kext %s can't find prelinked kext link state size.",
-                getIdentifierCString());
-            goto finish;
-        }
-
-        data = (void *) (intptr_t) (addressNum->unsigned64BitValue());
-        linkStateLength = (uint32_t) (lengthNum->unsigned32BitValue());
-
-        anInfoDict->removeObject(kPrelinkLinkStateKey);
-        anInfoDict->removeObject(kPrelinkLinkStateSizeKey);
-
-       /* Copy the link state out of the booter-provided memory so it is in
-        * the VM system and we can page it out.
-        */
-        alloc_result = kmem_alloc_pageable(kernel_map,
-            (vm_offset_t *)&linkStateCopy, linkStateLength);
-        if (alloc_result != KERN_SUCCESS) {
-            OSKextLog(this,
-                kOSKextLogErrorLevel |
-                kOSKextLogArchiveFlag,
-                "Kext %s failed to copy prelinked link state.",
-                getIdentifierCString());
-            goto finish;
-        }
-        memcpy(linkStateCopy, data, linkStateLength);
-
-        linkState = OSData::withBytesNoCopy(linkStateCopy, linkStateLength);
-        if (!linkState) {
-            OSKextLog(this,
-                kOSKextLogErrorLevel |
-                kOSKextLogArchiveFlag,
-                "Kext %s failed to create link state wrapper.",
-                getIdentifierCString());
-            goto finish;
-        }
-        linkState->setDeallocFunction(osdata_kmem_free);
-
-       /* Clear linkStateCopy; the OSData owns it now so we mustn't free it.
-        */
-        linkStateCopy = NULL;
-    }
+    anInfoDict->removeObject(kPrelinkBundlePathKey);
+    anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
 
    /* Create an OSData wrapper around the linked executable.
     */
@@ -1226,48 +1502,58 @@ OSKext::initWithPrelinkedInfoDict(
             goto finish;
         }
 
-        data = (void *) (intptr_t) (addressNum->unsigned64BitValue());
+        data = (void *) ((intptr_t) (addressNum->unsigned64BitValue()) + vm_kernel_slide);
         length = (uint32_t) (lengthNum->unsigned32BitValue());
 
+#if KASLR_KEXT_DEBUG
+        IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
+              (unsigned long)VM_KERNEL_UNSLIDE(data), 
+              (unsigned long)data,
+              length);
+#endif
+
         anInfoDict->removeObject(kPrelinkExecutableLoadKey);
         anInfoDict->removeObject(kPrelinkExecutableSizeKey);
 
-       /* If the kext's load address differs from its source address, allocate
-        * space in the kext map at the load address and copy the kext over.
-        */
+        /* If the kext's load address differs from its source address, allocate
+         * space in the kext map at the load address and copy the kext over.
+         */
         addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
         if (addressNum) {
-            srcData = (void *) (intptr_t) (addressNum->unsigned64BitValue());
-
+            srcData = (void *) ((intptr_t) (addressNum->unsigned64BitValue()) + vm_kernel_slide);
+            
+#if KASLR_KEXT_DEBUG
+            IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
+                  (unsigned long)VM_KERNEL_UNSLIDE(srcData),
+                  (unsigned long)srcData);
+#endif
+            
             if (data != srcData) {
 #if __LP64__
+                kern_return_t alloc_result;
+                
                 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
                 if (alloc_result != KERN_SUCCESS) {
                     OSKextLog(this,
-                        kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
-                        "Failed to allocate space for prelinked kext %s.",
-                        getIdentifierCString());
+                              kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
+                              "Failed to allocate space for prelinked kext %s.",
+                              getIdentifierCString());
                     goto finish;
                 }
                 memcpy(data, srcData, length);
 #else
                 OSKextLog(this,
-                    kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
-                    "Error: prelinked kext %s - source and load addresses "
-                    "differ on ILP32 architecture.",
-                    getIdentifierCString());
+                          kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
+                          "Error: prelinked kext %s - source and load addresses "
+                          "differ on ILP32 architecture.",
+                          getIdentifierCString());
                 goto finish;
 #endif /* __LP64__ */
             }
-
+            
             anInfoDict->removeObject(kPrelinkExecutableSourceKey);
         }
 
-       /* We don't need to set a dealloc function for the linked executable
-        * because it is freed separately in OSKext::unload(), which must unwire
-        * part of the memory.
-        * xxx - do we *have* to do it that way?
-        */
         prelinkedExecutable = OSData::withBytesNoCopy(data, length);
         if (!prelinkedExecutable) {
             OSKextLog(this,
@@ -1277,8 +1563,13 @@ OSKext::initWithPrelinkedInfoDict(
                 getIdentifierCString());
             goto finish;
         }
-        setLinkedExecutable(prelinkedExecutable);
 
+#if VM_MAPPED_KEXTS
+        prelinkedExecutable->setDeallocFunction(osdata_kext_free);
+#else
+        prelinkedExecutable->setDeallocFunction(osdata_phys_free);
+#endif
+        setLinkedExecutable(prelinkedExecutable);
         addressNum = OSDynamicCast(OSNumber,
             anInfoDict->getObject(kPrelinkKmodInfoKey));
         if (!addressNum) {
@@ -1290,7 +1581,18 @@ OSKext::initWithPrelinkedInfoDict(
             goto finish;
         }
 
-        kmod_info = (kmod_info_t *) (intptr_t) (addressNum->unsigned64BitValue());
+        if (addressNum->unsigned64BitValue() != 0) {
+            kmod_info = (kmod_info_t *) (intptr_t) (addressNum->unsigned64BitValue() + vm_kernel_slide);
+            kmod_info->address += vm_kernel_slide;
+#if KASLR_KEXT_DEBUG
+            IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
+                  (unsigned long)VM_KERNEL_UNSLIDE(kmod_info), 
+                  (unsigned long)kmod_info);
+            IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n", 
+                  (unsigned long)VM_KERNEL_UNSLIDE(kmod_info->address), 
+                  (unsigned long)kmod_info->address);
+ #endif
+        }
 
         anInfoDict->removeObject(kPrelinkKmodInfoKey);
     }
@@ -1306,6 +1608,19 @@ OSKext::initWithPrelinkedInfoDict(
         }
     }
 
+    result = slidePrelinkedExecutable(doCoalesedSlides);
+    if (result != kOSReturnSuccess) {
+        goto finish;
+    }
+
+    if (doCoalesedSlides == false) {
+        /* set VM protections now, wire later at kext load */
+        result = setVMAttributes(true, false);
+        if (result != KERN_SUCCESS) {
+            goto finish;
+        }
+    }
+    
     flags.prelinked = true;
 
    /* If we created a kext from prelink info,
@@ -1316,16 +1631,43 @@ OSKext::initWithPrelinkedInfoDict(
     result = registerIdentifier();
 
 finish:
+    OSSafeReleaseNULL(prelinkedExecutable);
 
-   /* If we didn't hand linkStateCopy off to an OSData, free it.
-    */
-    if (linkStateCopy) {
-        kmem_free(kernel_map, (vm_offset_t)linkStateCopy, linkStateLength);
+    return result;
+}
+
+/*********************************************************************
+ *********************************************************************/
+/* static */
+void OSKext::setAllVMAttributes(void)
+{
+    OSCollectionIterator * kextIterator     = NULL;  // must release
+    const OSSymbol * thisID                 = NULL;  // do not release
+
+    IORecursiveLockLock(sKextLock);
+
+    kextIterator = OSCollectionIterator::withCollection(sKextsByID);
+    if (!kextIterator) {
+        goto finish;
+    }
+    
+    while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
+        OSKext *    thisKext;  // do not release
+        
+        thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
+        if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
+            continue;
+        }
+       
+        /* set VM protections now, wire later at kext load */
+        thisKext->setVMAttributes(true, false);
     }
     
-    OSSafeRelease(prelinkedExecutable);
+finish:
+    IORecursiveLockUnlock(sKextLock);
+    OSSafeReleaseNULL(kextIterator);
 
-    return result;
+    return;
 }
 
 /*********************************************************************
@@ -1367,7 +1709,7 @@ OSKext::initWithBooterData(
     void                * executableAddr = NULL;  // do not free
     char                * bundlePathAddr = NULL;  // do not free
 
-    OSObject            * parsedXML = NULL;  // must release
+    OSObject            * parsedXML      = NULL;  // must release
     OSDictionary        * theInfoDict    = NULL;  // do not release
     OSString            * kextPath       = NULL;  // must release
     OSString            * errorString    = NULL;  // must release
@@ -1503,10 +1845,10 @@ OSKext::initWithBooterData(
     result = registerIdentifier();
 
 finish:
-    OSSafeRelease(parsedXML);
-    OSSafeRelease(kextPath);
-    OSSafeRelease(errorString);
-    OSSafeRelease(executable);
+    OSSafeReleaseNULL(parsedXML);
+    OSSafeReleaseNULL(kextPath);
+    OSSafeReleaseNULL(errorString);
+    OSSafeReleaseNULL(executable);
 
     return result;
 }
@@ -1527,6 +1869,8 @@ OSKext::registerIdentifier(void)
     OSData        * newUUID             = NULL;  // must release
     OSData        * existingUUID        = NULL;  // must release
 
+    IORecursiveLockLock(sKextLock);
+
    /* Get the new kext's version for checks & log messages.
     */
     newVersion = getVersion();
@@ -1691,6 +2035,8 @@ OSKext::registerIdentifier(void)
 
 finish:
 
+    IORecursiveLockUnlock(sKextLock);
+
     if (result) {
         OSKextLog(this,
             kOSKextLogStepLevel |
@@ -1699,8 +2045,8 @@ finish:
             getIdentifierCString(), newVersionCString);
     }
 
-    OSSafeRelease(newUUID);
-    OSSafeRelease(existingUUID);
+    OSSafeReleaseNULL(newUUID);
+    OSSafeReleaseNULL(existingUUID);
 
     return result;
 }
@@ -1708,21 +2054,20 @@ finish:
 /*********************************************************************
 * Does the bare minimum validation to look up a kext.
 * All other validation is done on the spot as needed.
-*
-* No need for lock, only called from init
 **********************************************************************/
 bool
 OSKext::setInfoDictionaryAndPath(
     OSDictionary * aDictionary,
     OSString     * aPath)
 {
-    bool          result                   = false;
-    OSString    * bundleIDString           = NULL;  // do not release
-    OSString    * versionString            = NULL;  // do not release
-    OSString    * compatibleVersionString  = NULL;  // do not release
-    const char  * versionCString           = NULL;  // do not free
-    const char  * compatibleVersionCString = NULL;  // do not free
-    OSBoolean   * scratchBool              = NULL;  // do not release
+    bool           result                   = false;
+    OSString     * bundleIDString           = NULL;  // do not release
+    OSString     * versionString            = NULL;  // do not release
+    OSString     * compatibleVersionString  = NULL;  // do not release
+    const char   * versionCString           = NULL;  // do not free
+    const char   * compatibleVersionCString = NULL;  // do not free
+    OSBoolean    * scratchBool              = NULL;  // do not release
+    OSDictionary * scratchDict              = NULL;  // do not release
 
     if (infoDict) {
         panic("Attempt to set info dictionary on a kext "
@@ -1839,19 +2184,28 @@ OSKext::setInfoDictionaryAndPath(
             goto finish;
         }
     }
+    
+    /* Check to see if this kext is in exclude list */
+    if ( isInExcludeList() ) {
+        OSKextLog(this,
+                  kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
+                  "Kext %s is in exclude list, not loadable",
+                  getIdentifierCString());
+        goto finish;
+    }
 
    /* Set flags for later use if the infoDict gets flushed. We only
     * check for true values, not false ones(!)
     */
     scratchBool = OSDynamicCast(OSBoolean,
         getPropertyForHostArch(kOSBundleIsInterfaceKey));
-    if (scratchBool && scratchBool->isTrue()) {
+    if (scratchBool == kOSBooleanTrue) {
         flags.interface = 1;
     }
     
     scratchBool = OSDynamicCast(OSBoolean,
         getPropertyForHostArch(kOSKernelResourceKey));
-    if (scratchBool && scratchBool->isTrue()) {
+    if (scratchBool == kOSBooleanTrue) {
         flags.kernelComponent = 1;
         flags.interface = 1;  // xxx - hm. the kernel itself isn't an interface...
         flags.started = 1;
@@ -1861,6 +2215,14 @@ OSKext::setInfoDictionaryAndPath(
         flags.hasAllDependencies = 1;
     }
 
+   /* Make sure common string values in personalities are uniqued to OSSymbols.
+    */
+    scratchDict = OSDynamicCast(OSDictionary, 
+        getPropertyForHostArch(kIOKitPersonalitiesKey));
+    if (scratchDict) {
+        uniquePersonalityProperties(scratchDict);
+    }
+
     result = true;
 
 finish:
@@ -1888,7 +2250,7 @@ OSKext::setExecutable(
         result = true;
         goto finish;
     }
-
+    
     if (infoDict->getObject(_kOSKextExecutableKey) ||
         infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
 
@@ -1919,21 +2281,110 @@ finish:
 
 /*********************************************************************
 *********************************************************************/
-void
-OSKext::free(void)
+static void
+uniqueStringPlistProperty(OSDictionary * dict, const char * key)
+{
+    OSString       * stringValue = NULL;  // do not release
+    const OSSymbol * symbolValue = NULL;  // must release
+
+    stringValue = OSDynamicCast(OSString, dict->getObject(key));
+    if (!stringValue) {
+        goto finish;
+    }
+    
+    symbolValue = OSSymbol::withString(stringValue);
+    if (!symbolValue) {
+        goto finish;
+    }
+
+    dict->setObject(key, symbolValue);
+    
+finish:
+    if (symbolValue) symbolValue->release();
+
+    return;
+}
+
+/*********************************************************************
+*********************************************************************/
+static void
+uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
+{
+    OSString       * stringValue = NULL;  // do not release
+    const OSSymbol * symbolValue = NULL;  // must release
+
+    stringValue = OSDynamicCast(OSString, dict->getObject(key));
+    if (!stringValue) {
+        goto finish;
+    }
+    
+    symbolValue = OSSymbol::withString(stringValue);
+    if (!symbolValue) {
+        goto finish;
+    }
+
+    dict->setObject(key, symbolValue);
+    
+finish:
+    if (symbolValue) symbolValue->release();
+
+    return;
+}
+
+/*********************************************************************
+* Replace common personality property values with uniqued instances
+* to save on wired memory.
+*********************************************************************/
+/* static */
+void
+OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
+{
+   /* Properties every personality has.
+    */
+    uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
+    uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
+    uniqueStringPlistProperty(personalityDict, gIOClassKey);
+    
+   /* Other commonly used properties.
+    */
+    uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
+    uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
+    uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
+
+    uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
+    uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
+    uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
+    uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
+    uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher"); 
+    uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
+    uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
+    uniqueStringPlistProperty(personalityDict, "Vendor");
+    uniqueStringPlistProperty(personalityDict, "Vendor Identification");
+    uniqueStringPlistProperty(personalityDict, "Vendor Name");
+    uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
+    uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
+    uniqueStringPlistProperty(personalityDict, "idProduct");
+
+    return;
+}
+
+/*********************************************************************
+*********************************************************************/
+void
+OSKext::free(void)
 {
     if (isLoaded()) {
         panic("Attempt to free loaded kext %s.", getIdentifierCString());
     }
 
-    OSSafeRelease(infoDict);
-    OSSafeRelease(bundleID);
-    OSSafeRelease(path);
-    OSSafeRelease(dependencies);
-    OSSafeRelease(linkState);
-    OSSafeRelease(linkedExecutable);
-    OSSafeRelease(metaClasses);
-    OSSafeRelease(interfaceUUID);
+    OSSafeReleaseNULL(infoDict);
+    OSSafeReleaseNULL(bundleID);
+    OSSafeReleaseNULL(path);
+    OSSafeReleaseNULL(executableRelPath);
+    OSSafeReleaseNULL(dependencies);
+    OSSafeReleaseNULL(linkedExecutable);
+    OSSafeReleaseNULL(metaClasses);
+    OSSafeReleaseNULL(interfaceUUID);
 
     if (isInterface() && kmod_info) {
         kfree(kmod_info, sizeof(kmod_info_t));
@@ -1967,7 +2418,7 @@ OSKext::readMkextArchive(OSData * mkextData,
             "Mkext archive too small to be valid.");
         goto finish;
     }
-
+    
     mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
     
     if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
@@ -1991,8 +2442,6 @@ OSKext::readMkextArchive(OSData * mkextData,
 
     if (mkextVersion == MKEXT_VERS_2) {
         result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
-    } else if (mkextVersion == MKEXT_VERS_1) {
-        result = OSKext::readMkext1Archive(mkextData, checksumPtr);
     } else {
         OSKextLog(/* kext */ NULL,
             kOSKextLogErrorLevel |
@@ -2005,332 +2454,6 @@ finish:
     return result;
 }
 
-/*********************************************************************
-* Assumes magic, signature, version, length have been checked.
-*
-* Doesn't do as much bounds-checking as it should, but we're dropping
-* mkext1 support from the kernel for SnowLeopard soon.
-*
-* Should keep track of all kexts created so far, and if we hit a
-* fatal error halfway through, remove those kexts. If we've dropped
-* an older version that had already been read, whoops! Might want to
-* add a level of buffering?
-*********************************************************************/
-/* static */
-OSReturn
-OSKext::readMkext1Archive(
-    OSData   * mkextData,
-    uint32_t * checksumPtr)
-{
-    OSReturn        result              = kOSReturnError;
-    uint32_t        mkextLength;
-    mkext1_header * mkextHeader         = 0;  // do not free
-    void          * mkextEnd            = 0;  // do not free
-    uint32_t        mkextVersion;
-    uint8_t       * crc_address         = 0;
-    uint32_t        checksum;
-    uint32_t        numKexts            = 0;
-    
-    OSData        * infoDictDataObject  = NULL;  // must release
-    OSObject      * parsedXML      = NULL;  // must release
-    OSDictionary  * infoDict            = NULL;  // do not release
-    OSString      * errorString         = NULL;  // must release
-    OSData        * mkextExecutableInfo = NULL;  // must release
-    OSKext        * theKext             = NULL;  // must release
-
-    mkextLength = mkextData->getLength();
-    mkextHeader = (mkext1_header *)mkextData->getBytesNoCopy();
-    mkextEnd = (char *)mkextHeader + mkextLength;
-    mkextVersion = OSSwapBigToHostInt32(mkextHeader->version);
-
-    crc_address = (u_int8_t *)&mkextHeader->version;
-    checksum = mkext_adler32(crc_address,
-        (uintptr_t)mkextHeader +
-        OSSwapBigToHostInt32(mkextHeader->length) - (uintptr_t)crc_address);
-
-    if (OSSwapBigToHostInt32(mkextHeader->adler32) != checksum) {
-        OSKextLog(/* kext */ NULL,
-            kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
-            "Kext archive has a bad checksum.");
-        result = kOSKextReturnBadData;
-        goto finish;
-    }
-
-    if (checksumPtr) {
-        *checksumPtr = checksum;
-    }
-
-   /* Check that the CPU type & subtype match that of the running kernel. */
-    if (OSSwapBigToHostInt32(mkextHeader->cputype) != (UInt32)CPU_TYPE_ANY) {
-        if ((UInt32)_mh_execute_header.cputype !=
-            OSSwapBigToHostInt32(mkextHeader->cputype)) {
-
-            OSKextLog(/* kext */ NULL,
-                kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
-                "Kext archive doesn't contain software "
-                "for this computer's CPU type.");
-            result = kOSKextReturnArchNotFound;
-            goto finish;
-        }
-    }
-    
-    numKexts = OSSwapBigToHostInt32(mkextHeader->numkexts);
-
-    for (uint32_t i = 0; i < numKexts; i++) {
-
-        OSSafeReleaseNULL(infoDictDataObject);
-        OSSafeReleaseNULL(infoDict);
-        OSSafeReleaseNULL(mkextExecutableInfo);
-        OSSafeReleaseNULL(errorString);
-        OSSafeReleaseNULL(theKext);
-
-        mkext_kext * kextEntry = &mkextHeader->kext[i];
-        mkext_file * infoDictPtr = &kextEntry->plist;
-        mkext_file * executablePtr = &kextEntry->module;
-        if (kextEntry >= mkextEnd) {
-            OSKextLog(/* kext */ NULL,
-                kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
-                "Mkext file overrun.");
-            result = kOSKextReturnBadData;
-            goto finish;
-        }
-
-       /* Note that we're pretty tolerant of errors in individual entries.
-        * As long as we can keep processing, we do.
-        */
-        infoDictDataObject = OSKext::extractMkext1Entry(
-            mkextHeader, infoDictPtr);
-        if (!infoDictDataObject) {
-            OSKextLog(/* kext */ NULL,
-                kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
-                "Can't uncompress info dictionary "
-                "from mkext archive entry %d.", i);
-            continue;
-        }
-
-        parsedXML = OSUnserializeXML(
-                (const char *)infoDictDataObject->getBytesNoCopy(),
-                &errorString);
-        if (parsedXML) {
-            infoDict = OSDynamicCast(OSDictionary, parsedXML);
-        }
-        if (!infoDict) {
-            const char * errorCString = "(unknown error)";
-            
-            if (errorString && errorString->getCStringNoCopy()) {
-                errorCString = errorString->getCStringNoCopy();
-            } else if (parsedXML) {
-                errorCString = "not a dictionary";
-            }
-            OSKextLog(/* kext */ NULL,
-                kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
-                "Error: Can't read XML property list "
-                  "for mkext archive entry %d: %s.", i, errorCString);
-            continue;
-        }
-
-        theKext = new OSKext;
-        if (!theKext) {
-            OSKextLog(/* kext */ NULL,
-                kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
-                "Kext allocation failure.");
-            continue;
-        }
-
-       /*****
-        * Prepare an entry to hold the mkext entry info for the
-        * compressed binary module, if there is one. If all four fields
-        * of the module entry are zero, there isn't one.
-        */
-        if ((OSSwapBigToHostInt32(executablePtr->offset) ||
-            OSSwapBigToHostInt32(executablePtr->compsize) ||
-            OSSwapBigToHostInt32(executablePtr->realsize) ||
-            OSSwapBigToHostInt32(executablePtr->modifiedsecs))) {
-
-            MkextEntryRef entryRef;
-
-            mkextExecutableInfo = OSData::withCapacity(sizeof(entryRef));
-            if (!mkextExecutableInfo) {
-                panic("Error: Couldn't allocate data object "
-                      "for mkext archive entry %d.\n", i);
-            }
-
-            entryRef.mkext = (mkext_basic_header *)mkextHeader;
-            entryRef.fileinfo = (uint8_t *)executablePtr;
-            if (!mkextExecutableInfo->appendBytes(&entryRef,
-                sizeof(entryRef))) {
-
-                OSKextLog(/* kext */ NULL,
-                    kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
-                    "Couldn't record executable info "
-                    "for mkext archive entry %d.", i);
-                // we might hit a load error later but oh well
-                // xxx - should probably remove theKext
-                continue;
-            }
-
-        }
-
-       /* Init can fail because of a data/runtime error, or because the
-        * kext is a dup. Either way, we don't care here.
-        */
-        if (!theKext->initWithMkext1Info(infoDict, mkextExecutableInfo,
-            mkextData)) {
-
-            // theKext is released at the top of the loop or in the finish block
-            continue;
-        }
-
-       /* If we got even one kext out of the mkext archive,
-        * we have successfully read the archive, in that we
-        * have data references into its mapped memory.
-        */
-        result = kOSReturnSuccess;
-    }
-
-finish:
-
-    OSSafeRelease(infoDictDataObject);
-    OSSafeRelease(parsedXML);
-    OSSafeRelease(errorString);
-    OSSafeRelease(mkextExecutableInfo);
-    OSSafeRelease(theKext);
-
-    return result;
-}
-
-/*********************************************************************
-*********************************************************************/
-bool
-OSKext::initWithMkext1Info(
-    OSDictionary * anInfoDict,
-    OSData       * executableWrapper,
-    OSData       * mkextData)
-{
-    bool result = false;
-    
-    // mkext1 doesn't allow for path (might stuff in info dict)
-    if (!setInfoDictionaryAndPath(anInfoDict, /* path */ NULL)) {
-        goto finish;
-    }
-
-    if (!registerIdentifier()) {
-        goto finish;
-    }
-    
-    if (!setExecutable(executableWrapper, mkextData, true)) {
-        goto finish;
-    }
-    
-    result = true;
-    
-finish:
-
-   /* If we can't init, remove the kext from the lookup dictionary.
-    * This is safe to call in init because there's an implicit retain.
-    */
-    if (!result) {
-        OSKext::removeKext(this, /* removePersonalities? */ false);
-    }
-
-    return result;
-}
-
-/*********************************************************************
-* xxx - this should take the input data length
-*********************************************************************/
-/* static */
-OSData *
-OSKext::extractMkext1Entry(
-    const void  * mkextFileBase,
-    const void  * entry)
-{
-    OSData      * result                 = NULL;
-    OSData      * uncompressedData       = NULL;  // release on error
-    const char  * errmsg                 = NULL;
-
-    mkext_file  * fileinfo;
-    uint8_t     * uncompressedDataBuffer = 0; // do not free (panic on alloc. fail)
-    size_t        uncompressed_size      = 0;
-    kern_return_t kern_result;
-
-    fileinfo = (mkext_file *)entry;
-
-    size_t offset = OSSwapBigToHostInt32(fileinfo->offset);
-    size_t compressed_size = OSSwapBigToHostInt32(fileinfo->compsize);
-    size_t expected_size = OSSwapBigToHostInt32(fileinfo->realsize);
-
-    // Add 1 for '\0' to terminate XML string (for plists)
-    // (we really should have the archive format include that).
-    size_t alloc_size = expected_size + 1;
-    time_t modifiedsecs = OSSwapBigToHostInt32(fileinfo->modifiedsecs);
-
-   /* If these four fields are zero there's no file, but it's up to
-    * the calling context to decide if that's an error.
-    */
-    if (offset == 0 && compressed_size == 0 &&
-        expected_size == 0 && modifiedsecs == 0) {
-        goto finish;
-    }
-
-    kern_result = kmem_alloc(kernel_map,
-        (vm_offset_t *)&uncompressedDataBuffer,
-        alloc_size);
-    if (kern_result != KERN_SUCCESS) {
-        panic(ALLOC_FAIL);
-        goto finish;
-    }
-
-    uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer,
-        alloc_size);
-    if (uncompressedData == NULL) {
-       /* No need to free uncompressedDataBuffer here, either. */
-        panic(ALLOC_FAIL);
-        goto finish;
-    }
-    uncompressedData->setDeallocFunction(&osdata_kmem_free);
-
-   /* Do the decompression if necessary. Note that even if the file isn't
-    * compressed, we want to make a copy so that we don't have the tie to
-    * the larger mkext file buffer any more.
-    * xxx - need to detect decompression overflow too
-    */
-    if (compressed_size != 0) {
-        errmsg = "OSKext::uncompressMkext - "
-            "uncompressed file shorter than expected";
-        uncompressed_size = decompress_lzss(uncompressedDataBuffer,
-            expected_size,
-            ((uint8_t *)mkextFileBase) + offset,
-            compressed_size);
-        if (uncompressed_size != expected_size) {
-            goto finish;
-        }
-    } else {
-        memcpy(uncompressedDataBuffer,
-            ((uint8_t *)mkextFileBase) + offset,
-            expected_size);
-    }
-
-    // Add a terminating nul character in case the data is XML.
-    // (we really should have the archive format include that).
-    uncompressedDataBuffer[expected_size] = '\0';
-
-    result = uncompressedData;
-    errmsg = NULL;
-
-finish:
-    if (!result) {
-        OSKextLog(/* kext */ NULL,
-            kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
-            "%s", errmsg);
-
-        if (uncompressedData) {
-            uncompressedData->release();
-        }
-    }
-    return result;
-}
-
 /*********************************************************************
 * Assumes magic, signature, version, length have been checked.
 * xxx - need to add further bounds checking for each file entry
@@ -2361,7 +2484,7 @@ OSKext::readMkext2Archive(
     OSString      * errorString                = NULL;  // must release
     OSData        * mkextPlistUncompressedData = NULL;  // must release
     const char    * mkextPlistDataBuffer       = NULL;  // do not free
-    OSObject      * parsedXML           = NULL;  // must release
+    OSObject      * parsedXML                  = NULL;  // must release
     OSDictionary  * mkextPlist                 = NULL;  // do not release
     OSArray       * mkextInfoDictArray         = NULL;  // do not release
     uint32_t        count, i;
@@ -2482,14 +2605,16 @@ OSKext::readMkext2Archive(
 
 
         infoDict = OSDynamicCast(OSDictionary,
-            mkextInfoDictArray->getObject(i));
-
+                                 mkextInfoDictArray->getObject(i));
+        
        /* Create the kext for the entry, then release it, because the
         * kext system keeps them around until explicitly removed.
         * Any creation/registration failures are already logged for us.
         */
-        OSKext * newKext = OSKext::withMkext2Info(infoDict, mkextData);
-        OSSafeRelease(newKext);
+        if (infoDict) {
+            OSKext * newKext = OSKext::withMkext2Info(infoDict, mkextData);
+            OSSafeReleaseNULL(newKext);
+        }
     }
 
    /* Even if we didn't keep any kexts from the mkext, we may have a load
@@ -2499,9 +2624,9 @@ OSKext::readMkext2Archive(
 
 finish:
 
-    OSSafeRelease(parsedXML);
-    OSSafeRelease(mkextPlistUncompressedData);
-    OSSafeRelease(errorString);
+    OSSafeReleaseNULL(parsedXML);
+    OSSafeReleaseNULL(mkextPlistUncompressedData);
+    OSSafeReleaseNULL(errorString);
 
     return result;
 }
@@ -2537,22 +2662,31 @@ OSKext::initWithMkext2Info(
     OSCollectionIterator * iterator            = NULL;  // must release
     OSData               * executable          = NULL;  // must release
 
-    if (!super::init()) {
+    if (anInfoDict == NULL || !super::init()) {
         goto finish;
     }
 
    /* Get the path. Don't look for an arch-specific path property.
     */
     kextPath = OSDynamicCast(OSString,
-        anInfoDict->getObject(kMKEXTBundlePathKey));
+                             anInfoDict->getObject(kMKEXTBundlePathKey));
 
     if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
         goto finish;
     }
 
-   /* Don't need the path to be in the info dictionary any more.
+   /* If we have a path to the executable, save it.
+    */
+    executableRelPath = OSDynamicCast(OSString,
+        anInfoDict->getObject(kMKEXTExecutableRelativePathKey));
+    if (executableRelPath) {
+        executableRelPath->retain();
+    }
+
+   /* Don't need the paths to be in the info dictionary any more.
     */
     anInfoDict->removeObject(kMKEXTBundlePathKey);
+    anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
 
     executableOffsetNum = OSDynamicCast(OSNumber,
         infoDict->getObject(kMKEXTExecutableKey));
@@ -2572,8 +2706,8 @@ OSKext::initWithMkext2Info(
 
 finish:
 
-    OSSafeRelease(executable);
-    OSSafeRelease(iterator);
+    OSSafeReleaseNULL(executable);
+    OSSafeReleaseNULL(iterator);
     return result;
 }
 
@@ -2632,10 +2766,23 @@ z_alloc(void * notused __unused, u_int num_items, u_int size)
 {
     void     * result = NULL;
     z_mem    * zmem = NULL;
-    uint32_t   total = num_items * size;
-    uint32_t   allocSize =  total + sizeof(zmem);
+
+    uint64_t   total = ((uint64_t)num_items) * ((uint64_t)size);
+    //Check for overflow due to multiplication 
+    if (total > UINT32_MAX){
+        panic("z_alloc(%p, %x, %x): overflow caused by %x * %x\n",
+               notused, num_items, size, num_items, size);
+    }
     
-    zmem = (z_mem *)kalloc(allocSize);
+    uint64_t   allocSize64 =  total + ((uint64_t)sizeof(zmem));
+    //Check for overflow due to addition
+    if (allocSize64 > UINT32_MAX){
+        panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx\n",
+               notused, num_items, size, (uint32_t)total, sizeof(zmem));
+    }
+    uint32_t allocSize = (uint32_t)allocSize64;
+
+    zmem = (z_mem *)kalloc_tag(allocSize, VM_KERN_MEMORY_OSKEXT);
     if (!zmem) {
         goto finish;
     }
@@ -2683,12 +2830,12 @@ OSKext::extractMkext2FileData(
     }
 
     if (KERN_SUCCESS != kmem_alloc(kernel_map,
-        (vm_offset_t*)&uncompressedDataBuffer, fullSize)) {
+        (vm_offset_t*)&uncompressedDataBuffer, fullSize, VM_KERN_MEMORY_OSKEXT)) {
 
        /* How's this for cheesy? The kernel is only asked to extract
         * kext plists so we tailor the log messages.
         */
-        if (this == sKernelKext) {
+        if (isKernel()) {
             OSKextLog(this,
                 kOSKextLogErrorLevel |
                 kOSKextLogArchiveFlag,
@@ -2705,7 +2852,7 @@ OSKext::extractMkext2FileData(
     }
     uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
     if (!uncompressedData) {
-        if (this == sKernelKext) {
+        if (isKernel()) {
             OSKextLog(this,
                 kOSKextLogErrorLevel |
                 kOSKextLogArchiveFlag,
@@ -2721,7 +2868,7 @@ OSKext::extractMkext2FileData(
     }
     uncompressedData->setDeallocFunction(&osdata_kmem_free);
 
-    if (this == sKernelKext) {
+    if (isKernel()) {
         OSKextLog(this,
             kOSKextLogDetailLevel |
             kOSKextLogArchiveFlag,
@@ -2747,7 +2894,7 @@ OSKext::extractMkext2FileData(
 
     zlib_result = inflateInit(&zstream);
     if (Z_OK != zlib_result) {
-        if (this == sKernelKext) {
+        if (isKernel()) {
             OSKextLog(this,
                 kOSKextLogErrorLevel |
                 kOSKextLogArchiveFlag,
@@ -2770,7 +2917,7 @@ OSKext::extractMkext2FileData(
     if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
         uncompressedSize = zstream.total_out;
     } else {
-        if (this == sKernelKext) {
+        if (isKernel()) {
             OSKextLog(this,
                 kOSKextLogErrorLevel |
                 kOSKextLogArchiveFlag,
@@ -2793,7 +2940,7 @@ OSKext::extractMkext2FileData(
     }
 
     if (uncompressedSize != fullSize) {
-        if (this == sKernelKext) {
+        if (isKernel()) {
             OSKextLog(this,
                 kOSKextLogErrorLevel |
                 kOSKextLogArchiveFlag,
@@ -2818,7 +2965,7 @@ finish:
     if (zstream_inited) inflateEnd(&zstream);
 
     if (!result) {
-        OSSafeRelease(uncompressedData);
+        OSSafeReleaseNULL(uncompressedData);
     }
 
     return result;
@@ -2859,7 +3006,7 @@ OSKext::loadFromMkext(
     Boolean            delayAutounload           = false;
     OSKextExcludeLevel startKextExcludeLevel     = kOSKextExcludeNone;
     OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
-
+    
     IORecursiveLockLock(sKextLock);
 
     if (logInfoOut) {
@@ -2954,7 +3101,7 @@ OSKext::loadFromMkext(
     }
 
     startKextExcludeNum = OSDynamicCast(OSNumber,
-        requestArgs->getObject(kKextKextRequestArgumentStartExcludeKey));
+        requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
     startMatchingExcludeNum = OSDynamicCast(OSNumber,
         requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
     delayAutounloadBool = OSDynamicCast(OSBoolean,
@@ -3029,10 +3176,10 @@ finish:
 
     IORecursiveLockUnlock(sKextLock);
 
-    OSSafeRelease(mkextData);
-    OSSafeRelease(mkextPlist);
-    OSSafeRelease(serializer);
-    OSSafeRelease(logInfoArray);
+    OSSafeReleaseNULL(mkextData);
+    OSSafeReleaseNULL(mkextPlist);
+    OSSafeReleaseNULL(serializer);
+    OSSafeReleaseNULL(logInfoArray);
 
     return result;
 }
@@ -3084,7 +3231,7 @@ OSKext::serializeLogInfo(
         logInfo = serializer->text();
         logInfoLength = serializer->getLength();
 
-        kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, logInfoLength);
+        kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength), VM_KERN_MEMORY_OSKEXT);
         if (kmem_result != KERN_SUCCESS) {
             OSKextLog(/* kext */ NULL,
                 kOSKextLogErrorLevel |
@@ -3093,6 +3240,9 @@ OSKext::serializeLogInfo(
            /* Incidental error; we're going to (try to) allow the request
             * to succeed. */
         } else {
+            /* 11981737 - clear uninitialized data in last page */
+            bzero((void *)(buffer + logInfoLength),
+                  (round_page(logInfoLength) - logInfoLength));
             memcpy(buffer, logInfo, logInfoLength);
             *logInfoOut = buffer;
             *logInfoLengthOut = logInfoLength;
@@ -3101,7 +3251,7 @@ OSKext::serializeLogInfo(
     
     result = kOSReturnSuccess;
 finish:
-    OSSafeRelease(serializer);
+    OSSafeReleaseNULL(serializer);
     return result;
 }
 
@@ -3177,7 +3327,6 @@ OSKext::lookupKextWithAddress(vm_address_t address)
                 (vm_address_t)thisKext->linkedExecutable->getBytesNoCopy();
             vm_address_t kext_end = kext_start +
                 thisKext->linkedExecutable->getLength();
-            
             if ((kext_start <= address) && (address < kext_end)) {
                 foundKext = thisKext;
                 foundKext->retain();
@@ -3192,24 +3341,117 @@ finish:
     return foundKext;
 }
 
+OSData *
+OSKext::copyKextUUIDForAddress(OSNumber *address)
+{
+       OSData *uuid = NULL;
+
+       if (!address) {
+               return NULL;
+       }
+
+       uintptr_t addr = (uintptr_t)address->unsigned64BitValue() + vm_kernel_slide;
+
+#if CONFIG_MACF
+       /* Is the calling process allowed to query kext info? */
+       if (current_task() != kernel_task) {
+               int macCheckResult = 0;
+               kauth_cred_t cred = NULL;
+
+               cred = kauth_cred_get_with_ref();
+               macCheckResult = mac_kext_check_query(cred);
+               kauth_cred_unref(&cred);
+
+               if (macCheckResult != 0) {
+                       OSKextLog(/* kext */ NULL,
+                                       kOSKextLogErrorLevel | kOSKextLogLoadFlag,
+                                       "Failed to query kext UUID (MAC policy error 0x%x).",
+                                       macCheckResult);
+                       return NULL;
+               }
+       }
+#endif
+
+       if (((vm_offset_t)addr >= vm_kernel_stext) && ((vm_offset_t)addr < vm_kernel_etext)) {
+               /* address in xnu proper */
+               unsigned long uuid_len = 0;
+               uuid = OSData::withBytes(getuuidfromheader(&_mh_execute_header, &uuid_len), uuid_len);
+       } else {
+               IOLockLock(sKextSummariesLock);
+               OSKextLoadedKextSummary *summary = OSKext::summaryForAddress(addr);
+               if (summary) {
+                       uuid = OSData::withBytes(summary->uuid, sizeof(uuid_t));
+               }
+               IOLockUnlock(sKextSummariesLock);
+       }
+
+       return uuid;
+}
+
 /*********************************************************************
 *********************************************************************/
-/* static */
-bool OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
+OSKext *
+OSKext::lookupKextWithUUID(uuid_t wanted)
 {
-    bool result = false;
     OSKext * foundKext = NULL;                 // returned
+    uint32_t count, i;
 
     IORecursiveLockLock(sKextLock);
 
-    foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
-    if (foundKext && foundKext->isLoaded()) {
-        result = true;
+    count = sLoadedKexts->getCount();
+
+    for (i = 0; i < count; i++) {
+        OSKext   * thisKext     = NULL;
+
+        thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
+        if (!thisKext) {
+            continue;
+        }
+
+        OSData *uuid_data = thisKext->copyUUID();
+        if (!uuid_data) {
+            continue;
+        }
+
+        uuid_t uuid;
+        memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
+        uuid_data->release();
+
+        if (0 == uuid_compare(wanted, uuid)) {
+            foundKext = thisKext;
+            foundKext->retain();
+            goto finish;
+        }
+
     }
 
+finish:
     IORecursiveLockUnlock(sKextLock);
-    
-    return result;
+
+    return foundKext;
+}
+
+
+
+
+/*********************************************************************
+*********************************************************************/
+/* static */
+bool OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
+{
+    bool result = false;
+    OSKext * foundKext = NULL;                 // returned
+
+    IORecursiveLockLock(sKextLock);
+
+    foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
+    if (foundKext && foundKext->isLoaded()) {
+        result = true;
+    }
+
+    IORecursiveLockUnlock(sKextLock);
+    
+    return result;
 }
 
 /*********************************************************************
@@ -3220,10 +3462,27 @@ bool OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
 OSReturn
 OSKext::removeKext(
     OSKext * aKext,
+#if CONFIG_EMBEDDED
+    __unused
+#endif
     bool     terminateServicesAndRemovePersonalitiesFlag)
  {
+#if CONFIG_EMBEDDED
+    OSKextLog(aKext,
+        kOSKextLogErrorLevel |
+        kOSKextLogKextBookkeepingFlag,
+        "removeKext() called for %s, not supported on embedded",
+        aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
+
+    return kOSReturnSuccess;
+#else /* CONFIG_EMBEDDED */
+
     OSReturn result    = kOSKextReturnInUse;
     OSKext * checkKext = NULL;   // do not release
+#if CONFIG_MACF
+    int macCheckResult = 0;
+    kauth_cred_t cred  = NULL;
+#endif
 
     IORecursiveLockLock(sKextLock);
 
@@ -3243,6 +3502,29 @@ OSKext::removeKext(
     }
 
     if (aKext->isLoaded()) {
+#if CONFIG_MACF
+        if (current_task() != kernel_task) {
+            cred = kauth_cred_get_with_ref();
+            macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
+            kauth_cred_unref(&cred);
+        }
+
+        if (macCheckResult != 0) {
+            result = kOSReturnError;
+            OSKextLog(aKext,
+                kOSKextLogErrorLevel |
+                kOSKextLogKextBookkeepingFlag,
+                "Failed to remove kext %s (MAC policy error 0x%x).",
+                aKext->getIdentifierCString(), macCheckResult);
+            goto finish;
+        }
+#endif
+
+        /* make sure there are no resource requests in flight - 17187548 */
+        if (aKext->countRequestCallbacks()) {
+            goto finish;
+        }
+
        /* If we are terminating, send the request to the IOCatalogue
         * (which will actually call us right back but that's ok we have
         * a recursive lock don't you know) but do not ask the IOCatalogue
@@ -3253,7 +3535,7 @@ OSKext::removeKext(
                 aKext->getIdentifierCString(), /* unload */ false);
             if (result != kOSReturnSuccess) {
                 OSKextLog(aKext,
-                    kOSKextLogProgressLevel |
+                    kOSKextLogErrorLevel |
                     kOSKextLogKextBookkeepingFlag,
                     "Can't remove kext %s; services failed to terminate - 0x%x.",
                     aKext->getIdentifierCString(), result);
@@ -3278,17 +3560,18 @@ OSKext::removeKext(
     }
 
     OSKextLog(aKext,
-        kOSKextLogProgressLevel |
-        kOSKextLogKextBookkeepingFlag,
-        "Removing kext %s.",
-        aKext->getIdentifierCString());
-
+              kOSKextLogProgressLevel |
+              kOSKextLogKextBookkeepingFlag,
+              "Removing kext %s.",
+              aKext->getIdentifierCString());
+          
     sKextsByID->removeObject(aKext->getIdentifier());
     result = kOSReturnSuccess;
 
 finish:
     IORecursiveLockUnlock(sKextLock);
     return result;
+#endif /* CONFIG_EMBEDDED */
  }
 
 /*********************************************************************
@@ -3379,7 +3662,177 @@ OSKext::copyKexts(void)
 
     return result;
 }
+
+/*********************************************************************
+ *********************************************************************/
+#define BOOTER_KEXT_PREFIX   "Driver-"
+
+typedef struct _DeviceTreeBuffer {
+    uint32_t paddr;
+    uint32_t length;
+} _DeviceTreeBuffer;
+
+/*********************************************************************
+ * Create a dictionary of excluded kexts from the given booter data.
+ *********************************************************************/
+/* static */
+void
+OSKext::createExcludeListFromBooterData(
+                                        OSDictionary *          theDictionary,
+                                        OSCollectionIterator *  theIterator )
+{
+    OSString                  * deviceTreeName      = NULL;  // do not release
+    const _DeviceTreeBuffer   * deviceTreeBuffer    = NULL;  // do not release
+    char                      * booterDataPtr       = NULL;  // do not release
+    _BooterKextFileInfo       * kextFileInfo        = NULL;  // do not release
+    char                      * infoDictAddr        = NULL;  // do not release
+    OSObject                  * parsedXML           = NULL;  // must release
+    OSDictionary              * theInfoDict         = NULL;  // do not release
+    
+    theIterator->reset();
+    
+    /* look for AppleKextExcludeList.kext */
+    while ( (deviceTreeName =
+             OSDynamicCast(OSString, theIterator->getNextObject())) ) {
+        
+        const char *    devTreeNameCString;
+        OSData *        deviceTreeEntry;
+        OSString *      myBundleID;    // do not release
+        
+        OSSafeReleaseNULL(parsedXML);
+        
+        deviceTreeEntry = 
+        OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
+        if (!deviceTreeEntry) {
+            continue;
+        }
+        
+        /* Make sure it is a kext */
+        devTreeNameCString = deviceTreeName->getCStringNoCopy();
+        if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
+                    (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
+            OSKextLog(NULL,
+                      kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 
+                      "\"%s\" not a kext",
+                      devTreeNameCString);
+            continue;
+        }
+        
+        deviceTreeBuffer = (const _DeviceTreeBuffer *)
+        deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
+        if (!deviceTreeBuffer) {
+            continue;
+        }
+        
+        booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
+        if (!booterDataPtr) {
+            continue;
+        }
+        
+        kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
+        if (!kextFileInfo->infoDictPhysAddr || 
+            !kextFileInfo->infoDictLength)       {
+            continue;
+        }
+        
+        infoDictAddr = (char *)
+        ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
+        if (!infoDictAddr) {
+            continue;
+        }
+        
+        parsedXML = OSUnserializeXML(infoDictAddr);
+        if (!parsedXML) {
+            continue;
+        }
+        
+        theInfoDict = OSDynamicCast(OSDictionary, parsedXML);
+        if (!theInfoDict) {
+            continue;
+        }
+        
+        myBundleID = 
+        OSDynamicCast(OSString, 
+                      theInfoDict->getObject(kCFBundleIdentifierKey));
+        if ( myBundleID && 
+            strcmp( myBundleID->getCStringNoCopy(), "com.apple.driver.KextExcludeList" ) == 0 ) {
+            
+            /* get copy of exclusion list dictionary */
+            OSDictionary *      myTempDict;     // do not free
+            
+            myTempDict = OSDynamicCast(
+                                       OSDictionary,
+                                       theInfoDict->getObject("OSKextExcludeList"));
+            if ( NULL == myTempDict ) {
+                /* 25322874 */
+                panic("Missing OSKextExcludeList dictionary\n");
+            }
+            
+            IORecursiveLockLock(sKextLock);
+            
+            /* get rid of old exclusion list */
+            if (sExcludeListByID) {
+                OSSafeReleaseNULL(sExcludeListByID);
+            }
+            sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
+            IORecursiveLockUnlock(sKextLock);
+
+            break;
+        }
+        
+    } // while ( (deviceTreeName = ...) )
+    
+    OSSafeReleaseNULL(parsedXML);
+    return;
+}
+
+/*********************************************************************
+ * Create a dictionary of excluded kexts from the given prelink 
+ * info (kernelcache).
+ *********************************************************************/
+/* static */
+void
+OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
+{
+    OSDictionary *  myInfoDict = NULL;  // do not release
+    OSString *      myBundleID;         // do not release
+    u_int           i;
+    
+    /* Find com.apple.driver.KextExcludeList. */
+    for (i = 0; i < theInfoArray->getCount(); i++) {
+        myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
+        if (!myInfoDict) {
+            continue;
+        }
+        myBundleID = 
+        OSDynamicCast(OSString, 
+                      myInfoDict->getObject(kCFBundleIdentifierKey));
+        if ( myBundleID && 
+            strcmp( myBundleID->getCStringNoCopy(), "com.apple.driver.KextExcludeList" ) == 0 ) {
+            // get copy of exclude list dictionary
+            OSDictionary *      myTempDict;     // do not free
+            myTempDict = OSDynamicCast(OSDictionary,
+                                       myInfoDict->getObject("OSKextExcludeList"));
+            if ( NULL == myTempDict ) {
+                /* 25322874 */
+                panic("Missing OSKextExcludeList dictionary\n");
+            }
+            
+            IORecursiveLockLock(sKextLock);
+            // get rid of old exclude list
+            if (sExcludeListByID) {
+                OSSafeReleaseNULL(sExcludeListByID);
+            }
+            
+            sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
+            IORecursiveLockUnlock(sKextLock);
+            break;
+        }
+    } // for (i = 0; i < theInfoArray->getCount()...
+    
+    return;
+}
+
 #if PRAGMA_MARK
 #pragma mark Accessors
 #endif
@@ -3417,6 +3870,14 @@ OSKext::getCompatibleVersion(void)
     return compatibleVersion;
 }
 
+/*********************************************************************
+*********************************************************************/
+bool
+OSKext::isLibrary(void)
+{
+    return (getCompatibleVersion() > 0);
+}
+
 /*********************************************************************
 *********************************************************************/
 bool
@@ -3434,10 +3895,7 @@ OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
 bool
 OSKext::declaresExecutable(void)
 {
-    if (getPropertyForHostArch(kCFBundleExecutableKey)) {
-        return true;
-     }
-     return false;
+    return (getPropertyForHostArch(kCFBundleExecutableKey) != NULL);
 }
 
 /*********************************************************************
@@ -3470,9 +3928,6 @@ OSKext::getExecutable(void)
             extractedExecutable = extractMkext2FileData(
                 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
                 compressedSize, fullSize);
-        } else if (mkextVersion == MKEXT_VERS_1) {
-            extractedExecutable = extractMkext1Entry(
-                mkextEntryRef->mkext, mkextEntryRef->fileinfo);
         } else {
             OSKextLog(this, kOSKextLogErrorLevel |
             kOSKextLogArchiveFlag,
@@ -3499,7 +3954,7 @@ OSKext::getExecutable(void)
 
 finish:
 
-    OSSafeRelease(extractedExecutable);
+    OSSafeReleaseNULL(extractedExecutable);
 
     return result;
 }
@@ -3512,6 +3967,14 @@ OSKext::isInterface(void)
     return flags.interface;
 }
 
+/*********************************************************************
+*********************************************************************/
+bool
+OSKext::isKernel(void)
+{
+    return (this == sKernelKext);
+}
+
 /*********************************************************************
 *********************************************************************/
 bool
@@ -3520,6 +3983,14 @@ OSKext::isKernelComponent(void)
     return flags.kernelComponent ? true : false;
 }
 
+/*********************************************************************
+*********************************************************************/
+bool
+OSKext::isExecutable(void)
+{
+    return (!isKernel() && !isInterface() && declaresExecutable());
+}
+
 /*********************************************************************
 * We might want to check this recursively for all dependencies,
 * since a subtree of dependencies could get loaded before we hit
@@ -3538,6 +4009,10 @@ OSKext::isLoadableInSafeBoot(void)
     bool       result   = false;
     OSString * required = NULL;  // do not release
     
+    if (isKernel()) {
+        result = true;
+        goto finish;
+    }
     
     required = OSDynamicCast(OSString,
         getPropertyForHostArch(kOSBundleRequiredKey));
@@ -3604,6 +4079,28 @@ OSKext::getLoadTag(void)
     return loadTag;
 }
 
+/*********************************************************************
+ *********************************************************************/
+void OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
+{
+    if (linkedExecutable) {
+        *loadSize = linkedExecutable->getLength();
+           
+        /* If we have a kmod_info struct, calculated the wired size
+         * from that. Otherwise it's the full load size.
+         */
+        if (kmod_info) {
+            *wiredSize = *loadSize - kmod_info->hdr_size;
+        } else {
+            *wiredSize = *loadSize;
+        }
+    }
+    else {
+        *wiredSize = 0;
+        *loadSize = 0;
+    }
+}
+
 /*********************************************************************
 *********************************************************************/
 OSData *
@@ -3638,7 +4135,16 @@ OSKext::copyUUID(void)
 
     header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
     load_cmd = (const struct load_command *)&header[1];
-
+        
+    if (header->magic != MH_MAGIC_KERNEL) {
+        OSKextLog(NULL,
+                  kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
+                  "%s: bad header %p",
+                  __func__,
+                  header);
+        goto finish;
+    }
+    
     for (i = 0; i < header->ncmds; i++) {
         if (load_cmd->cmd == LC_UUID) {
             uuid_cmd = (struct uuid_command *)load_cmd;
@@ -3654,12 +4160,30 @@ finish:
 
 /*********************************************************************
 *********************************************************************/
-#if defined (__ppc__)
-#define ARCHNAME "ppc"
-#elif defined (__i386__)
-#define ARCHNAME "i386"
-#elif defined (__x86_64__)
+#if defined (__arm__)
+#include <arm/arch.h>
+#endif
+
+#if   defined (__x86_64__)
 #define ARCHNAME "x86_64"
+#elif defined (__arm64__)
+#define ARCHNAME "arm64"
+#elif defined (__arm__)
+
+#if defined (__ARM_ARCH_7S__)
+#define ARCHNAME "armv7s"
+#elif defined (__ARM_ARCH_7F__)
+#define ARCHNAME "armv7f"
+#elif defined (__ARM_ARCH_7K__)
+#define ARCHNAME "armv7k"
+#elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
+#define ARCHNAME "armv7"
+#elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
+#define ARCHNAME "armv6"
+#endif
+
+#elif defined (__arm64__)
+#define ARCHNAME "arm64"
 #else
 #error architecture not supported
 #endif
@@ -3675,7 +4199,7 @@ static char * makeHostArchKey(const char * key, uint32_t * keySizeOut)
    /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
     */
     keySize = 1 + 1 + strlen(key) + strlen(ARCHNAME);
-    result = (char *)kalloc(keySize);
+    result = (char *)kalloc_tag(keySize, VM_KERN_MEMORY_OSKEXT);
     if (!result) {
         goto finish;
     }
@@ -3732,8 +4256,115 @@ finish:
 #if PRAGMA_MARK
 #pragma mark Load/Start/Stop/Unload
 #endif
+
+#define isWhiteSpace(c)        ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
+
+/*********************************************************************
+ * sExcludeListByID is a dictionary with keys / values of:
+ *  key = bundleID string of kext we will not allow to load
+ *  value = version string(s) of the kext that is to be denied loading.
+ *      The version strings can be comma delimited.  For example if kext
+ *      com.foocompany.fookext has two versions that we want to deny
+ *      loading then the version strings might look like:
+ *      1.0.0, 1.0.1
+ *      If the current fookext has a version of 1.0.0 OR 1.0.1 we will
+ *      not load the kext.
+ *
+ *      Value may also be in the form of "LE 2.0.0" (version numbers
+ *      less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version 
+ *      number less than 2.0.0 will not load)
+ *
+ *      NOTE - we cannot use the characters "<=" or "<" because we have code 
+ *      that serializes plists and treats '<' as a special character.
+ *********************************************************************/
+bool 
+OSKext::isInExcludeList(void)
+{
+    OSString *      versionString           = NULL;  // do not release
+    char *          versionCString          = NULL;  // do not free
+    size_t          i;
+    boolean_t       wantLessThan = false;
+    boolean_t       wantLessThanEqualTo = false;
+    char            myBuffer[32];
+    
+    if (!sExcludeListByID) {
+        return(false);
+    }
+    /* look up by bundleID in our exclude list and if found get version
+     * string (or strings) that we will not allow to load
+     */
+    versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID));
+    if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
+        return(false);
+    }
+    
+    /* parse version strings */
+    versionCString = (char *) versionString->getCStringNoCopy();
+    
+    /* look for "LT" or "LE" form of version string, must be in first two
+     * positions.
+     */
+    if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
+        wantLessThan = true;
+        versionCString +=2; 
+    }
+    else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
+        wantLessThanEqualTo = true;
+        versionCString +=2;
+    }
+
+    for (i = 0; *versionCString != 0x00; versionCString++) {
+        /* skip whitespace */
+        if (isWhiteSpace(*versionCString)) {
+            continue;
+        }
+        
+        /* peek ahead for version string separator or null terminator */
+        if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
+            
+            /* OK, we have a version string */
+            myBuffer[i++] = *versionCString;
+            myBuffer[i] = 0x00;
+
+            OSKextVersion excludeVers;
+            excludeVers = OSKextParseVersionString(myBuffer);
+                
+            if (wantLessThanEqualTo) {
+                if (version <= excludeVers) {
+                    return(true);
+                }
+            }
+            else if (wantLessThan) {
+                if (version < excludeVers) {
+                    return(true);
+                }
+            }
+            else if ( version == excludeVers )  {
+                return(true);
+            }
+            
+            /* reset for the next (if any) version string */
+            i = 0;
+            wantLessThan = false;
+            wantLessThanEqualTo = false;
+        }
+        else {
+            /* save valid version character */
+            myBuffer[i++] = *versionCString;
+            
+            /* make sure bogus version string doesn't overrun local buffer */
+            if ( i >= sizeof(myBuffer) ) {
+                break;
+            }
+        }
+    }
+    
+    return(false);
+} 
+
 /*********************************************************************
 *********************************************************************/
+/* static */
 OSReturn
 OSKext::loadKextWithIdentifier(
     const char       * kextIdentifierCString,
@@ -3756,11 +4387,10 @@ OSKext::loadKextWithIdentifier(
         startOpt, startMatchingOpt, personalityNames);
         
 finish:
-    OSSafeRelease(kextIdentifier);
+    OSSafeReleaseNULL(kextIdentifier);
     return result;
 }
 
-
 /*********************************************************************
 *********************************************************************/
 OSReturn
@@ -3773,6 +4403,7 @@ OSKext::loadKextWithIdentifier(
     OSArray           * personalityNames)
 {
     OSReturn          result               = kOSReturnError;
+    OSReturn          pingResult           = kOSReturnError;
     OSKext          * theKext              = NULL;  // do not release
     OSDictionary    * loadRequest          = NULL;  // must release
     const OSSymbol  * kextIdentifierSymbol = NULL;  // must release
@@ -3840,13 +4471,12 @@ OSKext::loadKextWithIdentifier(
                 kextIdentifier->getCStringNoCopy());
         }
 
-        if (sKextdActive) {
-            OSKextPingKextd();
-        } else {
+        pingResult = OSKext::pingKextd();
+        if (pingResult == kOSKextReturnDisabled) {
             OSKextLog(/* kext */ NULL,
                 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
                 kOSKextLogLoadFlag,
-                "Not loading kext %s - not found and kextd not available in early boot.",
+                "Kext %s might not load - kextd is currently unavailable.",
                 kextIdentifier->getCStringNoCopy());
         }
 
@@ -3878,8 +4508,8 @@ OSKext::loadKextWithIdentifier(
     }
 
 finish:
-    OSSafeRelease(loadRequest);
-    OSSafeRelease(kextIdentifierSymbol);
+    OSSafeReleaseNULL(loadRequest);
+    OSSafeReleaseNULL(kextIdentifierSymbol);
     
     IORecursiveLockUnlock(sKextLock);
 
@@ -3907,6 +4537,7 @@ OSKext::recordIdentifierRequest(
         goto finish;
     }
 
+    IORecursiveLockLock(sKextLock);
     if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol)) {
         if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol)) {
             fail = true;
@@ -3920,6 +4551,8 @@ OSKext::recordIdentifierRequest(
                 kextIdentifier->getCStringNoCopy());
         }
     }
+    IORecursiveLockUnlock(sKextLock);
+
 finish:
 
     if (fail) {
@@ -3929,7 +4562,7 @@ finish:
             "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
             kextIdentifier->getCStringNoCopy());
     }
-    OSSafeRelease(kextIdentifierSymbol);
+    OSSafeReleaseNULL(kextIdentifierSymbol);
     return;
 }
 
@@ -3949,6 +4582,17 @@ OSKext::load(
     Boolean              alreadyLoaded                = false;
     OSKext             * lastLoadedKext               = NULL;
 
+    if (isInExcludeList()) {
+        OSKextLog(this,
+                  kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
+                  kOSKextLogLoadFlag,
+                  "Kext %s is in exclude list, not loadable",
+                  getIdentifierCString());
+        
+        result = kOSKextReturnNotLoadable;
+        goto finish;
+    }
+
     if (isLoaded()) {
         alreadyLoaded = true;
         result = kOSReturnSuccess;
@@ -3960,6 +4604,26 @@ OSKext::load(
             getIdentifierCString());
         goto loaded;
     }
+    
+#if CONFIG_MACF
+    if (current_task() != kernel_task) {
+        int                 macCheckResult      = 0;
+        kauth_cred_t        cred                = NULL;
+
+        cred = kauth_cred_get_with_ref();
+        macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
+        kauth_cred_unref(&cred);
+        
+        if (macCheckResult != 0) {
+            result = kOSReturnError;
+            OSKextLog(this,
+                      kOSKextLogErrorLevel | kOSKextLogLoadFlag,
+                      "Failed to load kext %s (MAC policy error 0x%x).",
+                      getIdentifierCString(), macCheckResult);
+            goto finish;
+        }
+   }
+#endif
 
     if (!sLoadEnabled) {
         OSKextLog(this,
@@ -4008,12 +4672,11 @@ OSKext::load(
         kOSKextLogProgressLevel | kOSKextLogLoadFlag,
         "Loading kext %s.",
         getIdentifierCString());
-
-
+    
     if (!sKxldContext) {
         kxldResult = kxld_create_context(&sKxldContext, &kern_allocate, 
             &kxld_log_callback, /* Flags */ (KXLDFlags) 0, 
-            /* cputype */ 0, /* cpusubtype */ 0);
+            /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
         if (kxldResult) {
             OSKextLog(this,
                 kOSKextLogErrorLevel |
@@ -4095,6 +4758,21 @@ OSKext::load(
         goto finish;
     }
 
+    pendingPgoHead.next = &pendingPgoHead;
+    pendingPgoHead.prev = &pendingPgoHead;
+
+    uuid_generate(instance_uuid);
+    account = IONew(OSKextAccount, 1);
+    if (!account) {
+       result = KERN_MEMORY_ERROR;
+       goto finish;
+    }
+    bzero(account, sizeof(*account));
+    account->loadTag = kmod_info->id;
+    account->site.refcount = 0;
+    account->site.flags = VM_TAG_KMOD;
+    account->kext = this;
+
     flags.loaded = true;
 
    /* Add the kext to the list of loaded kexts and update the kmod_info
@@ -4106,7 +4784,7 @@ OSKext::load(
 
    /* Keep the kernel itself out of the kmod list.
     */
-    if (lastLoadedKext == sKernelKext) {
+    if (lastLoadedKext->isKernel()) {
         lastLoadedKext = NULL;
     }
 
@@ -4114,6 +4792,8 @@ OSKext::load(
         kmod_info->next = lastLoadedKext->kmod_info;
     }
 
+    notifyKextLoadObservers(this, kmod_info);
+
    /* Make the global kmod list point at the just-loaded kext. Note that the
     * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
     * although we do report it in kextstat these days by using the newer
@@ -4127,19 +4807,38 @@ OSKext::load(
 
    /* Save the list of loaded kexts in case we panic.
     */
-    clock_get_uptime(&last_loaded_timestamp);
     OSKext::saveLoadedKextPanicList();
 
-loaded:
+    if (isExecutable()) {
+        OSKext::updateLoadedKextSummaries();
+        savePanicString(/* isLoading */ true);
 
-    if (declaresExecutable() && (startOpt == kOSKextExcludeNone)) {
-        result = start();
-        if (result != kOSReturnSuccess) {
-            OSKextLog(this,
-                kOSKextLogErrorLevel | kOSKextLogLoadFlag,
-                "Kext %s start failed (result 0x%x).",
-                getIdentifierCString(), result);
-            result = kOSKextReturnStartStopError;
+#if CONFIG_DTRACE
+        registerWithDTrace();
+#else
+        jettisonLinkeditSegment();
+#endif /* CONFIG_DTRACE */
+
+#if !VM_MAPPED_KEXTS
+        /* If there is a page (or more) worth of padding after the end
+         * of the last data section but before the end of the data segment
+         * then free it in the same manner the LinkeditSegment is freed
+         */
+        jettisonDATASegmentPadding();
+#endif
+    }
+
+loaded:
+    if (isExecutable() && !flags.started) {
+        if (startOpt == kOSKextExcludeNone) {
+            result = start();
+            if (result != kOSReturnSuccess) {
+                OSKextLog(this,
+                    kOSKextLogErrorLevel | kOSKextLogLoadFlag,
+                    "Kext %s start failed (result 0x%x).",
+                    getIdentifierCString(), result);
+                result = kOSKextReturnStartStopError;
+            }
         }
     }
     
@@ -4151,6 +4850,7 @@ loaded:
     if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
         result = sendPersonalitiesToCatalog(true, personalityNames);
     }
+
 finish:
 
    /* More hack! If the kext doesn't declare an executable, even if we
@@ -4183,44 +4883,328 @@ finish:
             kOSKextLogLoadFlag,
             "Kext %s loaded.",
             getIdentifierCString());
+
+        queueKextNotification(kKextRequestPredicateLoadNotification,
+            OSDynamicCast(OSString, bundleID));
     }
     return result;
 }
 
 /*********************************************************************
-* called only by load()
+* 
 *********************************************************************/
-OSReturn
-OSKext::loadExecutable()
+static char * strdup(const char * string)
 {
-    OSReturn              result             = kOSReturnError;
-    kern_return_t         kxldResult;
-    u_char            **  kxlddeps           = NULL;  // must kfree
-    uint32_t              num_kxlddeps       = 0;
-    uint32_t              num_kmod_refs      = 0;
-    u_char              * linkStateBytes     = NULL;  // do not free
-    u_long                linkStateLength    = 0;
-    u_char             ** linkStateBytesPtr  = NULL;  // do not free
-    u_long              * linkStateLengthPtr = NULL;  // do not free
-    struct mach_header ** kxldHeaderPtr      = NULL;  // do not free
-    struct mach_header  * kxld_header        = NULL;  // xxx - need to free here?
-    OSData              * theExecutable      = NULL;  // do not release
-    OSString            * versString         = NULL;  // do not release
-    const char          * versCString        = NULL;  // do not free
-    const char          * string             = NULL;  // do not free
-    unsigned int          i;
-
-   /* We need the version string for a variety of bits below.
-    */
-    versString = OSDynamicCast(OSString,
-        getPropertyForHostArch(kCFBundleVersionKey));
-    if (!versString) {
+    char * result = NULL;
+    size_t size;
+    
+    if (!string) {
         goto finish;
     }
-    versCString = versString->getCStringNoCopy();
-
-    if (isKernelComponent()) {
+    
+    size = 1 + strlen(string);
+    result = (char *)kalloc_tag(size, VM_KERN_MEMORY_OSKEXT);
+    if (!result) {
+        goto finish;
+    }
+    
+    memcpy(result, string, size);
+
+finish:
+    return result;
+}
+
+/*********************************************************************
+* 
+*********************************************************************/
+
+kernel_section_t *
+OSKext::lookupSection(const char *segname, const char *secname)
+{
+    kernel_section_t         * found_section = NULL;
+    kernel_mach_header_t     * mh            = NULL;
+    kernel_segment_command_t * seg           = NULL;
+    kernel_section_t         * sec           = NULL;
+
+    mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
+
+    for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
+
+        if (0 != strcmp(seg->segname, segname)) {
+            continue;
+        }
+
+        for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
+
+            if (0 == strcmp(sec->sectname, secname)) {
+                found_section = sec;
+                goto out;
+            }
+        }
+    }
+
+ out:
+    return found_section;
+}
+
+/*********************************************************************
+*
+*********************************************************************/
+
+OSReturn
+OSKext::slidePrelinkedExecutable(bool doCoalesedSlides)
+{
+    OSReturn                       result           = kOSKextReturnBadData;
+    kernel_mach_header_t         * mh               = NULL;
+    kernel_segment_command_t     * seg              = NULL;
+    kernel_segment_command_t     * linkeditSeg      = NULL;
+    kernel_section_t             * sec              = NULL;
+    char                         * linkeditBase     = NULL;
+    bool                           haveLinkeditBase = false;
+    char                         * relocBase        = NULL;
+    bool                           haveRelocBase    = false;
+    struct dysymtab_command      * dysymtab         = NULL;
+    struct linkedit_data_command * segmentSplitInfo = NULL;
+    struct symtab_command        * symtab           = NULL;
+    kernel_nlist_t               * sym              = NULL;
+    struct relocation_info       * reloc            = NULL;
+    uint32_t                       i                = 0;
+    int                            reloc_size;
+    vm_offset_t                    new_kextsize;
+
+    if (linkedExecutable == NULL || vm_kernel_slide == 0) {
+        result = kOSReturnSuccess;
+        goto finish;
+    }
+
+    mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
+    segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
+
+    for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
+        if (!seg->vmaddr) {
+            continue;
+        }
+        seg->vmaddr += vm_kernel_slide;
+                
+#if KASLR_KEXT_DEBUG
+        IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
+              seg->segname,
+              (unsigned long)VM_KERNEL_UNSLIDE(seg->vmaddr), 
+              (unsigned long)seg->vmaddr);
+#endif
+       
+        if (!haveRelocBase) {
+            relocBase = (char *) seg->vmaddr;
+            haveRelocBase = true;
+        }
+        if (!strcmp(seg->segname, "__LINKEDIT")) {
+            linkeditBase = (char *) seg->vmaddr - seg->fileoff;
+            haveLinkeditBase = true;
+            linkeditSeg = seg;
+        }
+        for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
+            sec->addr += vm_kernel_slide;
+
+#if KASLR_KEXT_DEBUG
+            IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
+                  sec->sectname,
+                  (unsigned long)VM_KERNEL_UNSLIDE(sec->addr), 
+                  (unsigned long)sec->addr);
+#endif
+        }
+    }
+
+    dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
+
+    symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
+
+    if (symtab != NULL && doCoalesedSlides == false) {
+      /* Some pseudo-kexts have symbol tables without segments.
+       * Ignore them. */
+        if (symtab->nsyms > 0 && haveLinkeditBase) {
+            sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
+            for (i = 0; i < symtab->nsyms; i++) {
+                if (sym[i].n_type & N_STAB) {
+                    continue;
+                }
+                sym[i].n_value += vm_kernel_slide;
+                
+#if KASLR_KEXT_DEBUG
+#define MAX_SYMS_TO_LOG 5
+                if ( i < MAX_SYMS_TO_LOG ) {
+                    IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n", 
+                          (unsigned long)VM_KERNEL_UNSLIDE(sym[i].n_value), 
+                          (unsigned long)sym[i].n_value);
+                }
+#endif
+            }
+        }
+    }
+    
+    if (dysymtab != NULL && doCoalesedSlides == false) {
+        if (dysymtab->nextrel > 0) {
+            OSKextLog(this,
+                kOSKextLogErrorLevel | kOSKextLogLoadFlag |
+                kOSKextLogLinkFlag,
+                "Sliding kext %s: External relocations found.",
+                getIdentifierCString());
+            goto finish;
+        }
+
+        if (dysymtab->nlocrel > 0) {
+            if (!haveLinkeditBase) {
+                OSKextLog(this,
+                    kOSKextLogErrorLevel | kOSKextLogLoadFlag |
+                    kOSKextLogLinkFlag,
+                    "Sliding kext %s: No linkedit segment.",
+                    getIdentifierCString());
+                goto finish;
+            }
+
+            if (!haveRelocBase) {
+                OSKextLog(this,
+                    kOSKextLogErrorLevel | kOSKextLogLoadFlag |
+                    kOSKextLogLinkFlag,
+#if __x86_64__
+                    "Sliding kext %s: No writable segments.",
+#else
+                    "Sliding kext %s: No segments.",
+#endif
+                    getIdentifierCString());
+                goto finish;
+            }
+
+            reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
+            reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
+            
+            for (i = 0; i < dysymtab->nlocrel; i++) {
+                if (   reloc[i].r_extern != 0
+                    || reloc[i].r_type != 0
+                    || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
+                    ) {
+                    OSKextLog(this,
+                        kOSKextLogErrorLevel | kOSKextLogLoadFlag |
+                        kOSKextLogLinkFlag,
+                        "Sliding kext %s: Unexpected relocation found.",
+                        getIdentifierCString());
+                    goto finish;
+                }
+                if (reloc[i].r_pcrel != 0) {
+                    continue;
+                }
+                *((uintptr_t *)(relocBase + reloc[i].r_address)) += vm_kernel_slide;
+
+#if KASLR_KEXT_DEBUG
+#define MAX_DYSYMS_TO_LOG 5
+                if ( i < MAX_DYSYMS_TO_LOG ) {
+                    IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n", 
+                          (unsigned long)VM_KERNEL_UNSLIDE(*((uintptr_t *)(relocBase + reloc[i].r_address))), 
+                          (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
+                }
+#endif
+            }
+
+            /* We should free these relocations, not just delete the reference to them.
+             * <rdar://problem/10535549> Free relocations from PIE kexts.
+             *
+             * For now, we do not free LINKEDIT for kexts with split segments.
+             */
+            new_kextsize = round_page(kmod_info->size - reloc_size);
+            if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
+                vm_offset_t     endofkext = kmod_info->address + kmod_info->size;
+                vm_offset_t     new_endofkext = kmod_info->address + new_kextsize;
+                vm_offset_t     endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
+                int             bytes_remaining = endofkext - endofrelocInfo;
+                OSData *        new_osdata = NULL;
+
+                /* fix up symbol offsets if they are after the dsymtab local relocs */
+                if (symtab) {
+                    if (dysymtab->locreloff < symtab->symoff){
+                        symtab->symoff -= reloc_size;
+                    }
+                    if (dysymtab->locreloff < symtab->stroff) {
+                        symtab->stroff -= reloc_size;
+                    }
+                }
+                if (dysymtab->locreloff < dysymtab->extreloff) {
+                    dysymtab->extreloff -= reloc_size;
+                }
+                
+                /* move data behind reloc info down to new offset */
+                if (endofrelocInfo < endofkext) {
+                   memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
+                }
+                               
+                /* Create a new OSData for the smaller kext object and reflect 
+                 * new linkedit segment size.
+                 */
+                linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
+                linkeditSeg->filesize = linkeditSeg->vmsize;
+                
+                new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, new_kextsize);
+                if (new_osdata) {
+                    /* Fix up kmod info and linkedExecutable.
+                     */
+                    kmod_info->size = new_kextsize;
+#if VM_MAPPED_KEXTS
+                    new_osdata->setDeallocFunction(osdata_kext_free);
+#else
+                    new_osdata->setDeallocFunction(osdata_phys_free);
+#endif
+                    linkedExecutable->setDeallocFunction(NULL);
+                    linkedExecutable->release();
+                    linkedExecutable = new_osdata;
+                    
+#if VM_MAPPED_KEXTS
+                    kext_free(new_endofkext, (endofkext - new_endofkext));
+#else
+                    ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
+#endif
+                }
+            }
+            dysymtab->nlocrel = 0;
+            dysymtab->locreloff = 0;
+        }
+    }
+                
+    result = kOSReturnSuccess;
+finish:
+    return result;
+}
+
+/*********************************************************************
+* called only by load()
+*********************************************************************/
+OSReturn
+OSKext::loadExecutable()
+{
+    OSReturn              result             = kOSReturnError;
+    kern_return_t         kxldResult;
+    KXLDDependency     *  kxlddeps           = NULL;  // must kfree
+    uint32_t              num_kxlddeps       = 0;
+    OSArray            *  linkDependencies   = NULL;  // must release
+    uint32_t              numDirectDependencies   = 0;
+    uint32_t              num_kmod_refs      = 0;
+    struct mach_header ** kxldHeaderPtr      = NULL;  // do not free
+    struct mach_header  * kxld_header        = NULL;  // xxx - need to free here?
+    OSData              * theExecutable      = NULL;  // do not release
+    OSString            * versString         = NULL;  // do not release
+    const char          * versCString        = NULL;  // do not free
+    const char          * string             = NULL;  // do not free
+    unsigned int          i;
+
+   /* We need the version string for a variety of bits below.
+    */
+    versString = OSDynamicCast(OSString,
+        getPropertyForHostArch(kCFBundleVersionKey));
+    if (!versString) {
+        goto finish;
+    }
+    versCString = versString->getCStringNoCopy();
+
+    if (isKernelComponent()) {
        if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
+
            if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
                 OSKextLog(this,
                     kOSKextLogErrorLevel |
@@ -4249,6 +5233,16 @@ OSKext::loadExecutable()
         goto register_kmod;
     }
 
+    /* <rdar://problem/21444003> all callers must be entitled */
+    if (FALSE == IOTaskHasEntitlement(current_task(), "com.apple.rootless.kext-management")) {
+        OSKextLog(this,
+                  kOSKextLogErrorLevel | kOSKextLogLoadFlag,
+                  "Not entitled to link kext '%s'",
+                  getIdentifierCString());
+        result = kOSKextReturnNotPrivileged;
+        goto finish;
+    }
+    
     theExecutable = getExecutable();
     if (!theExecutable) {
         if (declaresExecutable()) {
@@ -4263,11 +5257,37 @@ OSKext::loadExecutable()
         goto register_kmod;
     }
 
-    if (isKernelComponent()) {
-        num_kxlddeps = 1; // the kernel itself
-    } else {
-        num_kxlddeps = getNumDependencies();
+    if (isInterface()) {
+        OSData *executableCopy = OSData::withData(theExecutable);
+        setLinkedExecutable(executableCopy);
+        executableCopy->release();
+        goto register_kmod;
     }
+
+    numDirectDependencies = getNumDependencies();
+
+    if (flags.hasBleedthrough) {
+        linkDependencies = dependencies;
+        linkDependencies->retain();
+    } else {
+        linkDependencies = OSArray::withArray(dependencies);
+        if (!linkDependencies) {
+            OSKextLog(this,
+                kOSKextLogErrorLevel |
+                kOSKextLogLoadFlag | kOSKextLogLinkFlag,
+                "Can't allocate link dependencies to load kext %s.",
+                getIdentifierCString());
+            goto finish;
+        }
+
+        for (i = 0; i < numDirectDependencies; ++i) {
+            OSKext * dependencyKext = OSDynamicCast(OSKext,
+                dependencies->getObject(i));
+            dependencyKext->addBleedthroughDependencies(linkDependencies);
+        }
+    } 
+
+    num_kxlddeps = linkDependencies->getCount();
     if (!num_kxlddeps) {
         OSKextLog(this,
             kOSKextLogErrorLevel |
@@ -4276,7 +5296,8 @@ OSKext::loadExecutable()
             getIdentifierCString());
         goto finish;
     }
-    kxlddeps = (u_char **)kalloc(num_kxlddeps * sizeof(*kxlddeps));
+
+    kxlddeps = (KXLDDependency *)kalloc_tag(num_kxlddeps * sizeof(*kxlddeps), VM_KERN_MEMORY_OSKEXT);
     if (!kxlddeps) {
         OSKextLog(this,
             kOSKextLogErrorLevel |
@@ -4285,37 +5306,51 @@ OSKext::loadExecutable()
             getIdentifierCString());
         goto finish;
     }
-    
-    if (isKernelComponent()) {
-        OSData * kernelLinkState = OSKext::getKernelLinkState();
-        kxlddeps[0] = (u_char *)kernelLinkState->getBytesNoCopy();
-    } else for (i = 0; i < num_kxlddeps; i++) {
-        OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
-        if (!dependency->linkState) {
-            // xxx - maybe we should panic here
-            OSKextLog(this,
-                kOSKextLogErrorLevel |
-                kOSKextLogLoadFlag | kOSKextLogLinkFlag,
-                "Can't load kext %s - link state missing.",
-                getIdentifierCString());
-            goto finish;
+    bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
+
+    for (i = 0; i < num_kxlddeps; ++i ) {
+        OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
+
+        if (dependency->isInterface()) {
+            OSKext *interfaceTargetKext = NULL;
+            OSData * interfaceTarget = NULL;
+
+            if (dependency->isKernelComponent()) {
+                interfaceTargetKext = sKernelKext;
+                interfaceTarget = sKernelKext->linkedExecutable;
+            } else {
+                interfaceTargetKext = OSDynamicCast(OSKext, 
+                    dependency->dependencies->getObject(0));
+
+                interfaceTarget = interfaceTargetKext->linkedExecutable;
+            }
+
+            if (!interfaceTarget) {
+                // panic?
+                goto finish;
+            }
+
+           /* The names set here aren't actually logged yet <rdar://problem/7941514>,
+            * it will be useful to have them in the debugger.
+            * strdup() failing isn't critical right here so we don't check that.
+            */
+            kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
+            kxlddeps[i].kext_size = interfaceTarget->getLength();
+            kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
+
+            kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
+            kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
+            kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
+        } else {
+            kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
+            kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
+            kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
         }
-        kxlddeps[i] = (u_char *)dependency->linkState->getBytesNoCopy();
-        assert(kxlddeps[i]);
-    }
 
-   /* We only need link state for a library kext.
-    */
-    if (compatibleVersion > -1 && (declaresExecutable() || isKernelComponent())) {
-        linkStateBytesPtr = &linkStateBytes;
-        linkStateLengthPtr = &linkStateLength;
+        kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
     }
 
-   /* We only need the linked executable for a real kext.
-    */
-    if (!isInterface()) {
-        kxldHeaderPtr = &kxld_header;
-    }
+    kxldHeaderPtr = &kxld_header;
 
 #if DEBUG
     OSKextLog(this,
@@ -4326,13 +5361,11 @@ OSKext::loadExecutable()
         "    executable: %p    executable_length: %d\n"
         "    user_data: %p\n"
         "    kxld_dependencies: %p    num_dependencies: %d\n"
-        "    kxld_header_ptr: %p    kmod_info_ptr: %p\n"
-        "    link_state_ptr: %p    link_state_length_ptr: %p",
-        getIdentifierCString(), kxldContext,
+        "    kxld_header_ptr: %p    kmod_info_ptr: %p\n",
+        getIdentifierCString(), sKxldContext,
         theExecutable->getBytesNoCopy(), theExecutable->getLength(),
         this, kxlddeps, num_kxlddeps,
-        kxldHeaderPtr, kernelKmodInfoPtr,
-        linkStateBytesPtr, linkStateLengthPtr);
+        kxldHeaderPtr, &kmod_info);
 #endif
 
    /* After this call, the linkedExecutable instance variable
@@ -4342,9 +5375,7 @@ OSKext::loadExecutable()
         (u_char *)theExecutable->getBytesNoCopy(),
         theExecutable->getLength(),
         getIdentifierCString(), this, kxlddeps, num_kxlddeps,
-        (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info,
-        linkStateBytesPtr, linkStateLengthPtr,
-        /* symbolFile */ NULL, /* symbolFileSize */ NULL);
+        (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
 
     if (kxldResult != KERN_SUCCESS) {
         // xxx - add kxldResult here?
@@ -4356,31 +5387,22 @@ OSKext::loadExecutable()
         result = kOSKextReturnLinkError;
         goto finish;
     }
-
-   /* If we got a link state, wrap it in an OSData and keep it
-    * around for later use linking other kexts that depend on this kext.
-    */
-    if (linkStateBytes && linkStateLength > 0) {
-        linkState = OSData::withBytesNoCopy(linkStateBytes, linkStateLength);
-        assert(linkState);
-        linkState->setDeallocFunction(&osdata_kmem_free);
-    }
     
-   /* If this isn't an interface, We've written data & instructions into kernel 
-    * memory, so flush the data cache and invalidate the instruction cache.
+   /* We've written data & instructions into kernel memory, so flush the data
+    * cache and invalidate the instruction cache.
+    * I/D caches are coherent on x86
     */
-    if (!isInterface()) {
-        flush_dcache(kmod_info->address, kmod_info->size, false);
-        invalidate_icache(kmod_info->address, kmod_info->size, false);
-    }
-
+#if !defined(__i386__) && !defined(__x86_64__)
+    flush_dcache(kmod_info->address, kmod_info->size, false);
+    invalidate_icache(kmod_info->address, kmod_info->size, false);
+#endif
 register_kmod:
 
     if (isInterface()) {
 
        /* Whip up a fake kmod_info entry for the interface kext.
         */
-        kmod_info = (kmod_info_t *)kalloc(sizeof(kmod_info_t));
+        kmod_info = (kmod_info_t *)kalloc_tag(sizeof(kmod_info_t), VM_KERN_MEMORY_OSKEXT);
         if (!kmod_info) {
             result = KERN_MEMORY_ERROR;
             goto finish;
@@ -4415,8 +5437,8 @@ register_kmod:
     */
     num_kmod_refs = getNumDependencies();
     if (num_kmod_refs) {
-        kmod_info->reference_list = (kmod_reference_t *)kalloc(
-            num_kmod_refs * sizeof(kmod_reference_t));
+        kmod_info->reference_list = (kmod_reference_t *)kalloc_tag(
+            num_kmod_refs * sizeof(kmod_reference_t), VM_KERN_MEMORY_OSKEXT);
         if (!kmod_info->reference_list) {
             result = KERN_MEMORY_ERROR;
             goto finish;
@@ -4442,19 +5464,51 @@ register_kmod:
             "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).", 
             kmod_info->name,
             (unsigned)kmod_info->size / PAGE_SIZE,
-            (unsigned long)kmod_info->address,
+            (unsigned long)VM_KERNEL_UNSLIDE(kmod_info->address),
             (unsigned)kmod_info->id);
     }
 
-    result = setVMProtections();
+    /* if prelinked, VM protections are already set */
+    result = setVMAttributes(!isPrelinked(), true);
     if (result != KERN_SUCCESS) {
         goto finish;
     }
 
+#if KASAN
+    kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
+                    linkedExecutable->getLength(), getIdentifierCString());
+#else
+    if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
+        OSKextLog(this,
+                kOSKextLogErrorLevel | kOSKextLogLoadFlag,
+                "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
+                getIdentifierCString()
+                );
+        result = KERN_FAILURE;
+        goto finish;
+    }
+#endif
+
     result = kOSReturnSuccess;
 
 finish:
-    if (kxlddeps) kfree(kxlddeps, (num_kxlddeps * sizeof(void *)));
+    OSSafeReleaseNULL(linkDependencies);
+
+   /* Clear up locally allocated dependency info.
+    */
+    for (i = 0; i < num_kxlddeps; ++i ) {
+        size_t size;
+
+        if (kxlddeps[i].kext_name) {
+            size = 1 + strlen(kxlddeps[i].kext_name);
+            kfree(kxlddeps[i].kext_name, size);
+        }
+        if (kxlddeps[i].interface_name) {
+            size = 1 + strlen(kxlddeps[i].interface_name);
+            kfree(kxlddeps[i].interface_name, size);
+        }
+    }
+    if (kxlddeps) kfree(kxlddeps, (num_kxlddeps * sizeof(*kxlddeps)));
 
    /* We no longer need the unrelocated executable (which the linker
     * has altered anyhow).
@@ -4486,89 +5540,376 @@ finish:
 }
 
 /*********************************************************************
-* xxx - initWithPrelinkedInfoDict doesn't use this
+* The linkedit segment is used by the kext linker for dependency
+* resolution, and by dtrace for probe initialization. We can free it
+* for non-library kexts, since no kexts depend on non-library kexts
+* by definition, once dtrace has been initialized.
 *********************************************************************/
 void
-OSKext::setLinkedExecutable(OSData * anExecutable)
-{
-    if (linkedExecutable) {
-        panic("Attempt to set linked executable on kext "
-            "that already has one (%s).\n",
-            getIdentifierCString());
-    }
-    linkedExecutable = anExecutable;
-    linkedExecutable->retain();
-    return;
-}
-
-/*********************************************************************
-* called only by loadExecutable()
-*********************************************************************/
-OSReturn
-OSKext::setVMProtections(void)
+OSKext::jettisonLinkeditSegment(void)
 {
-    vm_map_t                    kext_map        = NULL;
-    kernel_segment_command_t  * seg             = NULL;
-    vm_map_offset_t             start           = 0;
-    vm_map_offset_t             end             = 0;
-    OSReturn                    result          = kOSReturnError;
+    kernel_mach_header_t     * machhdr = (kernel_mach_header_t *)kmod_info->address;
+    kernel_segment_command_t * linkedit = NULL;
+    vm_offset_t                start;
+    vm_size_t                  linkeditsize, kextsize;
+    OSData                   * data = NULL;
 
-    if (!kmod_info->address && !kmod_info->size) {
-        result = kOSReturnSuccess;
+#if NO_KEXTD
+    /* We can free symbol tables for all embedded kexts because we don't
+     * support runtime kext linking.
+     */
+    if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
+#else
+    if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
+#endif
         goto finish;
     }
 
-    /* Get the kext's vm map */
-    kext_map = kext_get_vm_map(kmod_info);
-    if (!kext_map) {
-        result = KERN_MEMORY_ERROR;
+   /* Find the linkedit segment.  If it's not the last segment, then freeing
+    * it will fragment the kext into multiple VM regions, which OSKext is not
+    * designed to handle, so we'll have to skip it.
+    */
+    linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
+    if (!linkedit) {
         goto finish;
     }
 
-    /* XXX: On arm, the vme covering the prelinked kernel (really, the whole
-     * range from 0xc0000000 to a little over 0xe0000000) has maxprot set to 0
-     * so the vm_map_protect calls below fail
-     * I believe this happens in the call to vm_map_enter in kmem_init but I 
-     * need to confirm.
-     */
-    /* Protect the headers as read-only; they do not need to be wired */
-    result = vm_map_protect(kext_map, kmod_info->address, 
-        kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE);
-    if (result != KERN_SUCCESS) {
+    if (round_page(kmod_info->address + kmod_info->size) !=
+        round_page(linkedit->vmaddr + linkedit->vmsize))
+    {
         goto finish;
     }
 
-    /* Set the VM protections and wire down each of the segments */
-    seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
-    while (seg) {
-        start = round_page(seg->vmaddr);
-        end = trunc_page(seg->vmaddr + seg->vmsize);
+   /* Create a new OSData for the smaller kext object.
+    */
+    linkeditsize = round_page(linkedit->vmsize);
+    kextsize = kmod_info->size - linkeditsize;
+    start = linkedit->vmaddr;
 
-        result = vm_map_protect(kext_map, start, end, seg->maxprot, TRUE);
-        if (result != KERN_SUCCESS) {
-            OSKextLog(this,
-                kOSKextLogErrorLevel |
-                kOSKextLogLoadFlag,
-                "Kext %s failed to set maximum VM protections "
-                "for segment %s - 0x%x.", 
-                getIdentifierCString(), seg->segname, (int)result);
-            goto finish;
-        }
+    data = OSData::withBytesNoCopy((void *)kmod_info->address, kextsize);
+    if (!data) {
+        goto finish;
+    }
 
-        result = vm_map_protect(kext_map, start, end, seg->initprot, FALSE);
-        if (result != KERN_SUCCESS) {
-            OSKextLog(this,
-                kOSKextLogErrorLevel |
-                kOSKextLogLoadFlag,
-                "Kext %s failed to set initial VM protections "
-                "for segment %s - 0x%x.", 
-                getIdentifierCString(), seg->segname, (int)result);
-            goto finish;
-        }
+   /* Fix the kmod info and linkedExecutable.
+    */
+    kmod_info->size = kextsize;
+        
+#if VM_MAPPED_KEXTS
+    data->setDeallocFunction(osdata_kext_free);
+#else
+    data->setDeallocFunction(osdata_phys_free);
+#endif
+    linkedExecutable->setDeallocFunction(NULL);
+    linkedExecutable->release();
+    linkedExecutable = data;
+    flags.jettisonLinkeditSeg = 1;
+        
+   /* Free the linkedit segment.
+    */
+#if VM_MAPPED_KEXTS
+    kext_free(start, linkeditsize);
+#else
+    ml_static_mfree(start, linkeditsize);
+#endif
 
-        result = vm_map_wire(kext_map, start, end, seg->initprot, FALSE);
-        if (result != KERN_SUCCESS) {
-            goto finish;
+finish:
+    return;
+}
+
+/*********************************************************************
+* If there are whole pages that are unused betweem the last section
+* of the DATA segment and the end of the DATA segment then we can free
+* them
+*********************************************************************/
+void
+OSKext::jettisonDATASegmentPadding(void)
+{
+    kernel_mach_header_t * mh;
+    kernel_segment_command_t * dataSeg;
+    kernel_section_t * sec, * lastSec;
+    vm_offset_t dataSegEnd, lastSecEnd;
+    vm_size_t padSize;
+
+    mh = (kernel_mach_header_t *)kmod_info->address;
+
+    dataSeg = getsegbynamefromheader(mh, SEG_DATA);
+    if (dataSeg == NULL) {
+        return;
+    }
+
+    lastSec = NULL;
+    sec = firstsect(dataSeg);
+    while (sec != NULL) {
+        lastSec = sec;
+        sec = nextsect(dataSeg, sec);
+    } 
+
+    if (lastSec == NULL) {
+        return;
+    }
+
+    if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
+        (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
+        return;
+    }
+
+    dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
+    lastSecEnd = round_page(lastSec->addr + lastSec->size);
+
+    if (dataSegEnd <= lastSecEnd) {
+        return;
+    }
+
+    padSize = dataSegEnd - lastSecEnd;
+
+    if (padSize >= PAGE_SIZE) {
+#if VM_MAPPED_KEXTS
+        kext_free(lastSecEnd, padSize);
+#else
+        ml_static_mfree(lastSecEnd, padSize);
+#endif
+    }
+}
+
+/*********************************************************************
+*********************************************************************/
+void
+OSKext::setLinkedExecutable(OSData * anExecutable)
+{
+    if (linkedExecutable) {
+        panic("Attempt to set linked executable on kext "
+            "that already has one (%s).\n",
+            getIdentifierCString());
+    }
+    linkedExecutable = anExecutable;
+    linkedExecutable->retain();
+    return;
+}
+
+#if CONFIG_DTRACE
+/*********************************************************************
+* Go through all loaded kexts and tell them to register with dtrace.
+* The instance method only registers if necessary.
+*********************************************************************/
+/* static */
+void
+OSKext::registerKextsWithDTrace(void)
+{
+    uint32_t count = sLoadedKexts->getCount();
+    uint32_t i;
+
+    IORecursiveLockLock(sKextLock);
+
+    for (i = 0; i < count; i++) {
+        OSKext   * thisKext     = NULL;  // do not release
+
+        thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
+        if (!thisKext || !thisKext->isExecutable()) {
+            continue;
+        }
+
+        thisKext->registerWithDTrace();
+    }
+
+    IORecursiveLockUnlock(sKextLock);
+
+    return;
+}
+
+extern "C" {
+    extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
+    extern int (*dtrace_modunload)(struct kmod_info *);
+};
+
+/*********************************************************************
+*********************************************************************/
+void
+OSKext::registerWithDTrace(void)
+{
+   /* Register kext with dtrace. A dtrace_modload failure should not
+    * prevent a kext from loading, so we ignore the return code.
+    */
+    if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
+        uint32_t modflag = 0;
+        OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
+        if (forceInit == kOSBooleanTrue) {
+            modflag |= KMOD_DTRACE_FORCE_INIT;
+        }
+
+        (void)(*dtrace_modload)(kmod_info, modflag);
+        flags.dtraceInitialized = true;
+        jettisonLinkeditSegment();
+    }
+    return;
+}
+/*********************************************************************
+*********************************************************************/
+void
+OSKext::unregisterWithDTrace(void)
+{
+   /* Unregister kext with dtrace. A dtrace_modunload failure should not
+    * prevent a kext from loading, so we ignore the return code.
+    */
+    if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
+        (void)(*dtrace_modunload)(kmod_info);
+        flags.dtraceInitialized = false;
+    }
+    return;
+}
+#endif /* CONFIG_DTRACE */
+
+
+/*********************************************************************
+* called only by loadExecutable()
+*********************************************************************/
+#if !VM_MAPPED_KEXTS
+#if defined(__arm__) || defined(__arm64__)
+static inline kern_return_t
+OSKext_protect(
+    vm_map_t   map,
+    vm_map_offset_t    start,
+    vm_map_offset_t    end,
+    vm_prot_t  new_prot,
+    boolean_t  set_max)
+{
+#pragma unused(map)
+    assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
+    assert(start <= end);
+    if (start >= end)
+        return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
+    else if (set_max)
+        return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
+    else
+        return ml_static_protect(start, end - start, new_prot);
+}
+
+static inline kern_return_t
+OSKext_wire(
+    vm_map_t   map,
+    vm_map_offset_t    start,
+    vm_map_offset_t    end,
+    vm_prot_t  access_type,
+    boolean_t       user_wire)
+{
+#pragma unused(map,start,end,access_type,user_wire)
+       return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
+}
+#else
+#error Unrecognized architecture 
+#endif
+#else
+static inline kern_return_t
+OSKext_protect(
+    vm_map_t   map,
+    vm_map_offset_t    start,
+    vm_map_offset_t    end,
+    vm_prot_t  new_prot,
+    boolean_t  set_max)
+{
+    if (start == end) { // 10538581
+        return(KERN_SUCCESS);
+    }
+    return vm_map_protect(map, start, end, new_prot, set_max);
+}
+
+static inline kern_return_t
+OSKext_wire(
+    vm_map_t   map,
+    vm_map_offset_t    start,
+    vm_map_offset_t    end,
+    vm_prot_t  access_type,
+    boolean_t       user_wire)
+{
+       return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
+}
+#endif
+
+OSReturn
+OSKext::setVMAttributes(bool protect, bool wire)
+{
+    vm_map_t                    kext_map        = NULL;
+    kernel_segment_command_t  * seg             = NULL;
+    vm_map_offset_t             start           = 0;
+    vm_map_offset_t             end             = 0;
+    OSReturn                    result          = kOSReturnError;
+
+    if (isInterface() || !declaresExecutable()) {
+        result = kOSReturnSuccess;
+        goto finish;
+    }
+
+    /* Get the kext's vm map */
+    kext_map = kext_get_vm_map(kmod_info);
+    if (!kext_map) {
+        result = KERN_MEMORY_ERROR;
+        goto finish;
+    }
+
+#if !VM_MAPPED_KEXTS
+    if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
+         /* This is a split kext in a prelinked kernelcache; we'll let the
+          * platform code take care of protecting it.  It is already wired.
+          */
+         /* TODO: Should this still allow protections for the first segment
+          * to go through, in the event that we have a mix of split and
+          * unsplit kexts?
+          */
+        result = KERN_SUCCESS;
+        goto finish;
+    }
+#endif
+
+    /* Protect the headers as read-only; they do not need to be wired */
+    result = (protect) ? OSKext_protect(kext_map, kmod_info->address, 
+        kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE)
+            : KERN_SUCCESS;
+    if (result != KERN_SUCCESS) {
+        goto finish;
+    }
+
+    /* Set the VM protections and wire down each of the segments */
+    seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
+    while (seg) {
+
+#if __arm__
+        /* We build all ARM kexts, so we can ensure they are aligned */
+        assert((seg->vmaddr & PAGE_MASK) == 0);
+        assert((seg->vmsize & PAGE_MASK) == 0);
+#endif
+
+        start = round_page(seg->vmaddr);
+        end = trunc_page(seg->vmaddr + seg->vmsize);
+
+        if (protect) {
+            result = OSKext_protect(kext_map, start, end, seg->maxprot, TRUE);
+            if (result != KERN_SUCCESS) {
+                OSKextLog(this,
+                    kOSKextLogErrorLevel |
+                    kOSKextLogLoadFlag,
+                    "Kext %s failed to set maximum VM protections "
+                    "for segment %s - 0x%x.",
+                    getIdentifierCString(), seg->segname, (int)result);
+                goto finish;
+            }
+
+            result = OSKext_protect(kext_map, start, end, seg->initprot, FALSE);
+            if (result != KERN_SUCCESS) {
+                OSKextLog(this,
+                    kOSKextLogErrorLevel |
+                    kOSKextLogLoadFlag,
+                    "Kext %s failed to set initial VM protections "
+                    "for segment %s - 0x%x.",
+                    getIdentifierCString(), seg->segname, (int)result);
+                goto finish;
+            }
+        }
+
+        if (segmentShouldBeWired(seg) && wire) {
+            result = OSKext_wire(kext_map, start, end, seg->initprot, FALSE);
+            if (result != KERN_SUCCESS) {
+                goto finish;
+            }
         }
 
         seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
@@ -4578,6 +5919,14 @@ finish:
     return result;
 }
 
+/*********************************************************************
+*********************************************************************/
+boolean_t 
+OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
+{
+    return (sKeepSymbols || strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)));
+}
+
 /*********************************************************************
 *********************************************************************/
 OSReturn
@@ -4587,6 +5936,7 @@ OSKext::validateKextMapping(bool startFlag)
     const char                          * whichOp = startFlag ? "start" : "stop";
     kern_return_t                         kern_result = 0;
     vm_map_t                              kext_map    = NULL;
+    kernel_segment_command_t            * seg         = NULL;
     mach_vm_address_t                     address     = 0;
     mach_vm_size_t                        size        = 0;
     uint32_t                              depth       = 0;
@@ -4632,22 +5982,52 @@ OSKext::validateKextMapping(bool startFlag)
 
    /* Verify that the start/stop function lies within the kext's address range.
     */
-    if (address < kmod_info->address + kmod_info->hdr_size ||
-        kmod_info->address + kmod_info->size <= address)
-    {
-        OSKextLog(this,
-            kOSKextLogErrorLevel |
-            kOSKextLogLoadFlag,
-            "Kext %s module %s pointer is outside of kext range "
-            "(%s %p - kext at %p-%p)..",
-            getIdentifierCString(),
-            whichOp,
-            whichOp,
-            (void *)address,
-            (void *)kmod_info->address,
-            (void *)(kmod_info->address + kmod_info->size));
-        result = kOSKextReturnBadData;
-        goto finish;
+    if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) { 
+       /* This will likely be how we deal with split kexts; walk the segments to
+        * check that the function lies inside one of the segments of this kext.
+        */
+        for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
+             seg != NULL;
+             seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
+            if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
+                break;
+            }
+        }
+
+        if (!seg) {
+            OSKextLog(this,
+                kOSKextLogErrorLevel |
+                kOSKextLogLoadFlag,
+                "Kext %s module %s pointer is outside of kext range "
+                "(%s %p - kext starts at %p).",
+                getIdentifierCString(),
+                whichOp,
+                whichOp,
+                (void *)VM_KERNEL_UNSLIDE(address),
+                (void *)VM_KERNEL_UNSLIDE(kmod_info->address));
+            result = kOSKextReturnBadData;
+            goto finish;
+        }
+
+        seg = NULL;
+    } else {
+        if (address < kmod_info->address + kmod_info->hdr_size ||
+            kmod_info->address + kmod_info->size <= address)
+        {
+            OSKextLog(this,
+                kOSKextLogErrorLevel |
+                kOSKextLogLoadFlag,
+                "Kext %s module %s pointer is outside of kext range "
+                "(%s %p - kext at %p-%p).",
+                getIdentifierCString(),
+                whichOp,
+                whichOp,
+                (void *)VM_KERNEL_UNSLIDE(address),
+                (void *)VM_KERNEL_UNSLIDE(kmod_info->address),
+                (void *)(VM_KERNEL_UNSLIDE(kmod_info->address) + kmod_info->size));
+            result = kOSKextReturnBadData;
+            goto finish;
+        }
     }
 
    /* Only do these checks before calling the start function;
@@ -4666,11 +6046,12 @@ OSKext::validateKextMapping(bool startFlag)
                 kOSKextLogLoadFlag,
                 "Kext %s - bad %s pointer %p.",
                 getIdentifierCString(),
-                whichOp, (void *)address);
+                whichOp, (void *)VM_KERNEL_UNSLIDE(address)); 
             result = kOSKextReturnBadData;
             goto finish;
         }
 
+#if VM_MAPPED_KEXTS
         if (!(info.protection & VM_PROT_EXECUTE)) {
             OSKextLog(this,
                 kOSKextLogErrorLevel |
@@ -4681,24 +6062,20 @@ OSKext::validateKextMapping(bool startFlag)
             result = kOSKextReturnBadData;
             goto finish;
         }
+#endif
 
-       /* Verify that the kext is backed by physical memory.
+       /* Verify that the kext's segments are backed by physical memory.
         */
-        for (address = kmod_info->address;
-             address < round_page(kmod_info->address + kmod_info->size);
-             address += PAGE_SIZE)
-        {
-            if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
-                OSKextLog(this,
-                    kOSKextLogErrorLevel |
-                    kOSKextLogLoadFlag,
-                    "Kext %s - page %p is not backed by physical memory.",
-                    getIdentifierCString(), 
-                    (void *)address);
+        seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
+        while (seg) {
+            if (!verifySegmentMapping(seg)) {
                 result = kOSKextReturnBadData;
                 goto finish;
             }
+
+            seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
         }
+
     }
 
     result = kOSReturnSuccess;
@@ -4706,6 +6083,62 @@ finish:
     return result;
 }
 
+/*********************************************************************
+*********************************************************************/
+boolean_t
+OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
+{
+    mach_vm_address_t address = 0;
+
+    if (!segmentShouldBeWired(seg)) return true;
+
+    for (address = seg->vmaddr;
+         address < round_page(seg->vmaddr + seg->vmsize);
+         address += PAGE_SIZE)
+    {
+        if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
+            OSKextLog(this,
+                kOSKextLogErrorLevel |
+                kOSKextLogLoadFlag,
+                "Kext %s - page %p is not backed by physical memory.",
+                getIdentifierCString(), 
+                (void *)address);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/*********************************************************************
+*********************************************************************/
+static void
+OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
+{
+
+    uint64_t                            stamp = 0;
+    firehose_tracepoint_id_u            trace_id;
+    struct firehose_trace_uuid_info_s   uuid_info_s;
+    firehose_trace_uuid_info_t          uuid_info = &uuid_info_s;
+    size_t                              uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
+    OSData                              *uuid_data;
+
+    stamp = firehose_tracepoint_time(firehose_activity_flags_default);
+    trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
+
+    uuid_data = aKext->copyUUID();
+    if (uuid_data) {
+        memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
+        OSSafeReleaseNULL(uuid_data);
+    }
+
+    uuid_info->ftui_size    = size;
+    uuid_info->ftui_address = VM_KERNEL_UNSLIDE(address);
+
+    firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
+    return;
+}
+
 /*********************************************************************
 *********************************************************************/
 OSReturn
@@ -4714,10 +6147,7 @@ OSKext::start(bool startDependenciesFlag)
     OSReturn                            result = kOSReturnError;
     kern_return_t                       (* startfunc)(kmod_info_t *, void *);
     unsigned int                        i, count;
-    void                              * kmodStartData      = NULL;  // special handling needed
-#if CONFIG_MACF_KEXT
-    mach_msg_type_number_t              kmodStartDataCount = 0;
-#endif /* CONFIG_MACF_KEXT */
+    void                              * kmodStartData = NULL; 
 
     if (isStarted() || isInterface() || isKernelComponent()) {
         result = kOSReturnSuccess;
@@ -4789,14 +6219,6 @@ OSKext::start(bool startDependenciesFlag)
         }
     }
 
-#if CONFIG_MACF_KEXT
-   /* See if the kext has any MAC framework module data in its plist.
-    * This is passed in as arg #2 of the kext's start routine,
-    * which is otherwise reserved for any other kext.
-    */
-    kmodStartData = MACFCopyModuleDataForKext(this, &kmodStartDataCount);
-#endif /* CONFIG_MACF_KEXT */
-
     OSKextLog(this,
         kOSKextLogDetailLevel |
         kOSKextLogLoadFlag,
@@ -4805,14 +6227,30 @@ OSKext::start(bool startDependenciesFlag)
 
     flags.starting = 1;
 
-#if !__i386__ && !__ppc__
+    // Drop a log message so logd can grab the needed information to decode this kext
+    OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
+
+#if !CONFIG_STATIC_CPPINIT
     result = OSRuntimeInitializeCPP(kmod_info, NULL);
     if (result == KERN_SUCCESS) {
 #endif
 
+#if CONFIG_KEC_FIPS
+        kmodStartData = GetAppleTEXTHashForKext(this, this->infoDict);
+        
+#if 0
+        if (kmodStartData) {
+            OSKextLog(this,
+                      kOSKextLogErrorLevel |
+                      kOSKextLogGeneralFlag,
+                      "Kext %s calling module start function. kmodStartData %p. arch %s",
+                      getIdentifierCString(), kmodStartData, ARCHNAME); 
+        }
+#endif
+#endif // CONFIG_KEC_FIPS 
         result = startfunc(kmod_info, kmodStartData);
 
-#if !__i386__ && !__ppc__
+#if !CONFIG_STATIC_CPPINIT
         if (result != KERN_SUCCESS) {
             (void) OSRuntimeFinalizeCPP(kmod_info, NULL);
         }
@@ -4845,18 +6283,6 @@ OSKext::start(bool startDependenciesFlag)
     }
 
 finish:
-#if CONFIG_MACF_KEXT
-   /* Free the module data for a MAC framework kext. When we start using
-    * param #2 we'll have to distinguish and free/release appropriately.
-    *
-    * xxx - I'm pretty sure the old codepath freed the data and that it's
-    * xxx - up to the kext to copy it.
-    */
-    if (kmodStartData) {
-        kmem_free(kernel_map, (vm_offset_t)kmodStartData, kmodStartDataCount);
-    }
-#endif /* CONFIG_MACF_KEXT */
-
     return result;
 }
 
@@ -4901,7 +6327,7 @@ OSKext::stop(void)
 {
     OSReturn result = kOSReturnError;
     kern_return_t (*stopfunc)(kmod_info_t *, void *);
-    
+
     if (!isStarted() || isInterface()) {
         result = kOSReturnSuccess;
         goto finish;
@@ -4951,10 +6377,6 @@ OSKext::stop(void)
         goto finish;
     }
 
-   /* Save the list of loaded kexts in case we panic.
-    */
-    OSKext::saveUnloadedKextPanicList(this);
-
     stopfunc = kmod_info->stop;
     if (stopfunc) {
         OSKextLog(this,
@@ -4966,7 +6388,7 @@ OSKext::stop(void)
         flags.stopping = 1;
 
         result = stopfunc(kmod_info, /* userData */ NULL);
-#if !__i386__ && !__ppc__
+#if !CONFIG_STATIC_CPPINIT
         if (result == KERN_SUCCESS) {
             result = OSRuntimeFinalizeCPP(kmod_info, NULL);
         }
@@ -4993,6 +6415,8 @@ OSKext::stop(void)
     }
 
 finish:
+    // Drop a log message so logd can update this kext's metadata
+    OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
     return result;
 }
 
@@ -5001,9 +6425,10 @@ finish:
 OSReturn
 OSKext::unload(void)
 {
-    OSReturn     result = kOSReturnError;
-    unsigned int index;
-    uint32_t     num_kmod_refs = 0;
+    OSReturn        result = kOSReturnError;
+    unsigned int    index;
+    uint32_t        num_kmod_refs = 0;
+    OSKextAccount * freeAccount;
 
     if (!sUnloadEnabled) {
         OSKextLog(this,
@@ -5030,11 +6455,20 @@ OSKext::unload(void)
         goto finish;
     }
 
+    if (!isLoaded()) {
+        result = kOSReturnSuccess;
+        goto finish;
+    }
 
-    if (hasOSMetaClassInstances()) {
-        OSKextLog(this,
-            kOSKextLogErrorLevel |
-            kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
+    if (isKernelComponent()) {
+        result = kOSKextReturnInvalidArgument;
+        goto finish;
+    }
+
+    if (metaClasses && !OSMetaClass::removeClasses(metaClasses)) {
+        OSKextLog(this,
+            kOSKextLogErrorLevel |
+            kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
             "Can't unload kext %s; classes have instances:",
             getIdentifierCString());
         reportOSMetaClassInstances(kOSKextLogErrorLevel |
@@ -5042,16 +6476,6 @@ OSKext::unload(void)
         result = kOSKextReturnInUse;
         goto finish;
     }
-
-    if (!isLoaded()) {
-        result = kOSReturnSuccess;
-        goto finish;
-    }
-
-    if (isKernelComponent()) {
-        result = kOSKextReturnInvalidArgument;
-        goto finish;
-    }
     
    /* Note that the kext is unloading before running any code that
     * might be in the kext (request callbacks, module stop function).
@@ -5059,6 +6483,10 @@ OSKext::unload(void)
     * of unloading.
     */
     flags.unloading = 1;
+
+   /* Update the string describing the last kext to unload in case we panic.
+    */
+    savePanicString(/* isLoading */ false);
     
     if (isStarted()) {
         result = stop();
@@ -5079,6 +6507,24 @@ OSKext::unload(void)
         "Kext %s unloading.",
         getIdentifierCString());
 
+    {
+        struct list_head *p;
+        struct list_head *prev;
+        struct list_head *next;
+        for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
+            OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
+            s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
+            prev = p->prev;
+            next = p->next;
+            prev->next = next;
+            next->prev = prev;
+            p->prev = p;
+            p->next = p;
+            IORecursiveLockWakeup(sKextLock, s, false);
+        }
+    }
+
+
    /* Even if we don't call the stop function, we want to be sure we
     * have no OSMetaClass references before unloading the kext executable
     * from memory. OSMetaClasses may have pointers into the kext executable
@@ -5113,7 +6559,7 @@ OSKext::unload(void)
         }
 
         OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
-        if (lastKext && lastKext != sKernelKext) {
+        if (lastKext && !lastKext->isKernel()) {
             kmod = lastKext->kmod_info;
         } else {
             kmod = NULL;  // clear the global kmod variable
@@ -5134,35 +6580,69 @@ OSKext::unload(void)
             num_kmod_refs * sizeof(kmod_reference_t));
     }
 
-   /* If we have a linked executable, release & clear it, and then
-    * unwire & deallocate the buffer the OSData wrapped.
-    */
+#if CONFIG_DTRACE
+    unregisterWithDTrace();
+#endif /* CONFIG_DTRACE */
+
+    notifyKextUnloadObservers(this);
+
+    freeAccount = NULL;
+    IOSimpleLockLock(sKextAccountsLock);
+    account->kext = NULL;
+    if (account->site.tag) account->site.flags |= VM_TAG_UNLOAD;
+    else                   freeAccount = account;
+    IOSimpleLockUnlock(sKextAccountsLock);
+    if (freeAccount) IODelete(freeAccount, OSKextAccount, 1);
+
+    /* Unwire and free the linked executable.
+     */
     if (linkedExecutable) {
-        vm_map_t kext_map;
+#if KASAN
+        kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
+#endif
 
-       /* linkedExecutable is just a wrapper for the executable and doesn't
-        * free it.
-        */
-        linkedExecutable->release();
-        linkedExecutable = NULL;
+#if VM_MAPPED_KEXTS
+        if (!isInterface()) {
+            kernel_segment_command_t *seg = NULL;
+            vm_map_t kext_map = kext_get_vm_map(kmod_info);
 
-        OSKextLog(this,
-            kOSKextLogProgressLevel |
-            kOSKextLogLoadFlag,
-            "Kext %s unwiring and unmapping linked executable.",
-            getIdentifierCString());
+            if (!kext_map) {
+                OSKextLog(this,
+                    kOSKextLogErrorLevel |
+                    kOSKextLogLoadFlag,
+                    "Failed to free kext %s; couldn't find the kext map.",
+                    getIdentifierCString());
+                result = kOSKextReturnInternalError;
+                goto finish;
+            }
+
+            OSKextLog(this,
+                kOSKextLogProgressLevel |
+                kOSKextLogLoadFlag,
+                "Kext %s unwiring and unmapping linked executable.",
+                getIdentifierCString());
+
+            seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
+            while (seg) {
+                if (segmentShouldBeWired(seg)) {
+                    result = vm_map_unwire(kext_map, seg->vmaddr, 
+                        seg->vmaddr + seg->vmsize, FALSE);
+                    if (result != KERN_SUCCESS) {
+                        OSKextLog(this,
+                            kOSKextLogErrorLevel |
+                            kOSKextLogLoadFlag,
+                            "Failed to unwire kext %s.",
+                            getIdentifierCString());
+                        result = kOSKextReturnInternalError;
+                        goto finish;
+                    }
+                }
 
-        kext_map = kext_get_vm_map(kmod_info);
-        if (kext_map) {
-            // xxx - do we have to do this before freeing? Why can't we just free it?
-            // xxx - we should be able to set a dealloc func on the linkedExecutable
-            result = vm_map_unwire(kext_map,
-                kmod_info->address + kmod_info->hdr_size, 
-                kmod_info->address + kmod_info->size, FALSE);
-            if (result == KERN_SUCCESS) {
-                kext_free(kmod_info->address, kmod_info->size);
+                seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
             }
         }
+#endif
+        OSSafeReleaseNULL(linkedExecutable);
     }
 
    /* An interface kext has a fake kmod_info that was allocated,
@@ -5177,17 +6657,86 @@ OSKext::unload(void)
     flags.loaded = false;
     flushDependencies();
 
+    /* save a copy of the bundle ID for us to check when deciding to 
+     * rebuild the kernel cache file.  If a kext was already in the kernel 
+     * cache and unloaded then later loaded we do not need to rebuild the 
+     * kernel cache.  9055303
+     */
+    if (isPrelinked()) {
+        if (!_OSKextInUnloadedPrelinkedKexts(bundleID)) {
+            IORecursiveLockLock(sKextLock);
+            if (sUnloadedPrelinkedKexts) {
+                sUnloadedPrelinkedKexts->setObject(bundleID);
+            }
+            IORecursiveLockUnlock(sKextLock);
+        }
+    }
+
     OSKextLog(this,
         kOSKextLogProgressLevel | kOSKextLogLoadFlag,
         "Kext %s unloaded.", getIdentifierCString());
 
+    queueKextNotification(kKextRequestPredicateUnloadNotification,
+        OSDynamicCast(OSString, bundleID));
+
 finish:
     OSKext::saveLoadedKextPanicList();
+    OSKext::updateLoadedKextSummaries();
 
     flags.unloading = 0;
     return result;
 }
 
+/*********************************************************************
+* Assumes sKextLock is held.
+*********************************************************************/
+/* static */
+OSReturn
+OSKext::queueKextNotification(
+    const char * notificationName,
+    OSString   * kextIdentifier)
+{
+    OSReturn          result               = kOSReturnError;
+    OSDictionary    * loadRequest          = NULL;  // must release
+
+    if (!kextIdentifier) {
+        result = kOSKextReturnInvalidArgument;
+        goto finish;
+    }
+
+   /* Create a new request unless one is already sitting
+    * in sKernelRequests for this bundle identifier
+    */
+    result = _OSKextCreateRequest(notificationName, &loadRequest);
+    if (result != kOSReturnSuccess) {
+        goto finish;
+    }
+    if (!_OSKextSetRequestArgument(loadRequest,
+        kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
+        
+        result = kOSKextReturnNoMemory;
+        goto finish;
+    }
+    if (!sKernelRequests->setObject(loadRequest)) {
+        result = kOSKextReturnNoMemory;
+        goto finish;
+    }
+
+   /* We might want to only queue the notification if kextd is active,
+    * but that wouldn't work for embedded. Note that we don't care if
+    * the ping immediately succeeds here so don't do anything with the
+    * result of this call.
+    */
+    OSKext::pingKextd();
+
+    result = kOSReturnSuccess;
+
+finish:
+    OSSafeReleaseNULL(loadRequest);
+
+    return result;
+}
+
 /*********************************************************************
 *********************************************************************/
 static void
@@ -5195,8 +6744,7 @@ _OSKextConsiderDestroyingLinkContext(
     __unused thread_call_param_t p0,
     __unused thread_call_param_t p1)
 {
-   /* Once both recursive locks are taken in correct order, we shouldn't
-    * have to worry about further recursive lock takes.
+   /* Take multiple locks in the correct order.
     */
     IORecursiveLockLock(sKextLock);
     IORecursiveLockLock(sKextInnerLock);
@@ -5235,9 +6783,8 @@ _OSKextConsiderDestroyingLinkContext(
 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
 * call relationship.
 *
-* Do not call any function that takes sKextLock here! This function
-* can be invoked with sKextInnerLock, and the two must always
-* be taken in the order: sKextLock -> sKextInnerLock.
+* This function must be invoked with sKextInnerLock held.
+* Do not call any function that takes sKextLock here!
 *********************************************************************/
 /* static */
 void
@@ -5271,51 +6818,6 @@ finish:
     return;
 }
 
-/*********************************************************************
-*********************************************************************/
-OSData *
-OSKext::getKernelLinkState()
-{
-    kern_return_t   kxldResult;
-    u_char        * kernel          = NULL;
-    size_t          kernelLength;
-    u_char        * linkStateBytes  = NULL;
-    u_long          linkStateLength;
-    OSData        * linkState       = NULL;
-
-    if (sKernelKext && sKernelKext->linkState) {
-        goto finish;
-    }
-
-    kernel = (u_char *)&_mh_execute_header;
-    kernelLength = getlastaddr() - (vm_offset_t)kernel;
-
-    kxldResult = kxld_link_file(sKxldContext,
-        kernel,
-        kernelLength,
-        kOSKextKernelIdentifier,
-        /* callbackData */ NULL,
-        /* dependencies */ NULL,
-        /* numDependencies */ 0,
-        /* linkedObjectOut */ NULL,
-        /* kmod_info_kern out */ NULL,
-        &linkStateBytes,
-        &linkStateLength,
-        /* symbolFile */ NULL,
-        /* symbolFileSize */ NULL);
-    if (kxldResult) {
-        panic("Can't generate kernel link state; no kexts can be loaded.");
-        goto finish;
-    }
-
-    linkState = OSData::withBytesNoCopy(linkStateBytes, linkStateLength);
-    linkState->setDeallocFunction(&osdata_kmem_free);
-    sKernelKext->linkState = linkState;
-
-finish:
-    return sKernelKext->linkState;
-}
-
 #if PRAGMA_MARK
 #pragma mark Autounload
 #endif
@@ -5323,6 +6825,7 @@ finish:
 * This is a static method because the kext will be deallocated if it
 * does unload!
 *********************************************************************/
+/* static */
 OSReturn
 OSKext::autounloadKext(OSKext * aKext)
 {
@@ -5359,10 +6862,9 @@ OSKext::autounloadKext(OSKext * aKext)
     result = OSKext::removeKext(aKext);
 
 finish:
-
     return result;
 }
-
+    
 /*********************************************************************
 *********************************************************************/
 void
@@ -5373,14 +6875,14 @@ _OSKextConsiderUnloads(
     bool         didUnload = false;
     unsigned int count, i;
 
-   /* Once both recursive locks are taken in correct order, we shouldn't
-    * have to worry about further recursive lock takes.
+   /* Take multiple locks in the correct order
+    * (note also sKextSummaries lock further down).
     */
     IORecursiveLockLock(sKextLock);
     IORecursiveLockLock(sKextInnerLock);
 
     OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
-
+    
    /* If the system is powering down, don't try to unload anything.
     */
     if (sSystemSleep) {
@@ -5388,9 +6890,8 @@ _OSKextConsiderUnloads(
     }
 
     OSKextLog(/* kext */ NULL,
-        kOSKextLogProgressLevel |
-        kOSKextLogLoadFlag,
-        "Checking for unused kexts to autounload.");
+              kOSKextLogProgressLevel | kOSKextLogLoadFlag,
+              "Checking for unused kexts to autounload.");
 
    /*****
     * Remove any request callbacks marked as stale,
@@ -5405,7 +6906,7 @@ _OSKextConsiderUnloads(
             OSBoolean * stale = OSDynamicCast(OSBoolean,
                 callbackRecord->getObject(kKextRequestStaleKey));
             
-            if (stale && stale->isTrue()) {
+            if (stale == kOSBooleanTrue) {
                 OSKext::invokeRequestCallback(callbackRecord,
                     kOSKextReturnTimeout);
             } else {
@@ -5432,8 +6933,8 @@ _OSKextConsiderUnloads(
             i = count - 1;
             do {
                 OSKext * thisKext = OSDynamicCast(OSKext,
-                    sLoadedKexts->getObject(i));
-                didUnload = (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
+                                                  sLoadedKexts->getObject(i));
+                didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
             } while (i--);
         }
     } while (didUnload);
@@ -5443,7 +6944,7 @@ finish:
     sConsiderUnloadsExecuted = true;
 
     (void) OSKext::considerRebuildOfPrelinkedKernel();
-
+    
     IORecursiveLockUnlock(sKextInnerLock);
     IORecursiveLockUnlock(sKextLock);
 
@@ -5463,6 +6964,9 @@ void OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
         sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, 0);
     }
 
+    /* we only reset delay value for unloading if we already have something
+     * pending.  rescheduleOnlyFlag should not start the count down.
+     */
     if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
         goto finish;
     }
@@ -5504,6 +7008,7 @@ finish:
 *********************************************************************/
 extern "C" {
 
+IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
 IOReturn OSKextSystemSleepOrWake(UInt32 messageType)
 {
     IORecursiveLockLock(sKextInnerLock);
@@ -5519,9 +7024,11 @@ IOReturn OSKextSystemSleepOrWake(UInt32 messageType)
             thread_call_cancel(sUnloadCallout);
         }
         sSystemSleep = true;
+        AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
     } else if (messageType == kIOMessageSystemHasPoweredOn) {
         sSystemSleep = false;
-    }
+        clock_get_uptime(&sLastWakeTime);
+   }
     IORecursiveLockUnlock(sKextInnerLock);
 
     return kIOReturnSuccess;
@@ -5542,39 +7049,117 @@ IOReturn OSKextSystemSleepOrWake(UInt32 messageType)
 void
 OSKext::considerRebuildOfPrelinkedKernel(void)
 {
-    OSReturn       checkResult      = kOSReturnError;
-    static bool    requestedPrelink = false;
-    OSDictionary * prelinkRequest   = NULL;  // must release
-
+    static bool     requestedPrelink        = false;
+    OSReturn        checkResult             = kOSReturnError;
+    OSDictionary *  prelinkRequest          = NULL;  // must release
+    OSCollectionIterator * kextIterator     = NULL;  // must release
+    const OSSymbol * thisID                 = NULL;  // do not release
+    bool            doRebuild               = false;
+    AbsoluteTime    my_abstime;
+    UInt64          my_ns;
+    SInt32          delta_secs;
+    
+    /* Only one auto rebuild per boot and only on boot from prelinked kernel */
+    if (requestedPrelink || !sPrelinkBoot) {
+        return;
+    }
+    
+    /* no direct return from this point */
     IORecursiveLockLock(sKextLock);
-
-    if (!sDeferredLoadSucceeded || !sConsiderUnloadsExecuted || 
-        sSafeBoot || requestedPrelink) 
-    {
+    
+    /* We need to wait for kextd to get up and running with unloads already done
+     * and any new startup kexts loaded.   
+     */
+    if (!sConsiderUnloadsExecuted ||
+        !sDeferredLoadSucceeded) {
         goto finish;
     }
-
-    OSKextLog(/* kext */ NULL,
-        kOSKextLogProgressLevel |
-        kOSKextLogArchiveFlag,
-        "Requesting build of prelinked kernel.");
-
+    
+    /* we really only care about boot / system start up related kexts so bail 
+     * if we're here after REBUILD_MAX_TIME.
+     */
+    if (!_OSKextInPrelinkRebuildWindow()) {
+        OSKextLog(/* kext */ NULL,
+                  kOSKextLogArchiveFlag,
+                  "%s prebuild rebuild has expired",
+                  __FUNCTION__);
+        requestedPrelink = true;
+        goto finish;
+    }
+    
+    /* we do not want to trigger a rebuild if we get here too close to waking
+     * up.  (see radar 10233768)
+     */
+    IORecursiveLockLock(sKextInnerLock);
+    
+    clock_get_uptime(&my_abstime);
+    delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
+    if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
+        SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
+        absolutetime_to_nanoseconds(my_abstime, &my_ns);
+        delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
+    }
+    IORecursiveLockUnlock(sKextInnerLock);
+    
+    if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
+        /* too close to time of last wake from sleep */
+        goto finish;
+    }
+    requestedPrelink = true;
+    
+    /* Now it's time to see if we have a reason to rebuild.  We may have done 
+     * some loads and unloads but the kernel cache didn't actually change.
+     * We will rebuild if any kext is not marked prelinked AND is not in our
+     * list of prelinked kexts that got unloaded.  (see radar 9055303)
+     */
+    kextIterator = OSCollectionIterator::withCollection(sKextsByID);
+    if (!kextIterator) {
+        goto finish;
+    }
+    
+    while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
+        OSKext *    thisKext;  // do not release
+        
+        thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
+        if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
+            continue;
+        }
+        
+        if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID)) {
+            continue;
+        }
+        /* kext is loaded and was not in current kernel cache so let's rebuild
+         */
+        doRebuild = true;
+        OSKextLog(/* kext */ NULL,
+                  kOSKextLogArchiveFlag,
+                  "considerRebuildOfPrelinkedKernel %s triggered rebuild",
+                  thisKext->bundleID->getCStringNoCopy());
+        break;
+    }
+    sUnloadedPrelinkedKexts->flushCollection();
+    
+    if (!doRebuild) {
+        goto finish;
+    }
+    
     checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
-        &prelinkRequest);
+                                       &prelinkRequest);
     if (checkResult != kOSReturnSuccess) {
         goto finish;
     }
-
+    
     if (!sKernelRequests->setObject(prelinkRequest)) {
         goto finish;
     }
-
-    OSKextPingKextd();
-    requestedPrelink = true;
-
+    
+    OSKext::pingKextd();
+    
 finish:
     IORecursiveLockUnlock(sKextLock);
-    OSSafeRelease(prelinkRequest);
+    OSSafeReleaseNULL(prelinkRequest);
+    OSSafeReleaseNULL(kextIterator);
+    
     return;
 }
 
@@ -5745,7 +7330,24 @@ OSKext::resolveDependencies(
                 libraryVersion->getCStringNoCopy());
             goto finish;
         }
-        
+
+       /* If a nonprelinked library somehow got into the mix for a
+        * prelinked kext, at any point in the chain, we must fail
+        * because the prelinked relocs for the library will be all wrong.
+        */
+        if (this->isPrelinked() &&
+            libraryKext->declaresExecutable() &&
+            !libraryKext->isPrelinked()) {
+
+            OSKextLog(this,
+                kOSKextLogErrorLevel |
+                kOSKextLogDependenciesFlag,
+                "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
+                getIdentifierCString(), library_id,
+                libraryVersion->getCStringNoCopy());
+            goto finish;
+        }
+
         if (!libraryKext->resolveDependencies(loopStack)) {
             goto finish;
         }
@@ -5815,8 +7417,16 @@ OSKext::resolveDependencies(
         }
     }
     
+    if (hasRawKernelDependency) {
+        OSKextLog(this,
+            kOSKextLogErrorLevel |
+            kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
+            "Error - kext %s declares a dependency on %s, which is not permitted.",
+            getIdentifierCString(), KERNEL_LIB);
+        goto finish;
+    }
 #if __LP64__
-    if (hasRawKernelDependency || hasKernelDependency) {
+    if (hasKernelDependency) {
         OSKextLog(this,
             kOSKextLogErrorLevel |
             kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
@@ -5838,17 +7448,7 @@ OSKext::resolveDependencies(
     // xxx - is it invalid to do both "com.apple.kernel" and any
     // xxx - "com.apple.kernel.*"?
 
-    if (hasRawKernelDependency && hasKernelDependency) {
-        OSKextLog(this,
-            kOSKextLogErrorLevel |
-            kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
-            "Error - kext %s declares dependencies on both "
-            "%s and %s.",
-            getIdentifierCString(), KERNEL_LIB, KERNEL6_LIB);
-        goto finish;
-    }
-    
-    if ((hasRawKernelDependency || hasKernelDependency) && hasKPIDependency) {
+    if (hasKernelDependency && hasKPIDependency) {
         OSKextLog(this,
             kOSKextLogWarningLevel |
             kOSKextLogDependenciesFlag,
@@ -5857,7 +7457,7 @@ OSKext::resolveDependencies(
             getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
     }
 
-    if (!hasRawKernelDependency && !hasKernelDependency && !hasKPIDependency) {
+    if (!hasKernelDependency && !hasKPIDependency) {
         // xxx - do we want to use validation flag for these too?
         OSKextLog(this,
             kOSKextLogWarningLevel |
@@ -5881,9 +7481,11 @@ OSKext::resolveDependencies(
     * its indirect dependencies to simulate old-style linking.  XXX - Should
     * check for duplicates.
     */
-    if (!hasRawKernelDependency && !hasKPIDependency) {
+    if (!hasKPIDependency) {
         unsigned int i;
 
+        flags.hasBleedthrough = true;
+
         count = getNumDependencies();
         
        /* We add to the dependencies array in this loop, but do not iterate
@@ -5956,8 +7558,8 @@ finish:
             getIdentifierCString());
     }
 
-    OSSafeRelease(localLoopStack);
-    OSSafeRelease(libraryIterator);
+    OSSafeReleaseNULL(localLoopStack);
+    OSSafeReleaseNULL(libraryIterator);
 
     return result;
 }
@@ -6107,6 +7709,8 @@ OSKext::addClass(
         }
     }
 
+    notifyAddClassObservers(this, aClass, flags);
+
     result = kOSReturnSuccess;
 
 finish:
@@ -6154,6 +7758,8 @@ OSKext::removeClass(
 
     metaClasses->removeObject(aClass);
     
+    notifyRemoveClassObservers(this, aClass, flags);
+
     result = kOSReturnSuccess;
 
 finish:
@@ -6203,7 +7809,7 @@ OSKext::hasOSMetaClassInstances(void)
 
 finish:
     
-    OSSafeRelease(classIterator);
+    OSSafeReleaseNULL(classIterator);
     return result;
 }
 
@@ -6224,7 +7830,7 @@ OSKext::reportOSMetaClassInstances(
     
     theKext->reportOSMetaClassInstances(msgLogSpec);
 finish:
-    OSSafeRelease(theKext);
+    OSSafeReleaseNULL(theKext);
     return;
 }
 
@@ -6257,7 +7863,7 @@ OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
     }
 
 finish:
-    OSSafeRelease(classIterator);
+    OSSafeReleaseNULL(classIterator);
     return;
 }
 
@@ -6285,12 +7891,11 @@ OSKext::handleRequest(
     char         * response           = NULL;  // returned by reference
     uint32_t       responseLength     = 0;
 
-    OSObject     * parsedXML      = NULL;  // must release
+    OSObject     * parsedXML          = NULL;  // must release
     OSDictionary * requestDict        = NULL;  // do not release
     OSString     * errorString        = NULL;  // must release
 
-    OSData       * responseData       = NULL;  // must release
-    OSObject     * responseObject = NULL;  // must release
+    OSObject     * responseObject     = NULL;  // must release
     
     OSSerialize  * serializer         = NULL;  // must release
 
@@ -6361,14 +7966,20 @@ OSKext::handleRequest(
         kOSKextLogIPCFlag,
         "Received '%s' request from user space.",
         predicate->getCStringNoCopy());
-    
+      
     result = kOSKextReturnNotPrivileged;
     if (hostPriv == HOST_PRIV_NULL) {
-        if (!predicate->isEqualTo(kKextRequestPredicateGetLoaded) &&
-            !predicate->isEqualTo(kKextRequestPredicateGetKernelLinkState) &&
-            !predicate->isEqualTo(kKextRequestPredicateGetKernelLoadAddress)) {
-
-            goto finish;
+        /* must be root to use these kext requests */
+        if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
+            predicate->isEqualTo(kKextRequestPredicateStart) ||
+            predicate->isEqualTo(kKextRequestPredicateStop) ||
+            predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
+            predicate->isEqualTo(kKextRequestPredicateSendResource) ) {
+            OSKextLog(/* kext */ NULL,
+                      kOSKextLogErrorLevel |
+                      kOSKextLogIPCFlag,
+                      "Access Failure - must be root user.");
+           goto finish;
         }
     }
 
@@ -6443,8 +8054,26 @@ OSKext::handleRequest(
     } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
         result = OSKext::dispatchResource(requestDict);
 
-    } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
-        OSBoolean * delayAutounloadBool = NULL;
+    } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
+
+         OSNumber     *lookupNum   = NULL;
+         lookupNum = OSDynamicCast(OSNumber,
+              _OSKextGetRequestArgument(requestDict,
+                  kKextRequestArgumentLookupAddressKey));
+
+         responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
+         if (responseObject) {
+             result = kOSReturnSuccess;
+         } else {
+             goto finish;
+         }
+
+    } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
+               predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
+        OSBoolean    * delayAutounloadBool = NULL;
+        OSObject     * infoKeysRaw         = NULL;
+        OSArray      * infoKeys            = NULL;
+        uint32_t       infoKeysCount       = 0;
         
         delayAutounloadBool = OSDynamicCast(OSBoolean,
             _OSKextGetRequestArgument(requestDict,
@@ -6457,8 +8086,36 @@ OSKext::handleRequest(
             OSKext::considerUnloads(/* rescheduleOnly? */ true);
         }
 
-        responseObject = OSDynamicCast(OSObject,
-            OSKext::copyLoadedKextInfo(kextIdentifiers));
+        infoKeysRaw = _OSKextGetRequestArgument(requestDict,
+                kKextRequestArgumentInfoKeysKey);
+        infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
+        if (infoKeysRaw && !infoKeys) {
+            OSKextLog(/* kext */ NULL,
+                kOSKextLogErrorLevel |
+                kOSKextLogIPCFlag,
+                "Invalid arguments to kext info request.");
+            goto finish;
+        }
+        
+        if (infoKeys) {
+            infoKeysCount = infoKeys->getCount();
+            for (uint32_t i = 0; i < infoKeysCount; i++) {
+                if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
+                    OSKextLog(/* kext */ NULL,
+                        kOSKextLogErrorLevel |
+                        kOSKextLogIPCFlag,
+                        "Invalid arguments to kext info request.");
+                    goto finish;
+                }
+            }
+        }
+
+        if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
+             responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
+        }
+        else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
+             responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
+        }
         if (!responseObject) {
             result = kOSKextReturnInternalError;
         } else {
@@ -6468,45 +8125,12 @@ OSKext::handleRequest(
                 "Returning loaded kext info.");
             result = kOSReturnSuccess;
         }
-
-    } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelLoadAddress)) {
-        OSNumber * addressNum = NULL;  // released as responseObject
-        kernel_segment_command_t * textseg = getsegbyname("__TEXT");
-
-        if (!textseg) {
-            OSKextLog(/* kext */ NULL,
-                kOSKextLogErrorLevel |
-                kOSKextLogGeneralFlag | kOSKextLogIPCFlag,
-                "Can't find text segment for kernel load address.");
-            result = kOSReturnError;
-            goto finish;
-        }
-
-        OSKextLog(/* kext */ NULL,
-            kOSKextLogDebugLevel |
-            kOSKextLogIPCFlag,
-            "Returning kernel load address 0x%llx.",
-            (unsigned long long)textseg->vmaddr);
-        addressNum = OSNumber::withNumber((long long unsigned int)textseg->vmaddr,
-            8 * sizeof(long long unsigned int));
-        responseObject = OSDynamicCast(OSObject, addressNum);
-        result = kOSReturnSuccess;
-
-    } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelLinkState)) {
-        OSKextLog(/* kext */ NULL,
-            kOSKextLogDebugLevel |
-            kOSKextLogIPCFlag,
-            "Returning kernel link state.");
-        responseData = sKernelKext->linkState;
-        responseData->retain();
-        result = kOSReturnSuccess;
-
     } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
 
        /* Hand the current sKernelRequests array to the caller
         * (who must release it), and make a new one.
         */
-        responseObject = OSDynamicCast(OSObject, sKernelRequests);
+        responseObject = sKernelRequests;
         sKernelRequests = OSArray::withCapacity(0);
         sPostedKextLoadIdentifiers->flushCollection();
         OSKextLog(/* kext */ NULL,
@@ -6518,7 +8142,7 @@ OSKext::handleRequest(
     } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
         
         /* Return the set of all requested bundle identifiers */
-        responseObject = OSDynamicCast(OSObject, sAllKextLoadIdentifiers);
+        responseObject = sAllKextLoadIdentifiers;
         responseObject->retain();
         OSKextLog(/* kext */ NULL,
             kOSKextLogDebugLevel |
@@ -6526,6 +8150,14 @@ OSKext::handleRequest(
             "Returning load requests.");
         result = kOSReturnSuccess;
     }
+    else {
+        OSKextLog(/* kext */ NULL,
+                  kOSKextLogDebugLevel |
+                  kOSKextLogIPCFlag,
+                  "Received '%s' invalid request from user space.",
+                  predicate->getCStringNoCopy());
+        goto finish;
+    }
 
    /**********
     * Now we have handle the request, or not. Gather up the response & logging
@@ -6543,19 +8175,7 @@ OSKext::handleRequest(
             "probable memory leak.");
     }
 
-    if (responseData && responseObject) {
-        OSKextLog(/* kext */ NULL,
-            kOSKextLogErrorLevel |
-            kOSKextLogIPCFlag,
-            "Mistakenly generated both data & plist responses to user request "
-            "(returning only data).");
-    } 
-
-    if (responseData && responseData->getLength() && responseOut) {
-
-        response = (char *)responseData->getBytesNoCopy();
-        responseLength = responseData->getLength();
-    } else if (responseOut && responseObject) {
+    if (responseOut && responseObject) {
         serializer = OSSerialize::withCapacity(0);
         if (!serializer) {
             result = kOSKextReturnNoMemory;
@@ -6564,8 +8184,7 @@ OSKext::handleRequest(
 
         if (!responseObject->serialize(serializer)) {
             OSKextLog(/* kext */ NULL,
-                kOSKextLogErrorLevel |
-                kOSKextLogIPCFlag,
+                kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
                 "Failed to serialize response to request from user space.");
             result = kOSKextReturnSerialization;
             goto finish;
@@ -6581,7 +8200,7 @@ OSKext::handleRequest(
        /* This kmem_alloc sets the return value of the function.
         */
         kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
-            responseLength);
+            round_page(responseLength), VM_KERN_MEMORY_OSKEXT);
         if (kmem_result != KERN_SUCCESS) {
             OSKextLog(/* kext */ NULL,
                 kOSKextLogErrorLevel |
@@ -6590,6 +8209,9 @@ OSKext::handleRequest(
             result = kmem_result;
             goto finish;
         } else {
+            /* 11981737 - clear uninitialized data in last page */
+            bzero((void *)(buffer + responseLength),
+                  (round_page(responseLength) - responseLength));
             memcpy(buffer, response, responseLength);
             *responseOut = buffer;
             *responseLengthOut = responseLength;
@@ -6613,23 +8235,316 @@ finish:
 
     IORecursiveLockUnlock(sKextLock);
 
-    OSSafeRelease(requestDict);
-    OSSafeRelease(errorString);
-    OSSafeRelease(responseData);
-    OSSafeRelease(responseObject);
-    OSSafeRelease(serializer);
-    OSSafeRelease(logInfoArray);
+    OSSafeReleaseNULL(parsedXML);
+    OSSafeReleaseNULL(errorString);
+    OSSafeReleaseNULL(responseObject);
+    OSSafeReleaseNULL(serializer);
+    OSSafeReleaseNULL(logInfoArray);
 
     return result;
 }
 
-/*********************************************************************
-*********************************************************************/
-/* static */
-OSArray *
-OSKext::copyLoadedKextInfo(OSArray * kextIdentifiers)
+
+// #include <InstrProfiling.h>
+extern "C" {
+
+    uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
+                                                         const char *DataEnd,
+                                                         const char *CountersBegin,
+                                                         const char *CountersEnd ,
+                                                         const char *NamesBegin,
+                                                         const char *NamesEnd);
+    int __llvm_profile_write_buffer_internal(char *Buffer,
+                                             const char *DataBegin,
+                                             const char *DataEnd,
+                                             const char *CountersBegin,
+                                             const char *CountersEnd ,
+                                             const char *NamesBegin,
+                                             const char *NamesEnd);
+}
+
+
+static
+void OSKextPgoMetadataPut(char *pBuffer,
+                          size_t *position,
+                          size_t bufferSize,
+                          uint32_t *num_pairs,
+                          const char *key,
+                          const char *value)
 {
-    OSArray      * result = NULL;
+    size_t strlen_key = strlen(key);
+    size_t strlen_value = strlen(value);
+    size_t len = strlen(key) + 1 + strlen(value) + 1;
+    char *pos = pBuffer + *position;
+    *position += len;
+    if (pBuffer && bufferSize && *position <= bufferSize) {
+        memcpy(pos, key, strlen_key); pos += strlen_key;
+        *(pos++) = '=';
+        memcpy(pos, value, strlen_value); pos += strlen_value;
+        *(pos++) = 0;
+        if (num_pairs) {
+            (*num_pairs)++;
+        }
+    }
+}
+
+
+static
+void OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
+{
+    *position += strlen(key) + 1 + value_max + 1;
+}
+
+
+static
+void OSKextPgoMetadataPutAll(OSKext *kext,
+                             uuid_t instance_uuid,
+                             char *pBuffer,
+                             size_t *position,
+                             size_t bufferSize,
+                             uint32_t *num_pairs)
+{
+    _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
+    //log_10 2^16 â‰ˆ 4.82
+    const size_t max_secs_string_size = 5 * sizeof(clock_sec_t)/2;
+    const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
+
+    if (!pBuffer) {
+        OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
+        OSKextPgoMetadataPutMax(position, "UUID", 36);
+        OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
+    } else {
+        uuid_string_t instance_uuid_string;
+        uuid_unparse(instance_uuid, instance_uuid_string);
+        OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
+                             "INSTANCE", instance_uuid_string);
+
+        OSData *uuid_data;
+        uuid_t uuid;
+        uuid_string_t uuid_string;
+        uuid_data = kext->copyUUID();
+        if (uuid_data) {
+            memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
+            OSSafeReleaseNULL(uuid_data);
+            uuid_unparse(uuid, uuid_string);
+            OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
+                                 "UUID", uuid_string);
+        }
+
+        clock_sec_t secs;
+        clock_usec_t usecs;
+        clock_get_calendar_microtime(&secs, &usecs);
+        assert(usecs < 1000000);
+        char timestamp[max_timestamp_string_size + 1];
+        _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
+        snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
+        OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
+                             "TIMESTAMP", timestamp);
+    }
+
+    OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
+                         "NAME", kext->getIdentifierCString());
+
+    char versionCString[kOSKextVersionMaxLength];
+    OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
+    OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
+                         "VERSION", versionCString);
+
+}
+
+static
+size_t OSKextPgoMetadataSize(OSKext *kext)
+{
+    size_t position = 0;
+    uuid_t fakeuuid = {};
+    OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
+    return position;
+}
+
+int OSKextGrabPgoDataLocked(OSKext *kext,
+                            bool metadata,
+                            uuid_t instance_uuid,
+                            uint64_t *pSize,
+                            char *pBuffer,
+                            uint64_t bufferSize)
+{
+    int err = 0;
+
+    kernel_section_t *sect_prf_data = NULL;
+    kernel_section_t *sect_prf_name = NULL;
+    kernel_section_t *sect_prf_cnts = NULL;
+    uint64_t size;
+    size_t metadata_size = 0;
+
+    sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
+    sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
+    sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
+
+    if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
+        err = ENOTSUP;
+        goto out;
+    }
+
+    size = __llvm_profile_get_size_for_buffer_internal(
+                         (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
+                         (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
+                         (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
+
+    if (metadata) {
+        metadata_size = OSKextPgoMetadataSize(kext);
+        size += metadata_size;
+        size += sizeof(pgo_metadata_footer);
+    }
+
+
+    if (pSize) {
+        *pSize = size;
+    }
+
+    if (pBuffer && bufferSize) {
+        if (bufferSize < size) {
+            err = ERANGE;
+            goto out;
+        }
+
+        err = __llvm_profile_write_buffer_internal(
+                    pBuffer,
+                    (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
+                    (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
+                    (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
+
+        if (err) {
+            err = EIO;
+            goto out;
+        }
+
+        if (metadata) {
+            char *end_of_buffer = pBuffer + size;
+            struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
+            char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
+
+            size_t metadata_position = 0;
+            uint32_t num_pairs = 0;
+            OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
+            while (metadata_position < metadata_size) {
+                metadata_buffer[metadata_position++] = 0;
+            }
+
+            struct pgo_metadata_footer footer;
+            footer.magic = htonl(0x6d657461);
+            footer.number_of_pairs = htonl( num_pairs );
+            footer.offset_to_pairs = htonl( sizeof(struct pgo_metadata_footer) + metadata_size );
+            memcpy(footerp, &footer, sizeof(footer));
+        }
+
+    }
+
+out:
+    return err;
+}
+
+
+int
+OSKextGrabPgoData(uuid_t uuid,
+                  uint64_t *pSize,
+                  char *pBuffer,
+                  uint64_t bufferSize,
+                  int wait_for_unload,
+                  int metadata)
+{
+    int err = 0;
+    OSKext *kext = NULL;
+
+
+    IORecursiveLockLock(sKextLock);
+
+    kext = OSKext::lookupKextWithUUID(uuid);
+    if (!kext)  {
+        err = ENOENT;
+        goto out;
+    }
+
+    if (wait_for_unload) {
+        OSKextGrabPgoStruct s;
+
+        s.metadata = metadata;
+        s.pSize = pSize;
+        s.pBuffer = pBuffer;
+        s.bufferSize = bufferSize;
+        s.err = EINTR;
+
+        struct list_head *prev = &kext->pendingPgoHead;
+        struct list_head *next = kext->pendingPgoHead.next;
+
+        s.list_head.prev = prev;
+        s.list_head.next = next;
+
+        prev->next = &s.list_head;
+        next->prev = &s.list_head;
+
+        kext->release();
+        kext = NULL;
+
+        IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
+
+        prev = s.list_head.prev;
+        next = s.list_head.next;
+
+        prev->next = next;
+        next->prev = prev;
+
+        err = s.err;
+
+    } else {
+        err = OSKextGrabPgoDataLocked(kext, metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
+    }
+
+ out:
+    if (kext) {
+        kext->release();
+    }
+
+    IORecursiveLockUnlock(sKextLock);
+
+    return err;
+}
+
+void
+OSKextResetPgoCountersLock()
+{
+    IORecursiveLockLock(sKextLock);
+}
+
+void
+OSKextResetPgoCountersUnlock()
+{
+    IORecursiveLockUnlock(sKextLock);
+}
+
+
+extern unsigned int not_in_kdp;
+
+void
+OSKextResetPgoCounters()
+{
+    assert(!not_in_kdp);
+    uint32_t count = sLoadedKexts->getCount();
+    for (uint32_t i = 0; i < count; i++) {
+        OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
+        kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
+        if (!sect_prf_cnts) {
+            continue;
+        }
+        memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
+    }
+}
+
+OSDictionary *
+OSKext::copyLoadedKextInfoByUUID(
+    OSArray * kextIdentifiers,
+    OSArray * infoKeys)
+{
+    OSDictionary * result = NULL;
     OSDictionary * kextInfo = NULL;  // must release
     uint32_t       count, i;
     uint32_t       idCount = 0;
@@ -6637,6 +8552,148 @@ OSKext::copyLoadedKextInfo(OSArray * kextIdentifiers)
 
     IORecursiveLockLock(sKextLock);
 
+#if CONFIG_MACF
+    /* Is the calling process allowed to query kext info? */
+    if (current_task() != kernel_task) {
+        int                 macCheckResult      = 0;
+        kauth_cred_t        cred                = NULL;
+
+        cred = kauth_cred_get_with_ref();
+        macCheckResult = mac_kext_check_query(cred);
+        kauth_cred_unref(&cred);
+
+        if (macCheckResult != 0) {
+            OSKextLog(/* kext */ NULL,
+                      kOSKextLogErrorLevel | kOSKextLogLoadFlag,
+                      "Failed to query kext info (MAC policy error 0x%x).",
+                      macCheckResult);
+            goto finish;
+        }
+   }
+#endif
+
+   /* Empty list of UUIDs is equivalent to no list (get all).
+    */
+    if (kextIdentifiers && !kextIdentifiers->getCount()) {
+        kextIdentifiers = NULL;
+    } else if (kextIdentifiers) {
+        idCount = kextIdentifiers->getCount();
+    }
+
+   /* Same for keys.
+    */
+    if (infoKeys && !infoKeys->getCount()) {
+        infoKeys = NULL;
+    }
+
+    count = sLoadedKexts->getCount();
+    result = OSDictionary::withCapacity(count);
+    if (!result) {
+        goto finish;
+    }
+
+    for (i = 0; i < count; i++) {
+        OSKext       *thisKext     = NULL;  // do not release
+        Boolean       includeThis  = true;
+        uuid_t        thisKextUUID;
+        OSData       *uuid_data;
+        uuid_string_t uuid_key;
+
+        if (kextInfo) {
+            kextInfo->release();
+            kextInfo = NULL;
+        }
+
+        thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
+        if (!thisKext) {
+            continue;
+        }
+
+        uuid_data = thisKext->copyUUID();
+        if (!uuid_data) {
+            continue;
+        }
+
+       memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
+       OSSafeReleaseNULL(uuid_data);
+
+       uuid_unparse(thisKextUUID, uuid_key);
+
+       /* Skip current kext if we have a list of UUIDs and
+        * it isn't in the list.
+        */
+        if (kextIdentifiers) {
+            includeThis = false;
+
+            for (idIndex = 0; idIndex < idCount; idIndex++) {
+                const OSString* wantedUUID = OSDynamicCast(OSString,
+                    kextIdentifiers->getObject(idIndex));
+
+                uuid_t uuid;
+                uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
+
+                if (0 == uuid_compare(uuid, thisKextUUID)) {
+                    includeThis = true;
+                    break;
+                }
+
+            }
+        }
+
+        if (!includeThis) {
+            continue;
+        }
+
+        kextInfo = thisKext->copyInfo(infoKeys);
+        if (kextInfo) {
+            result->setObject(uuid_key, kextInfo);
+        }
+    }
+
+finish:
+    IORecursiveLockUnlock(sKextLock);
+
+    if (kextInfo) kextInfo->release();
+
+    return result;
+}
+
+/*********************************************************************
+*********************************************************************/
+/* static */
+OSDictionary *
+OSKext::copyLoadedKextInfo(
+    OSArray * kextIdentifiers,
+    OSArray * infoKeys) 
+{
+    OSDictionary * result = NULL;
+    OSDictionary * kextInfo = NULL;  // must release
+    uint32_t       count, i;
+    uint32_t       idCount = 0;
+    uint32_t       idIndex = 0;
+
+    IORecursiveLockLock(sKextLock);
+
+#if CONFIG_MACF
+    /* Is the calling process allowed to query kext info? */
+    if (current_task() != kernel_task) {
+        int                 macCheckResult      = 0;
+        kauth_cred_t        cred                = NULL;
+
+        cred = kauth_cred_get_with_ref();
+        macCheckResult = mac_kext_check_query(cred);
+        kauth_cred_unref(&cred);
+
+        if (macCheckResult != 0) {
+            OSKextLog(/* kext */ NULL,
+                      kOSKextLogErrorLevel | kOSKextLogLoadFlag,
+                      "Failed to query kext info (MAC policy error 0x%x).",
+                      macCheckResult);
+            goto finish;
+        }
+   }
+#endif
+
    /* Empty list of bundle ids is equivalent to no list (get all).
     */
     if (kextIdentifiers && !kextIdentifiers->getCount()) {
@@ -6645,11 +8702,56 @@ OSKext::copyLoadedKextInfo(OSArray * kextIdentifiers)
         idCount = kextIdentifiers->getCount();
     }
 
+   /* Same for keys.
+    */
+    if (infoKeys && !infoKeys->getCount()) {
+        infoKeys = NULL;
+    }
+
     count = sLoadedKexts->getCount();
-    result = OSArray::withCapacity(count);
+    result = OSDictionary::withCapacity(count);
     if (!result) {
         goto finish;
     }
+
+#if 0
+    OSKextLog(/* kext */ NULL,
+              kOSKextLogErrorLevel |
+              kOSKextLogGeneralFlag,
+              "kaslr: vm_kernel_slide 0x%lx \n",
+              vm_kernel_slide);
+    OSKextLog(/* kext */ NULL,
+              kOSKextLogErrorLevel |
+              kOSKextLogGeneralFlag,
+              "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
+              vm_kernel_stext, vm_kernel_etext);
+    OSKextLog(/* kext */ NULL,
+              kOSKextLogErrorLevel |
+              kOSKextLogGeneralFlag,
+              "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
+              vm_kernel_base, vm_kernel_top);
+    OSKextLog(/* kext */ NULL,
+              kOSKextLogErrorLevel |
+              kOSKextLogGeneralFlag,
+              "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
+              vm_kext_base, vm_kext_top);
+    OSKextLog(/* kext */ NULL,
+              kOSKextLogErrorLevel |
+              kOSKextLogGeneralFlag,
+              "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
+              vm_prelink_stext, vm_prelink_etext);
+    OSKextLog(/* kext */ NULL,
+              kOSKextLogErrorLevel |
+              kOSKextLogGeneralFlag,
+              "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
+              vm_prelink_sinfo, vm_prelink_einfo);
+    OSKextLog(/* kext */ NULL,
+              kOSKextLogErrorLevel |
+              kOSKextLogGeneralFlag,
+              "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
+              vm_slinkedit, vm_elinkedit);
+#endif
+
     for (i = 0; i < count; i++) {
         OSKext   * thisKext     = NULL;  // do not release
         Boolean    includeThis  = true;
@@ -6685,8 +8787,10 @@ OSKext::copyLoadedKextInfo(OSArray * kextIdentifiers)
             continue;
         }
 
-        kextInfo = thisKext->copyInfo();
-        result->setObject(kextInfo);
+        kextInfo = thisKext->copyInfo(infoKeys);
+        if (kextInfo) {
+            result->setObject(thisKext->getIdentifier(), kextInfo);
+        }
     }
     
 finish:
@@ -6698,38 +8802,34 @@ finish:
 }
 
 /*********************************************************************
-Load Tag
-Bundle ID
-Bundle Version
-Path
-Load Address
-Load Size
-Wired Size
-Version
-Dependency Load Tags
-# Dependent References
-UUID
-RetainCount
+* Any info that needs to do allocations must goto finish on alloc
+* failure. Info that is just a lookup should just not set the object
+* if the info does not exist.
 *********************************************************************/
 #define _OSKextLoadInfoDictCapacity   (12)
 
 OSDictionary *
-OSKext::copyInfo(void)
-{
-    OSDictionary         * result             = NULL;
-    bool                   success            = false;
-    OSNumber             * cpuTypeNumber      = NULL;  // must release
-    OSNumber             * cpuSubtypeNumber   = NULL;  // must release
-    OSString             * versionString      = NULL;  // do not release
-    OSData               * uuid               = NULL;  // must release
-    OSNumber             * scratchNumber      = NULL;  // must release
-    OSArray              * dependencyLoadTags = NULL;  // must release
-    OSCollectionIterator * metaClassIterator  = NULL;  // must release
-    OSArray              * metaClassInfo      = NULL;  // must release
-    OSDictionary         * metaClassDict      = NULL;  // must release
-    OSMetaClass          * thisMetaClass      = NULL;  // do not release
-    OSString             * metaClassName      = NULL;  // must release
-    OSString             * superclassName     = NULL;  // must release
+OSKext::copyInfo(OSArray * infoKeys)
+{
+    OSDictionary         * result                      = NULL;
+    bool                   success                     = false;
+    OSData               * headerData                  = NULL;  // must release
+    OSData               * logData                     = NULL;  // must release
+    OSNumber             * cpuTypeNumber               = NULL;  // must release
+    OSNumber             * cpuSubtypeNumber            = NULL;  // must release
+    OSString             * versionString               = NULL;  // do not release
+    uint32_t               executablePathCStringSize   = 0;
+    char                 * executablePathCString       = NULL;  // must release
+    OSString             * executablePathString        = NULL;  // must release
+    OSData               * uuid                        = NULL;  // must release
+    OSNumber             * scratchNumber               = NULL;  // must release
+    OSArray              * dependencyLoadTags          = NULL;  // must release
+    OSCollectionIterator * metaClassIterator           = NULL;  // must release
+    OSArray              * metaClassInfo               = NULL;  // must release
+    OSDictionary         * metaClassDict               = NULL;  // must release
+    OSMetaClass          * thisMetaClass               = NULL;  // do not release
+    OSString             * metaClassName               = NULL;  // must release
+    OSString             * superclassName              = NULL;  // must release
     uint32_t               count, i;
 
     result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
@@ -6737,240 +8837,497 @@ OSKext::copyInfo(void)
         goto finish;
     }
 
-   /* CPU Type & Subtype.
-    * Use the CPU type of the kernel for all (loaded) kexts.
-    * xxx - should we not include this for the kernel components,
-    * xxx - or for any interface? they have mach-o files, they're just weird.
+    
+   /* Empty keys means no keys, but NULL is quicker to check.
+    */
+    if (infoKeys && !infoKeys->getCount()) {
+        infoKeys = NULL;
+    }
+
+   /* Headers, CPU type, and CPU subtype.
     */
-    if (linkedExecutable || (this == sKernelKext)) {
+    if (!infoKeys ||
+        _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
+        _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
+        _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
+        _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey))
+    {
+
+        if (linkedExecutable && !isInterface()) {
+
+            kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
+                linkedExecutable->getBytesNoCopy();
+
+#if !SECURE_KERNEL
+            // do not return macho header info on shipping iOS - 19095897
+            if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
+                kernel_mach_header_t *  temp_kext_mach_hdr;
+                struct load_command *   lcp;
+
+                headerData = OSData::withBytes(kext_mach_hdr,
+                    (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
+                if (!headerData) {
+                    goto finish;
+                }
+
+                // unslide any vmaddrs we return to userspace - 10726716
+               temp_kext_mach_hdr = (kernel_mach_header_t *)
+                    headerData->getBytesNoCopy();
+                if (temp_kext_mach_hdr == NULL) {
+                    goto finish;
+                }
+
+                lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
+                for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
+                    if (lcp->cmd == LC_SEGMENT_KERNEL) {
+                        kernel_segment_command_t *  segp;
+                        kernel_section_t *          secp;
+                        
+                        segp = (kernel_segment_command_t *) lcp;
+                        // 10543468 - if we jettisoned __LINKEDIT clear size info
+                        if (flags.jettisonLinkeditSeg) {
+                            if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
+                                segp->vmsize = 0;
+                                segp->fileoff = 0;
+                                segp->filesize = 0;
+                            }
+                        }
+
+#if 0
+                        OSKextLog(/* kext */ NULL,
+                                  kOSKextLogErrorLevel |
+                                  kOSKextLogGeneralFlag,
+                                  "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
+                                  __FUNCTION__, segp->segname, segp->vmaddr,
+                                  VM_KERNEL_UNSLIDE(segp->vmaddr),
+                                  segp->vmsize, segp->nsects);
+                        if ( (VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
+                            (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
+                            (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
+                            (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
+                            (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false) ) {
+                            OSKextLog(/* kext */ NULL,
+                                      kOSKextLogErrorLevel |
+                                      kOSKextLogGeneralFlag,
+                                      "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
+                                      __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
+                        }
+#endif
+                        segp->vmaddr = VM_KERNEL_UNSLIDE(segp->vmaddr);
+
+                        for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
+                            secp->addr = VM_KERNEL_UNSLIDE(secp->addr);
+                        }
+                    }
+                    lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
+                }
+                result->setObject(kOSBundleMachOHeadersKey, headerData);
+            }
+#endif // SECURE_KERNEL
+
+            if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
+                 osLogDataHeaderRef *header;
+                 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
+
+                 void *os_log_data          = NULL;
+                 void *cstring_data         = NULL;
+                 unsigned long os_log_size  = 0;
+                 unsigned long cstring_size = 0;
+                 uint32_t os_log_offset     = 0;
+                 uint32_t cstring_offset    = 0;
+                 bool res;
+
+                 os_log_data       = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
+                 os_log_offset     = getsectoffsetfromheader(kext_mach_hdr, "__TEXT", "__os_log");
+                 cstring_data      = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
+                 cstring_offset    = getsectoffsetfromheader(kext_mach_hdr, "__TEXT", "__cstring");
+
+                 header             = (osLogDataHeaderRef *) headerBytes;
+                 header->version    = OS_LOG_HDR_VERSION;
+                 header->sect_count = NUM_OS_LOG_SECTIONS;
+                 header->sections[OS_LOG_SECT_IDX].sect_offset  = os_log_offset;
+                 header->sections[OS_LOG_SECT_IDX].sect_size    = (uint32_t) os_log_size;
+                 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
+                 header->sections[CSTRING_SECT_IDX].sect_size   = (uint32_t) cstring_size;
+
+
+                 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
+                 if (!logData) {
+                      goto finish;
+                 }
+                 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
+                 if (!res) {
+                      goto finish;
+                 }
+                 if (os_log_data) {
+                      res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
+                      if (!res) {
+                           goto finish;
+                      }
+                 }
+                 if (cstring_data) {
+                      res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
+                      if (!res) {
+                           goto finish;
+                      }
+                 }
+                 result->setObject(kOSBundleLogStringsKey, logData);
+            }
 
-        cpuTypeNumber = OSNumber::withNumber(
-            (long long unsigned int)_mh_execute_header.cputype,
-            8 * sizeof(_mh_execute_header.cputype));
-        if (cpuTypeNumber) {
-            result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber);
+            if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
+                cpuTypeNumber = OSNumber::withNumber(
+                    (uint64_t) kext_mach_hdr->cputype,
+                    8 * sizeof(kext_mach_hdr->cputype));
+                if (!cpuTypeNumber) {
+                    goto finish;
+                }
+                result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber);
+            }
+
+            if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
+                cpuSubtypeNumber = OSNumber::withNumber(
+                    (uint64_t) kext_mach_hdr->cpusubtype,
+                    8 * sizeof(kext_mach_hdr->cpusubtype));
+                if (!cpuSubtypeNumber) {
+                    goto finish;
+                }
+                result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber);
+            }
         }
     }
     
-    // I don't want to rely on a mach header for nonkernel kexts, yet
-    if (this == sKernelKext) {
-        cpuSubtypeNumber = OSNumber::withNumber(
-            (long long unsigned int)_mh_execute_header.cputype,
-            8 * sizeof(_mh_execute_header.cputype));
-        if (cpuSubtypeNumber) {
-            result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber);
-        }
-    }
-
-   /* CFBundleIdentifier.
+   /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
     */
     result->setObject(kCFBundleIdentifierKey, bundleID);
 
    /* CFBundleVersion.
     */
-    versionString = OSDynamicCast(OSString,
-        getPropertyForHostArch(kCFBundleVersionKey));
-    if (versionString) {
-        result->setObject(kCFBundleVersionKey, versionString);
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
+        versionString = OSDynamicCast(OSString,
+            getPropertyForHostArch(kCFBundleVersionKey));
+        if (versionString) {
+            result->setObject(kCFBundleVersionKey, versionString);
+        }
     }
 
    /* OSBundleCompatibleVersion.
     */
-    versionString = OSDynamicCast(OSString,
-        getPropertyForHostArch(kOSBundleCompatibleVersionKey));
-    if (versionString) {
-        result->setObject(kOSBundleCompatibleVersionKey, versionString);
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
+        versionString = OSDynamicCast(OSString,
+            getPropertyForHostArch(kOSBundleCompatibleVersionKey));
+        if (versionString) {
+            result->setObject(kOSBundleCompatibleVersionKey, versionString);
+        }
     }
 
    /* Path.
     */
-    if (path) {
-        result->setObject(kOSBundlePathKey, path);
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
+        if (path) {
+            result->setObject(kOSBundlePathKey, path);
+        }
     }
 
-   /* UUID.
+
+   /* OSBundleExecutablePath.
     */
-    uuid = copyUUID();
-    if (uuid) {
-        result->setObject(kOSBundleUUIDKey, uuid);
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
+         if (path && executableRelPath) {
+
+            uint32_t pathLength = path->getLength();  // gets incremented below
+
+            // +1 for slash, +1 for \0
+            executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
+
+            executablePathCString = (char *)kalloc_tag((executablePathCStringSize) *
+                sizeof(char), VM_KERN_MEMORY_OSKEXT); // +1 for \0
+            if (!executablePathCString) {
+                goto finish;
+            }
+            strlcpy(executablePathCString, path->getCStringNoCopy(),
+                executablePathCStringSize);
+            executablePathCString[pathLength++] = '/';
+            executablePathCString[pathLength++] = '\0';
+            strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
+                executablePathCStringSize);
+
+            executablePathString = OSString::withCString(executablePathCString);
+
+            if (!executablePathString) {
+                goto finish;
+            }
+
+            result->setObject(kOSBundleExecutablePathKey, executablePathString);
+        }
+    }
+
+   /* UUID, if the kext has one.
+    */
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
+        uuid = copyUUID();
+        if (uuid) {
+            result->setObject(kOSBundleUUIDKey, uuid);
+        }
     }
     
    /*****
     * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
     */
-    result->setObject(kOSKernelResourceKey,
-        isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
+        result->setObject(kOSKernelResourceKey,
+            isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
+    }
     
-    result->setObject(kOSBundleIsInterfaceKey,
-        isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
+        result->setObject(kOSBundleIsInterfaceKey,
+            isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
+    }
     
-    result->setObject(kOSBundlePrelinkedKey,
-        isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
+        result->setObject(kOSBundlePrelinkedKey,
+            isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
+    }
     
-    result->setObject(kOSBundleStartedKey,
-        isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
+        result->setObject(kOSBundleStartedKey,
+            isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
+    }
 
    /* LoadTag (Index).
     */
-    scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
-        /* numBits */ 8 * sizeof(loadTag));
-    if (scratchNumber) {
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
+        scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
+            /* numBits */ 8 * sizeof(loadTag));
+        if (!scratchNumber) {
+            goto finish;
+        }
         result->setObject(kOSBundleLoadTagKey, scratchNumber);
         OSSafeReleaseNULL(scratchNumber);
     }
     
    /* LoadAddress, LoadSize.
     */
-    if (isInterface() || linkedExecutable) {
-       /* These go to userspace via serialization, so we don't want any doubts
-        * about their size.
-        */
-        uint64_t    loadAddress = 0;
-        uint32_t    loadSize    = 0;
-        uint32_t    wiredSize   = 0;
-
-       /* Interfaces always report 0 load address & size.
-        * Just the way they roll.
-        *
-        * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
-        * xxx - shouldn't have one!
-        */
-        if (linkedExecutable /* && !isInterface() */) {
-            loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
-            loadSize = linkedExecutable->getLength();
-            
-           /* If we have a kmod_info struct, calculated the wired size
-            * from that. Otherwise it's the full load size.
+    if (!infoKeys ||
+        _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
+        _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
+        _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
+        _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
+        _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey))
+    {
+        if (isInterface() || linkedExecutable) {
+           /* These go to userspace via serialization, so we don't want any doubts
+            * about their size.
             */
-            if (kmod_info) {
-                wiredSize = loadSize - kmod_info->hdr_size;
-            } else {
-                wiredSize = loadSize;
+            uint64_t    loadAddress     = 0;
+            uint32_t    loadSize        = 0;
+            uint32_t    wiredSize       = 0;
+            uint64_t    execLoadAddress = 0;
+            uint32_t    execLoadSize    = 0;
+
+           /* Interfaces always report 0 load address & size.
+            * Just the way they roll.
+            *
+            * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
+            * xxx - shouldn't have one!
+            */
+            if (linkedExecutable /* && !isInterface() */) {
+                kernel_mach_header_t     *mh  = NULL;
+                kernel_segment_command_t *seg = NULL;
+
+                loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
+                mh = (kernel_mach_header_t *)loadAddress;
+                loadAddress = VM_KERNEL_UNSLIDE(loadAddress);
+                loadSize = linkedExecutable->getLength();
+
+               /* Walk through the kext, looking for the first executable
+                * segment in case we were asked for its size/address.
+                */
+                for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
+                    if (seg->initprot & VM_PROT_EXECUTE) {
+                        execLoadAddress = VM_KERNEL_UNSLIDE(seg->vmaddr);
+                        execLoadSize = seg->vmsize;
+                        break;
+                    }
+                }
+
+               /* If we have a kmod_info struct, calculated the wired size
+                * from that. Otherwise it's the full load size.
+                */
+                if (kmod_info) {
+                    wiredSize = loadSize - kmod_info->hdr_size;
+                } else {
+                    wiredSize = loadSize;
+                }
             }
-        }
 
-        scratchNumber = OSNumber::withNumber(
-            (unsigned long long)(loadAddress),
-            /* numBits */ 8 * sizeof(loadAddress));
-        if (scratchNumber) {
-            result->setObject(kOSBundleLoadAddressKey, scratchNumber);
-            OSSafeReleaseNULL(scratchNumber);
-        }
-        scratchNumber = OSNumber::withNumber(
-            (unsigned long long)(loadSize),
-            /* numBits */ 8 * sizeof(loadSize));
-        if (scratchNumber) {
-            result->setObject(kOSBundleLoadSizeKey, scratchNumber);
-            OSSafeReleaseNULL(scratchNumber);
-        }
-        scratchNumber = OSNumber::withNumber(
-            (unsigned long long)(wiredSize),
-            /* numBits */ 8 * sizeof(wiredSize));
-        if (scratchNumber) {
-            result->setObject(kOSBundleWiredSizeKey, scratchNumber);
-            OSSafeReleaseNULL(scratchNumber);
+            if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
+                scratchNumber = OSNumber::withNumber(
+                    (unsigned long long)(loadAddress),
+                    /* numBits */ 8 * sizeof(loadAddress));
+                if (!scratchNumber) {
+                    goto finish;
+                }
+                result->setObject(kOSBundleLoadAddressKey, scratchNumber);
+                OSSafeReleaseNULL(scratchNumber);
+            }
+            if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
+                scratchNumber = OSNumber::withNumber(
+                    (unsigned long long)(execLoadAddress),
+                    /* numBits */ 8 * sizeof(execLoadAddress));
+                if (!scratchNumber) {
+                    goto finish;
+                }
+                result->setObject(kOSBundleExecLoadAddressKey, scratchNumber);
+                OSSafeReleaseNULL(scratchNumber);
+            }
+            if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
+                scratchNumber = OSNumber::withNumber(
+                    (unsigned long long)(loadSize),
+                    /* numBits */ 8 * sizeof(loadSize));
+                if (!scratchNumber) {
+                    goto finish;
+                }
+                result->setObject(kOSBundleLoadSizeKey, scratchNumber);
+                OSSafeReleaseNULL(scratchNumber);
+            }
+            if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
+                scratchNumber = OSNumber::withNumber(
+                    (unsigned long long)(execLoadSize),
+                    /* numBits */ 8 * sizeof(execLoadSize));
+                if (!scratchNumber) {
+                    goto finish;
+                }
+                result->setObject(kOSBundleExecLoadSizeKey, scratchNumber);
+                OSSafeReleaseNULL(scratchNumber);
+            }
+            if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
+                scratchNumber = OSNumber::withNumber(
+                    (unsigned long long)(wiredSize),
+                    /* numBits */ 8 * sizeof(wiredSize));
+                if (!scratchNumber) {
+                    goto finish;
+                }
+                result->setObject(kOSBundleWiredSizeKey, scratchNumber);
+                OSSafeReleaseNULL(scratchNumber);
+            }
         }
     }
-    
+
    /* OSBundleDependencies. In descending order for
     * easy compatibility with kextstat(8).
     */
-    if ((count = getNumDependencies())) {
-        dependencyLoadTags = OSArray::withCapacity(count);
-        result->setObject(kOSBundleDependenciesKey, dependencyLoadTags);
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
+        if ((count = getNumDependencies())) {
+            dependencyLoadTags = OSArray::withCapacity(count);
+            result->setObject(kOSBundleDependenciesKey, dependencyLoadTags);
 
-        i = count - 1;
-        do {
-            OSKext * dependency = OSDynamicCast(OSKext,
-                dependencies->getObject(i));
+            i = count - 1;
+            do {
+                OSKext * dependency = OSDynamicCast(OSKext,
+                    dependencies->getObject(i));
 
-            OSSafeReleaseNULL(scratchNumber);
-            
-            if (!dependency) {
-                continue;
-            }
-            scratchNumber = OSNumber::withNumber(
-                (unsigned long long)dependency->getLoadTag(),
-                /* numBits*/ 8 * sizeof(loadTag));
-            if (scratchNumber) {
+                OSSafeReleaseNULL(scratchNumber);
+                
+                if (!dependency) {
+                    continue;
+                }
+                scratchNumber = OSNumber::withNumber(
+                    (unsigned long long)dependency->getLoadTag(),
+                    /* numBits*/ 8 * sizeof(loadTag));
+                if (!scratchNumber) {
+                    goto finish;
+                }
                 dependencyLoadTags->setObject(scratchNumber);
-            }
-        } while (i--);
+            } while (i--);
+        }
     }
 
     OSSafeReleaseNULL(scratchNumber);
 
    /* OSBundleMetaClasses.
     */
-    if (metaClasses && metaClasses->getCount()) {
-        metaClassIterator = OSCollectionIterator::withCollection(metaClasses);
-        metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
-        if (!metaClassIterator || !metaClassInfo) {
-            goto finish;
-        }
-        result->setObject(kOSBundleClassesKey, metaClassInfo);
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
+        if (metaClasses && metaClasses->getCount()) {
+            metaClassIterator = OSCollectionIterator::withCollection(metaClasses);
+            metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
+            if (!metaClassIterator || !metaClassInfo) {
+                goto finish;
+            }
+            result->setObject(kOSBundleClassesKey, metaClassInfo);
 
-        while ( (thisMetaClass = OSDynamicCast(OSMetaClass,
-            metaClassIterator->getNextObject())) ) {
+            while ( (thisMetaClass = OSDynamicCast(OSMetaClass,
+                metaClassIterator->getNextObject())) ) {
 
-            OSSafeReleaseNULL(metaClassDict);
-            OSSafeReleaseNULL(metaClassName);
-            OSSafeReleaseNULL(superclassName);
-            OSSafeReleaseNULL(scratchNumber);
+                OSSafeReleaseNULL(metaClassDict);
+                OSSafeReleaseNULL(scratchNumber);
+                OSSafeReleaseNULL(metaClassName);
+                OSSafeReleaseNULL(superclassName);
 
-            metaClassDict = OSDictionary::withCapacity(3);
-            if (!metaClassDict) {
-                goto finish;
-            }
+                metaClassDict = OSDictionary::withCapacity(3);
+                if (!metaClassDict) {
+                    goto finish;
+                }
 
-            metaClassName = OSString::withCString(thisMetaClass->getClassName());
-            if (thisMetaClass->getSuperClass()) {
-                superclassName = OSString::withCString(
-                    thisMetaClass->getSuperClass()->getClassName());
-            }
-            scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
-                8 * sizeof(unsigned int));
-            if (!metaClassDict || !metaClassName || !superclassName ||
-                !scratchNumber) {
+                metaClassName = OSString::withCString(thisMetaClass->getClassName());
+                if (thisMetaClass->getSuperClass()) {
+                    superclassName = OSString::withCString(
+                        thisMetaClass->getSuperClass()->getClassName());
+                }
+                scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
+                    8 * sizeof(unsigned int));
+                    
+               /* Bail if any of the essentials is missing. The root class lacks a superclass,
+                * of course.
+                */
+                if (!metaClassDict || !metaClassName || !scratchNumber) {
+                    goto finish;
+                }
 
-                goto finish;
+                metaClassInfo->setObject(metaClassDict);
+                metaClassDict->setObject(kOSMetaClassNameKey, metaClassName);
+                if (superclassName) {
+                    metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName);
+                }
+                metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber);
             }
-
-            metaClassInfo->setObject(metaClassDict);
-            metaClassDict->setObject(kOSMetaClassNameKey, metaClassName);
-            metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName);
-            metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber);
         }
     }
     
    /* OSBundleRetainCount.
-    */
-    OSSafeReleaseNULL(scratchNumber);
-    {
-        int extRetainCount = getRetainCount() - 1;
-        if (isLoaded()) {
-            extRetainCount--;
-        }
-        scratchNumber = OSNumber::withNumber(
-            (int)extRetainCount,
-            /* numBits*/ 8 * sizeof(int));
-        if (scratchNumber) {
-            result->setObject(kOSBundleRetainCountKey, scratchNumber);
+    */
+    if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
+        OSSafeReleaseNULL(scratchNumber);
+        {
+            int kextRetainCount = getRetainCount() - 1;
+            if (isLoaded()) {
+                kextRetainCount--;
+            }
+            scratchNumber = OSNumber::withNumber(
+                (int)kextRetainCount,
+                /* numBits*/ 8 * sizeof(int));
+            if (scratchNumber) {
+                result->setObject(kOSBundleRetainCountKey, scratchNumber);
+            }
         }
     }
 
     success = true;
+
 finish:
-    OSSafeRelease(cpuTypeNumber);
-    OSSafeRelease(cpuSubtypeNumber);
-    OSSafeRelease(uuid);
-    OSSafeRelease(scratchNumber);
-    OSSafeRelease(dependencyLoadTags);
-    OSSafeRelease(metaClassIterator);
-    OSSafeRelease(metaClassInfo);
-    OSSafeRelease(metaClassDict);
-    OSSafeRelease(metaClassName);
-    OSSafeRelease(superclassName);
+    OSSafeReleaseNULL(headerData);
+    OSSafeReleaseNULL(logData);
+    OSSafeReleaseNULL(cpuTypeNumber);
+    OSSafeReleaseNULL(cpuSubtypeNumber);
+    OSSafeReleaseNULL(executablePathString);
+    if (executablePathCString) kfree(executablePathCString, executablePathCStringSize);
+    OSSafeReleaseNULL(uuid);
+    OSSafeReleaseNULL(scratchNumber);
+    OSSafeReleaseNULL(dependencyLoadTags);
+    OSSafeReleaseNULL(metaClassIterator);
+    OSSafeReleaseNULL(metaClassInfo);
+    OSSafeReleaseNULL(metaClassDict);
+    OSSafeReleaseNULL(metaClassName);
+    OSSafeReleaseNULL(superclassName);
     if (!success) {
         OSSafeReleaseNULL(result);
     }
@@ -6978,7 +9335,7 @@ finish:
 }
 
 /*********************************************************************
-*********************************************************************/
+ *********************************************************************/
 /* static */
 OSReturn
 OSKext::requestResource(
@@ -7009,6 +9366,17 @@ OSKext::requestResource(
         *requestTagOut = kOSKextRequestTagInvalid;
     }
 
+    /* If requests to user space are disabled, don't go any further */
+    if (!sKernelRequestsEnabled) {
+        OSKextLog(/* kext */ NULL, 
+            kOSKextLogErrorLevel | kOSKextLogIPCFlag,
+            "Can't request resource %s for %s - requests to user space are disabled.",
+            resourceNameCString,
+            kextIdentifierCString);
+        result = kOSKextReturnDisabled;
+        goto finish;
+    }
+
     if (!kextIdentifierCString || !resourceNameCString || !callback) {
         result = kOSKextReturnInvalidArgument;
         goto finish;
@@ -7109,7 +9477,7 @@ OSKext::requestResource(
         goto finish;
     }
 
-    OSKextPingKextd();
+    OSKext::pingKextd();
 
     result = kOSReturnSuccess;
     if (requestTagOut) {
@@ -7153,6 +9521,7 @@ finish:
 }
 
 /*********************************************************************
+* Assumes sKextLock is held.
 *********************************************************************/
 /* static */
 OSReturn
@@ -7173,12 +9542,13 @@ OSKext::dequeueCallbackForRequestTag(
         callbackRecordOut);
 
 finish:
-    OSSafeRelease(requestTagNum);
+    OSSafeReleaseNULL(requestTagNum);
 
     return result;
 }
 
 /*********************************************************************
+* Assumes sKextLock is held.
 *********************************************************************/
 /* static */
 OSReturn
@@ -7191,8 +9561,6 @@ OSKext::dequeueCallbackForRequestTag(
     OSNumber      * callbackTagNum  = NULL;  // do not release
     unsigned int    count, i;
 
-    IORecursiveLockLock(sKextLock);
-
     result = kOSReturnError;
     count = sRequestCallbackRecords->getCount();
     for (i = 0; i < count; i++) {
@@ -7227,11 +9595,22 @@ OSKext::dequeueCallbackForRequestTag(
     result = kOSKextReturnNotFound;
 
 finish:
-    IORecursiveLockUnlock(sKextLock);
     return result;
 }
 
+
+/*********************************************************************
+* Busy timeout triage
+*********************************************************************/
+/* static */
+bool
+OSKext::isWaitingKextd(void)
+{
+    return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
+}
+
 /*********************************************************************
+* Assumes sKextLock is held.
 *********************************************************************/
 /* static */
 OSReturn
@@ -7250,8 +9629,6 @@ OSKext::dispatchResource(OSDictionary * requestDict)
     void                          * context         = NULL;  // do not free
     OSKext                        * callbackKext    = NULL;  // must release (looked up)
 
-    IORecursiveLockLock(sKextLock);
-
    /* Get the args from the request. Right now we need the tag
     * to look up the callback record, and the result for invoking the callback.
     */
@@ -7305,17 +9682,13 @@ OSKext::dispatchResource(OSDictionary * requestDict)
     if (!callbackKext) {
         OSKextLog(/* kext */ NULL,
             kOSKextLogErrorLevel | kOSKextLogIPCFlag,
-            "Can't invoke callback for resource request; "
-            "no kext loaded at callback address %p.",
-            callback);
+            "Can't invoke callback for resource request; ");
         goto finish;
     }
     if (!callbackKext->flags.starting && !callbackKext->flags.started) {
         OSKextLog(/* kext */ NULL,
             kOSKextLogErrorLevel | kOSKextLogIPCFlag,
-            "Can't invoke kext resource callback; "
-            "kext at callback address %p is not running.",
-            callback);
+            "Can't invoke kext resource callback; ");
         goto finish;
     }
 
@@ -7329,7 +9702,6 @@ finish:
     if (callbackKext)   callbackKext->release();
     if (callbackRecord) callbackRecord->release();
 
-    IORecursiveLockUnlock(sKextLock);
     return result;
 }
 
@@ -7372,6 +9744,7 @@ finish:
 }
 
 /*********************************************************************
+* Assumes sKextLock is held.
 *********************************************************************/
 /* static */
 OSReturn
@@ -7383,9 +9756,11 @@ OSKext::cancelRequest(
     OSDictionary * callbackRecord = NULL;  // must release
     OSData       * contextWrapper = NULL;  // do not release
 
+    IORecursiveLockLock(sKextLock);
     result = OSKext::dequeueCallbackForRequestTag(requestTag,
         &callbackRecord);
-        
+    IORecursiveLockUnlock(sKextLock);
+
     if (result == kOSReturnSuccess && contextOut) {
         contextWrapper = OSDynamicCast(OSData,
             _OSKextGetRequestArgument(callbackRecord,
@@ -7399,6 +9774,7 @@ OSKext::cancelRequest(
 }
 
 /*********************************************************************
+* Assumes sKextLock is held.
 *********************************************************************/
 void
 OSKext::invokeOrCancelRequestCallbacks(
@@ -7407,8 +9783,6 @@ OSKext::invokeOrCancelRequestCallbacks(
 {
     unsigned int count, i;
     
-    IORecursiveLockLock(sKextLock);
-
     count = sRequestCallbackRecords->getCount();
     if (!count) {
         goto finish;
@@ -7448,11 +9822,11 @@ OSKext::invokeOrCancelRequestCallbacks(
     } while (i--);
 
 finish:
-    IORecursiveLockUnlock(sKextLock);
     return;
 }
 
 /*********************************************************************
+* Assumes sKextLock is held.
 *********************************************************************/
 uint32_t
 OSKext::countRequestCallbacks(void)
@@ -7460,8 +9834,6 @@ OSKext::countRequestCallbacks(void)
     uint32_t     result = 0;
     unsigned int count, i;
     
-    IORecursiveLockLock(sKextLock);
-
     count = sRequestCallbackRecords->getCount();
     if (!count) {
         goto finish;
@@ -7494,7 +9866,6 @@ OSKext::countRequestCallbacks(void)
     } while (i--);
 
 finish:
-    IORecursiveLockUnlock(sKextLock);
     return result;
 }
 
@@ -7506,7 +9877,6 @@ static OSReturn _OSKextCreateRequest(
 {
     OSReturn result = kOSKextReturnNoMemory;
     OSDictionary * request = NULL;  // must release on error
-    OSDictionary * args = NULL;     // must release
     
     request = OSDictionary::withCapacity(2);
     if (!request) {
@@ -7525,7 +9895,6 @@ finish:
     } else {
         *requestP = request;
     }
-    if (args) args->release();
 
     return result;
 }
@@ -7619,6 +9988,96 @@ finish:
     return result;
 }
 
+/*********************************************************************
+*********************************************************************/
+static bool _OSArrayContainsCString(
+    OSArray    * array,
+    const char * cString)
+{
+    bool             result = false;
+    const OSSymbol * symbol = NULL;
+    uint32_t         count, i;
+    
+    if (!array || !cString) {
+        goto finish;
+    }
+
+    symbol = OSSymbol::withCStringNoCopy(cString);
+    if (!symbol) {
+        goto finish;
+    }
+
+    count = array->getCount();
+    for (i = 0; i < count; i++) {
+        OSObject * thisObject = array->getObject(i);
+        if (symbol->isEqualTo(thisObject)) {
+            result = true;
+            goto finish;
+        }
+    }
+
+finish:
+    if (symbol) symbol->release();
+    return result;
+}
+
+/*********************************************************************
+ * We really only care about boot / system start up related kexts. 
+ * We return true if we're less than REBUILD_MAX_TIME since start up,
+ * otherwise return false.
+ *********************************************************************/
+bool _OSKextInPrelinkRebuildWindow(void)
+{
+    static bool     outside_the_window = false;
+    AbsoluteTime    my_abstime;
+    UInt64          my_ns;
+    SInt32          my_secs;
+    
+    if (outside_the_window) {
+        return(false);
+    }
+    clock_get_uptime(&my_abstime);
+    absolutetime_to_nanoseconds(my_abstime, &my_ns);
+    my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
+    if (my_secs > REBUILD_MAX_TIME) {
+        outside_the_window = true;
+        return(false);
+    }
+    return(true);
+}
+
+/*********************************************************************
+ *********************************************************************/
+bool _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
+{
+    int unLoadedCount, i;
+    bool result = false;
+    
+    IORecursiveLockLock(sKextLock);
+    
+    if (sUnloadedPrelinkedKexts == NULL) {
+        goto finish;
+    }
+    unLoadedCount = sUnloadedPrelinkedKexts->getCount();
+    if (unLoadedCount == 0) {
+        goto finish;
+    }
+    
+    for (i = 0; i < unLoadedCount; i++) {
+        const OSSymbol *    myBundleID;     // do not release
+        
+        myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
+        if (!myBundleID) continue;
+        if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
+            result = true;
+            break;
+        }
+    }
+finish:
+    IORecursiveLockUnlock(sKextLock);
+    return(result);
+}
+
 #if PRAGMA_MARK
 #pragma mark Personalities (IOKit Drivers)
 #endif
@@ -7906,29 +10365,21 @@ OSKext::removePersonalitiesFromCatalog(void)
 /* static */
 OSKextLogSpec
 OSKext::setUserSpaceLogFilter(
-    OSKextLogSpec   userLogFilter,
+    OSKextLogSpec   newUserLogFilter,
     bool            captureFlag)
 {
     OSKextLogSpec result;
+    bool          allocError = false;
 
-    IORecursiveLockLock(sKextInnerLock);
+   /* Do not call any function that takes sKextLoggingLock during
+    * this critical block. That means do logging after.
+    */
+    IOLockLock(sKextLoggingLock);
 
     result = sUserSpaceKextLogFilter;
-    sUserSpaceKextLogFilter = userLogFilter;
-
-   /* If the config flag itself is changing, log the state change
-    * going both ways, before setting up the user-space log arrays,
-    * so that this is only logged in the kernel.
-    */
-    if (sUserSpaceKextLogFilter != result) {
-        OSKextLog(/* kext */ NULL,
-            kOSKextLogDebugLevel |
-            kOSKextLogGeneralFlag,
-            "User-space log flags changed from 0x%x to 0x%x.",
-            result, sUserSpaceKextLogFilter);
-    }
+    sUserSpaceKextLogFilter = newUserLogFilter;
 
-    if (userLogFilter && captureFlag &&
+    if (newUserLogFilter && captureFlag &&
         !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
 
         // xxx - do some measurements for a good initial capacity?
@@ -7936,16 +10387,31 @@ OSKext::setUserSpaceLogFilter(
         sUserSpaceLogMessageArray = OSArray::withCapacity(0);
         
         if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
-            OSKextLog(/* kext */ NULL,
-                kOSKextLogErrorLevel |
-                kOSKextLogGeneralFlag,
-                "Failed to allocate user-space log message arrays.");
             OSSafeReleaseNULL(sUserSpaceLogSpecArray);
             OSSafeReleaseNULL(sUserSpaceLogMessageArray);
+            allocError = true;
         }
     }
 
-    IORecursiveLockUnlock(sKextInnerLock);
+    IOLockUnlock(sKextLoggingLock);
+
+   /* If the config flag itself is changing, log the state change
+    * going both ways, before setting up the user-space log arrays,
+    * so that this is only logged in the kernel.
+    */
+    if (result != newUserLogFilter) {
+        OSKextLog(/* kext */ NULL,
+            kOSKextLogDebugLevel |
+            kOSKextLogGeneralFlag,
+            "User-space log flags changed from 0x%x to 0x%x.",
+            result, newUserLogFilter);
+    }
+    if (allocError) {
+        OSKextLog(/* kext */ NULL,
+            kOSKextLogErrorLevel |
+            kOSKextLogGeneralFlag,
+            "Failed to allocate user-space log message arrays.");
+    }
 
     return result;
 }
@@ -7957,10 +10423,14 @@ OSKext::setUserSpaceLogFilter(
 OSArray *
 OSKext::clearUserSpaceLogFilter(void)
 {
-    OSArray        * result        = NULL;
+    OSArray       * result       = NULL;
     OSKextLogSpec   oldLogFilter;
+    OSKextLogSpec   newLogFilter = kOSKextLogSilentFilter;
 
-    IORecursiveLockLock(sKextInnerLock);
+   /* Do not call any function that takes sKextLoggingLock during
+    * this critical block. That means do logging after.
+    */
+    IOLockLock(sKextLoggingLock);
 
     result = OSArray::withCapacity(2);
     if (result) {
@@ -7971,25 +10441,26 @@ OSKext::clearUserSpaceLogFilter(void)
     OSSafeReleaseNULL(sUserSpaceLogMessageArray);
 
     oldLogFilter = sUserSpaceKextLogFilter;
-    sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
+    sUserSpaceKextLogFilter = newLogFilter;
+
+    IOLockUnlock(sKextLoggingLock);
 
    /* If the config flag itself is changing, log the state change
     * going both ways, after tearing down the user-space log
     * arrays, so this is only logged within the kernel.
     */
-    if (oldLogFilter != sUserSpaceKextLogFilter) {
+    if (oldLogFilter != newLogFilter) {
         OSKextLog(/* kext */ NULL,
             kOSKextLogDebugLevel |
             kOSKextLogGeneralFlag,
             "User-space log flags changed from 0x%x to 0x%x.",
-            oldLogFilter, sUserSpaceKextLogFilter);
+            oldLogFilter, newLogFilter);
     }
 
-    IORecursiveLockUnlock(sKextInnerLock);
-
     return result;
 }
 
+
 /*********************************************************************
 * Do not call any function that takes sKextLock here!
 *********************************************************************/
@@ -7999,9 +10470,9 @@ OSKext::getUserSpaceLogFilter(void)
 {
     OSKextLogSpec result;
 
-    IORecursiveLockLock(sKextInnerLock);
+    IOLockLock(sKextLoggingLock);
     result = sUserSpaceKextLogFilter;
-    IORecursiveLockUnlock(sKextInnerLock);
+    IOLockUnlock(sKextLoggingLock);
 
     return result;
 }
@@ -8032,30 +10503,21 @@ inline const char * colorForFlags(OSKextLogSpec flags)
     switch (logLevel) {
     case kOSKextLogErrorLevel:
         return VTRED VTBOLD;
-        break;
     case kOSKextLogWarningLevel:
         return VTRED;
-        break;
     case kOSKextLogBasicLevel:
         return VTYELLOW VTUNDER;
-        break;
     case kOSKextLogProgressLevel:
         return VTYELLOW;
-        break;
     case kOSKextLogStepLevel:
         return VTGREEN;
-        break;
     case kOSKextLogDetailLevel:
         return VTCYAN;
-        break;
     case kOSKextLogDebugLevel:
         return VTMAGENTA;
-        break;
     default:
         return "";  // white
-        break;
     }
-    return "";
 }
 
 inline bool logSpecMatch(
@@ -8120,7 +10582,7 @@ OSKextVLog(
     OSKext         * aKext,
     OSKextLogSpec    msgLogSpec,
     const char     * format,
-    va_list    srcArgList)
+    va_list          srcArgList)
 {
     extern int       disableConsoleOutput;
 
@@ -8134,7 +10596,7 @@ OSKextVLog(
     OSString       * logString         = NULL;         // must release
     char           * buffer            = stackBuffer;  // do not free
 
-    IORecursiveLockLock(sKextInnerLock);
+    IOLockLock(sKextLoggingLock);
 
    /* Set the kext/global bit in the message spec if we have no
     * kext or if the kext requests logging.
@@ -8159,7 +10621,7 @@ OSKextVLog(
     va_end(argList);
 
     if (length + 1 >= sizeof(stackBuffer)) {
-        allocBuffer = (char *)kalloc((length + 1) * sizeof(char));
+        allocBuffer = (char *)kalloc_tag((length + 1) * sizeof(char), VM_KERN_MEMORY_OSKEXT);
         if (!allocBuffer) {
             goto finish;
         }
@@ -8203,21 +10665,212 @@ OSKextVLog(
     }
 
 finish:
+    IOLockUnlock(sKextLoggingLock);
+
     if (allocBuffer) {
         kfree(allocBuffer, (length + 1) * sizeof(char));
     }
-    OSSafeRelease(logString);
-    OSSafeRelease(logSpecNum);
-    IORecursiveLockUnlock(sKextInnerLock);
+    OSSafeReleaseNULL(logString);
+    OSSafeReleaseNULL(logSpecNum);
     return;
 }
 
+#if KASLR_IOREG_DEBUG
+    
+#define IOLOG_INDENT( the_indention ) \
+{ \
+    int     i; \
+    for ( i = 0; i < (the_indention); i++ ) { \
+        IOLog(" "); \
+    } \
+}
+    
+extern vm_offset_t      vm_kernel_stext;
+extern vm_offset_t      vm_kernel_etext;
+extern mach_vm_offset_t kext_alloc_base; 
+extern mach_vm_offset_t kext_alloc_max;
+    
+bool ScanForAddrInObject(OSObject * theObject, 
+                         int indent );
+
+bool ScanForAddrInObject(OSObject * theObject, 
+                         int indent)
+{
+    const OSMetaClass *     myTypeID;
+    OSCollectionIterator *  myIter;
+    OSSymbol *              myKey;
+    OSObject *              myValue;
+    bool                    myResult = false;
+    
+    if ( theObject == NULL ) {
+        IOLog("%s: theObject is NULL \n", 
+              __FUNCTION__);
+        return myResult;
+    }
+    
+    myTypeID = OSTypeIDInst(theObject);
+    
+    if ( myTypeID == OSTypeID(OSDictionary) ) {
+        OSDictionary *      myDictionary;
+        
+        myDictionary = OSDynamicCast(OSDictionary, theObject);
+        myIter = OSCollectionIterator::withCollection( myDictionary );
+        if ( myIter == NULL ) 
+            return myResult;
+        myIter->reset();
+        
+        while ( (myKey = OSDynamicCast(OSSymbol, myIter->getNextObject())) ) {
+            bool    myTempResult;
+            
+            myValue = myDictionary->getObject(myKey);
+            myTempResult = ScanForAddrInObject(myValue, (indent + 4));
+            if (myTempResult) {
+                // if we ever get a true result return true
+                myResult = true;
+                IOLOG_INDENT(indent);
+                IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
+            }
+        }
+        myIter->release();
+    }
+    else if ( myTypeID == OSTypeID(OSArray) ) {
+        OSArray *   myArray;
+        
+        myArray = OSDynamicCast(OSArray, theObject);
+        myIter = OSCollectionIterator::withCollection(myArray);
+        if ( myIter == NULL ) 
+            return myResult;
+        myIter->reset();
+        
+        while ( (myValue = myIter->getNextObject()) ) {
+            bool        myTempResult;
+            myTempResult = ScanForAddrInObject(myValue, (indent + 4));
+            if (myTempResult) {
+                // if we ever get a true result return true
+                myResult = true;
+                IOLOG_INDENT(indent);
+                IOLog("OSArray: \n");
+            }
+        }
+        myIter->release();
+    }
+    else if ( myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol) ) {
+        
+        // should we look for addresses in strings?
+    }
+    else if ( myTypeID == OSTypeID(OSData) ) {
+        
+        void * *        myPtrPtr;
+        unsigned int    myLen;
+        OSData *        myDataObj;
+        
+        myDataObj =    OSDynamicCast(OSData, theObject);
+        myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
+        myLen = myDataObj->getLength();
+        
+        if (myPtrPtr && myLen && myLen > 7) {
+            int     i;
+            int     myPtrCount = (myLen / sizeof(void *));
+            
+            for (i = 0; i < myPtrCount; i++) {
+                UInt64 numberValue = (UInt64) *(myPtrPtr);
+                
+                if ( kext_alloc_max != 0 &&
+                    numberValue >= kext_alloc_base && 
+                    numberValue < kext_alloc_max ) {
+                    
+                    OSKext * myKext    = NULL;  // must release (looked up)
+                                                // IOLog("found OSData %p in kext map %p to %p  \n",
+                                                //       *(myPtrPtr),
+                                                //       (void *) kext_alloc_base,
+                                                //       (void *) kext_alloc_max);
+                    
+                    myKext = OSKext::lookupKextWithAddress( (vm_address_t) *(myPtrPtr) );
+                    if (myKext) {
+                        IOLog("found addr %p from an OSData obj within kext \"%s\"  \n",
+                              *(myPtrPtr),
+                              myKext->getIdentifierCString());
+                        myKext->release();
+                    }
+                    myResult = true;
+                }
+                if ( vm_kernel_etext != 0 &&
+                    numberValue >= vm_kernel_stext && 
+                    numberValue < vm_kernel_etext ) {
+                    IOLog("found addr %p from an OSData obj within kernel text segment %p to %p  \n",
+                          *(myPtrPtr),
+                          (void *) vm_kernel_stext,
+                          (void *) vm_kernel_etext);
+                    myResult = true;
+                }
+                myPtrPtr++;
+            }
+        }
+    }
+    else if ( myTypeID == OSTypeID(OSBoolean) ) {
+        
+        // do nothing here...
+    }
+    else if ( myTypeID == OSTypeID(OSNumber) ) {
+        
+        OSNumber * number = OSDynamicCast(OSNumber, theObject);
+        
+        UInt64 numberValue = number->unsigned64BitValue();
+        
+        if ( kext_alloc_max != 0 &&
+            numberValue >= kext_alloc_base && 
+            numberValue < kext_alloc_max ) {
+            
+            OSKext * myKext    = NULL;  // must release (looked up)
+            IOLog("found OSNumber in kext map %p to %p  \n",
+                  (void *) kext_alloc_base,
+                  (void *) kext_alloc_max);
+            IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
+            
+            myKext = OSKext::lookupKextWithAddress( (vm_address_t) numberValue );
+            if (myKext) {
+                IOLog("found in kext \"%s\"  \n",
+                      myKext->getIdentifierCString());
+                myKext->release();
+            }
+            
+            myResult = true;
+        }
+        if ( vm_kernel_etext != 0 &&
+            numberValue >= vm_kernel_stext && 
+            numberValue < vm_kernel_etext ) {
+            IOLog("found OSNumber in kernel text segment %p to %p  \n",
+                  (void *) vm_kernel_stext,
+                  (void *) vm_kernel_etext);
+            IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
+            myResult = true;
+        }
+    }
+#if 0
+    else {
+        const OSMetaClass* myMetaClass = NULL;
+        
+        myMetaClass = theObject->getMetaClass();
+        if ( myMetaClass ) {
+            IOLog("class %s \n", myMetaClass->getClassName() );
+        }
+        else {
+            IOLog("Unknown object \n" );
+        }
+    }
+#endif
+    
+    return myResult;
+}
+#endif // KASLR_KEXT_DEBUG 
+
 }; /* extern "C" */
 
 #if PRAGMA_MARK
 #pragma mark Backtrace Dump & kmod_get_info() support
 #endif
 /*********************************************************************
+* This function must be safe to call in panic context.
 *********************************************************************/
 /* static */
 void
@@ -8225,76 +10878,251 @@ OSKext::printKextsInBacktrace(
     vm_offset_t  * addr,
     unsigned int   cnt,
     int         (* printf_func)(const char *fmt, ...),
-    bool           lockFlag)
+    uint32_t       flags)
 {
-    vm_offset_t      * kscan_addr = NULL;
-    kmod_info_t      * k = NULL;
-    kmod_reference_t * r = NULL;
-    unsigned int       i;
-    int                found_kmod = 0;
+    addr64_t    summary_page = 0;
+    addr64_t    last_summary_page = 0;
+    bool        found_kmod = false;
+    u_int       i = 0;
 
-    if (lockFlag) {
-        IORecursiveLockLock(sKextLock);
+    if (kPrintKextsLock & flags) {
+        if (!sKextSummariesLock) return;
+        IOLockLock(sKextSummariesLock);
     }
 
-    for (k = kmod; k; k = k->next) {
-        if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)k)) == 0) {
-            (*printf_func)("         kmod scan stopped due to missing "
-                "kmod page: %p\n", k);
-            break;
+    if (!gLoadedKextSummaries) {
+        (*printf_func)("         can't perform kext scan: no kext summary");
+        goto finish;
+    }
+
+    summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
+    last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
+    for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
+        if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
+            (*printf_func)("         can't perform kext scan: "
+                "missing kext summary page %p", summary_page);
+            goto finish;
+        }
+    }
+
+    for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
+        OSKextLoadedKextSummary * summary;
+        
+        summary = gLoadedKextSummaries->summaries + i;
+        if (!summary->address) {
+            continue;
+        }
+        
+        if (!summaryIsInBacktrace(summary, addr, cnt)) {
+            continue;
         }
-        if (!k->address) {
-            continue; // skip fake entries for built-in kernel components
+        
+        if (!found_kmod) {
+            if (!(kPrintKextsTerse & flags)) {
+                (*printf_func)("      Kernel Extensions in backtrace:\n");
+            }
+            found_kmod = true;
         }
-        for (i = 0, kscan_addr = addr; i < cnt; i++, kscan_addr++) {
-            if ((*kscan_addr >= k->address) &&
-                (*kscan_addr < (k->address + k->size))) {
 
-                if (!found_kmod) {
-                    (*printf_func)("      Kernel Extensions in backtrace "
-                        "(with dependencies):\n");
-                }
-                found_kmod = 1;
-                (*printf_func)("         %s(%s)@%p->%p\n",
-                    k->name, k->version, k->address, k->address + k->size - 1);
+        printSummary(summary, printf_func, flags);
+    }
 
-                for (r = k->reference_list; r; r = r->next) {
-                    kmod_info_t * rinfo;
+finish:
+    if (kPrintKextsLock & flags) {
+        IOLockUnlock(sKextSummariesLock);
+    }
 
-                    if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)r)) == 0) {
-                        (*printf_func)("            kmod dependency scan stopped "
-                            "due to missing dependency page: %p\n", r);
-                        break;
-                    }
+    return;
+}
 
-                    rinfo = r->info;
+/*********************************************************************
+* This function must be safe to call in panic context.
+*********************************************************************/
+/* static */
+boolean_t
+OSKext::summaryIsInBacktrace(
+    OSKextLoadedKextSummary   * summary,
+    vm_offset_t               * addr,
+    unsigned int                cnt)
+{
+    u_int i = 0;
+
+    for (i = 0; i < cnt; i++) {
+        vm_offset_t kscan_addr = addr[i];
+        if ((kscan_addr >= summary->address) &&
+            (kscan_addr < (summary->address + summary->size))) 
+        {
+            return TRUE;
+        }
+    }
 
-                    if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
-                        (*printf_func)("            kmod dependency scan stopped "
-                            "due to missing kmod page: %p\n", rinfo);
-                        break;
-                    }
+    return FALSE;
+}
 
-                    if (!rinfo->address) {
-                        continue; // skip fake entries for built-ins
-                    }
+/*
+ * Get the kext summary object for the kext where 'addr' lies. Must be called with
+ * sKextSummariesLock held.
+ */
+OSKextLoadedKextSummary *
+OSKext::summaryForAddress(const uintptr_t addr)
+{
+       for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
+
+               OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
+               if (!summary->address) {
+                       continue;
+               }
+
+#if VM_MAPPED_KEXTS
+               /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
+                * support split kexts, but we also may unmap the kexts, which can
+                * race with the above codepath (see OSKext::unload).  As such,
+                * use a simple range lookup if we are using VM_MAPPED_KEXTS.
+                */
+               if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
+                       return summary;
+               }
+#else
+               kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
+               kernel_segment_command_t *seg;
+
+               for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
+                       if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
+                               return summary;
+                       }
+               }
+#endif
+       }
 
-                    (*printf_func)("            dependency: %s(%s)@%p\n",
-                        rinfo->name, rinfo->version, rinfo->address);
-                }
+       /* addr did not map to any kext */
+       return NULL;
+}
 
-                break;  // only report this kmod for one backtrace address
-            }
+/* static */
+void *
+OSKext::kextForAddress(const void *addr)
+{
+       void *image = NULL;
+
+       if (((vm_offset_t)(uintptr_t)addr >= vm_kernel_stext) &&
+                       ((vm_offset_t)(uintptr_t)addr < vm_kernel_etext)) {
+               return (void *)&_mh_execute_header;
+       }
+
+       if (!sKextSummariesLock) {
+               return NULL;
+       }
+       IOLockLock(sKextSummariesLock);
+       OSKextLoadedKextSummary *summary = OSKext::summaryForAddress((uintptr_t)addr);
+       if (summary) {
+               image = (void *)summary->address;
+       }
+       IOLockUnlock(sKextSummariesLock);
+
+       return image;
+}
+
+/*********************************************************************
+ * scan list of loaded kext summaries looking for a load address match and if
+ * found return the UUID C string.  If not found then set empty string.
+ *********************************************************************/
+static void findSummaryUUID(
+                            uint32_t        tag_ID,
+                            uuid_string_t   uuid);
+
+static void findSummaryUUID(
+                            uint32_t        tag_ID, 
+                            uuid_string_t   uuid)
+{
+    u_int     i;
+    
+    uuid[0] = 0x00; // default to no UUID
+    
+    for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
+        OSKextLoadedKextSummary * summary;
+        
+        summary = gLoadedKextSummaries->summaries + i;
+        
+        if (summary->loadTag == tag_ID) {
+            (void) uuid_unparse(summary->uuid, uuid);
+            break;
         }
     }
-
-    if (lockFlag) {
-        IORecursiveLockUnlock(sKextLock);
+    return;
+}
+
+/*********************************************************************
+* This function must be safe to call in panic context.
+*********************************************************************/
+void OSKext::printSummary(
+    OSKextLoadedKextSummary * summary,
+    int                    (* printf_func)(const char *fmt, ...),
+    uint32_t                  flags)
+{
+    kmod_reference_t * kmod_ref = NULL;
+    uuid_string_t uuid;
+    char version[kOSKextVersionMaxLength];
+    uint64_t tmpAddr;
+
+    if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
+        strlcpy(version, "unknown version", sizeof(version));
+    }
+    (void) uuid_unparse(summary->uuid, uuid);
+    
+    if (kPrintKextsUnslide & flags) {
+        tmpAddr = VM_KERNEL_UNSLIDE(summary->address);
+    }
+    else {
+        tmpAddr = summary->address;
     }
+    (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
+               (kPrintKextsTerse & flags) ? "" : "         ",
+        summary->name, version, uuid,
+        tmpAddr, tmpAddr + summary->size - 1);
 
+    if (kPrintKextsTerse & flags) return;
+    
+    /* print dependency info */
+    for (kmod_ref = (kmod_reference_t *) summary->reference_list; 
+         kmod_ref; 
+         kmod_ref = kmod_ref->next) {
+        kmod_info_t * rinfo;
+        
+        if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
+            (*printf_func)("            kmod dependency scan stopped "
+                           "due to missing dependency page: %p\n",
+                          (kPrintKextsUnslide & flags) ? (void *)VM_KERNEL_UNSLIDE(kmod_ref) : kmod_ref);
+            break;
+        }
+        rinfo = kmod_ref->info;
+        
+        if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
+            (*printf_func)("            kmod dependency scan stopped "
+                           "due to missing kmod page: %p\n",
+                          (kPrintKextsUnslide & flags) ? (void *)VM_KERNEL_UNSLIDE(rinfo) : rinfo);
+            break;
+        }
+        
+        if (!rinfo->address) {
+            continue; // skip fake entries for built-ins
+        }
+        
+        /* locate UUID in gLoadedKextSummaries */
+        findSummaryUUID(rinfo->id, uuid);
+        
+        if (kPrintKextsUnslide & flags) {
+            tmpAddr = VM_KERNEL_UNSLIDE(rinfo->address);
+        }
+        else {
+            tmpAddr = rinfo->address;
+        }
+        (*printf_func)("            dependency: %s(%s)[%s]@%p\n",
+                       rinfo->name, rinfo->version, uuid, tmpAddr);
+    }
     return;
 }
 
+
 /*******************************************************************************
 * substitute() looks at an input string (a pointer within a larger buffer)
 * for a match to a substring, and on match it writes the marker & substitution
@@ -8423,12 +11251,15 @@ compactIdentifier(
 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
  */
 static int assemble_identifier_and_version(
-    kmod_info_t * kmod_info, 
-    char        * identPlusVers);
+                                           kmod_info_t * kmod_info,
+                                           char        * identPlusVers,
+                                           int           bufSize);
+
 static int
 assemble_identifier_and_version(
-    kmod_info_t * kmod_info, 
-    char        * identPlusVers)
+                                kmod_info_t * kmod_info, 
+                                char        * identPlusVers,
+                                int           bufSize)
 {
     int result = 0;
 
@@ -8436,29 +11267,29 @@ assemble_identifier_and_version(
     result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
     identPlusVers[result++] = '\t';  // increment for real char
     identPlusVers[result] = '\0';    // don't increment for nul char
-    result = strlcat(identPlusVers, kmod_info->version, KMOD_MAX_NAME);
-
+    result = strlcat(identPlusVers, kmod_info->version, bufSize);
+    if (result >= bufSize) {
+        identPlusVers[bufSize - 1] = '\0';
+        result = bufSize - 1;
+    }
+    
     return result;
 }
 
 /*******************************************************************************
+* Assumes sKextLock is held.
 *******************************************************************************/
-#define LAST_LOADED " - last loaded "
-#define LAST_LOADED_TS_WIDTH  (16)
-
 /* static */
-uint32_t
+int
 OSKext::saveLoadedKextPanicListTyped(
     const char * prefix,
     int          invertFlag,
     int          libsFlag,
     char       * paniclist,
-    uint32_t     list_size,
-    uint32_t   * list_length_ptr)
+    uint32_t     list_size)
 {
-    uint32_t      result = 0;
-    int           error  = 0;
-    unsigned int  count, i;
+    int             result = -1;
+    unsigned int    count, i;
 
     count = sLoadedKexts->getCount();
     if (!count) {
@@ -8467,12 +11298,24 @@ OSKext::saveLoadedKextPanicListTyped(
 
     i = count - 1;
     do {
-        OSKext      * theKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
-        kmod_info_t * kmod_info = theKext->kmod_info;
+        OSObject    * rawKext = sLoadedKexts->getObject(i);
+        OSKext      * theKext = OSDynamicCast(OSKext, rawKext);
         int           match;
-        char          identPlusVers[2*KMOD_MAX_NAME];
         uint32_t      identPlusVersLength;
-        char          timestampBuffer[17]; // enough for a uint64_t
+        uint32_t      tempLen;
+        char          identPlusVers[2*KMOD_MAX_NAME];
+        
+        if (!rawKext) {
+            printf("OSKext::saveLoadedKextPanicListTyped - "
+                "NULL kext in loaded kext list; continuing\n");
+            continue;
+        }
+
+        if (!theKext) {
+            printf("OSKext::saveLoadedKextPanicListTyped - "
+                "Kext type cast failed in loaded kext list; continuing\n");
+            continue;
+        }
 
        /* Skip all built-in kexts.
         */
@@ -8480,6 +11323,8 @@ OSKext::saveLoadedKextPanicListTyped(
             continue;
         }
 
+        kmod_info_t * kmod_info = theKext->kmod_info;
+
        /* Filter for kmod name (bundle identifier).
         */
         match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
@@ -8499,49 +11344,39 @@ OSKext::saveLoadedKextPanicListTyped(
             !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
 
             printf("kext scan stopped due to missing kmod_info page: %p\n",
-                kmod_info);
-            error = 1;
+                   kmod_info);
             goto finish;
         }
 
         identPlusVersLength = assemble_identifier_and_version(kmod_info,
-            identPlusVers);
+                                                              identPlusVers,
+                                                              sizeof(identPlusVers));
         if (!identPlusVersLength) {
             printf("error saving loaded kext info\n");
             goto finish;
         }
 
-       /* We're going to note the last-loaded kext in the list.
-        */
-        if (i + 1 == count) {
-            snprintf(timestampBuffer, sizeof(timestampBuffer), "%llu",
-                AbsoluteTime_to_scalar(&last_loaded_timestamp));
-            identPlusVersLength += sizeof(LAST_LOADED) - 1 +
-                strnlen(timestampBuffer, sizeof(timestampBuffer));
-        }
-
-       /* Adding 1 for the newline.
-        */
-        if (*list_length_ptr + identPlusVersLength + 1 >= list_size) {
+        /* make sure everything fits and we null terminate.
+         */
+        tempLen = strlcat(paniclist, identPlusVers, list_size);
+        if (tempLen >= list_size) {
+            // panic list is full, keep it and null terminate
+            paniclist[list_size - 1] = 0x00;
+            result = 0;
             goto finish;
         }
-        
-        *list_length_ptr = strlcat(paniclist, identPlusVers, list_size);
-        if (i + 1 == count) {
-            *list_length_ptr = strlcat(paniclist, LAST_LOADED, list_size);
-            *list_length_ptr = strlcat(paniclist, timestampBuffer, list_size);
+        tempLen = strlcat(paniclist, "\n", list_size);
+        if (tempLen >= list_size) {
+            // panic list is full, keep it and null terminate
+            paniclist[list_size - 1] = 0x00;
+            result = 0;
+            goto finish;
         }
-        *list_length_ptr = strlcat(paniclist, "\n", list_size);
-        
     } while (i--);
     
+    result = 0;
 finish:
-    if (!error) {
-        if (*list_length_ptr + 1 <= list_size) {
-            result = list_size - (*list_length_ptr + 1);
-        }
-    }
-
+    
     return result;
 }
 
@@ -8553,140 +11388,116 @@ OSKext::saveLoadedKextPanicList(void)
 {
     char     * newlist        = NULL;
     uint32_t   newlist_size   = 0;
-    uint32_t   newlist_length = 0;
-
-    IORecursiveLockLock(sKextLock);
-
-    newlist_length = 0;
+    
     newlist_size = KEXT_PANICLIST_SIZE;
-    newlist = (char *)kalloc(newlist_size);
+    newlist = (char *)kalloc_tag(newlist_size, VM_KERN_MEMORY_OSKEXT);
     
     if (!newlist) {
         OSKextLog(/* kext */ NULL,
-            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
-            "Couldn't allocate kext panic log buffer.");
+                  kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
+                  "Couldn't allocate kext panic log buffer.");
         goto finish;
     }
     
     newlist[0] = '\0';
-
+    
     // non-"com.apple." kexts
-    if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
-        /* libs? */ -1, newlist, newlist_size, &newlist_length)) {
+    if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
+                                             /* libs? */ -1, newlist, newlist_size) != 0) {
         
         goto finish;
     }
     // "com.apple." nonlibrary kexts
-    if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
-        /* libs? */ 0, newlist, newlist_size, &newlist_length)) {
+    if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
+                                             /* libs? */ 0, newlist, newlist_size) != 0) {
         
         goto finish;
     }
     // "com.apple." library kexts
-    if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
-        /* libs? */ 1, newlist, newlist_size, &newlist_length)) {
+    if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
+                                             /* libs? */ 1, newlist, newlist_size) != 0) {
         
         goto finish;
     }
-
+    
     if (loaded_kext_paniclist) {
         kfree(loaded_kext_paniclist, loaded_kext_paniclist_size);
     }
     loaded_kext_paniclist = newlist;
+    newlist = NULL;
     loaded_kext_paniclist_size = newlist_size;
-    loaded_kext_paniclist_length = newlist_length;
-
+    
 finish:
-    IORecursiveLockUnlock(sKextLock);
+    if (newlist) {
+        kfree(newlist, newlist_size);
+    }
     return;
 }
-
+    
 /*********************************************************************
+* Assumes sKextLock is held.
 *********************************************************************/
-/* static */
 void
-OSKext::saveUnloadedKextPanicList(OSKext * aKext)
+OSKext::savePanicString(bool isLoading)
 {
-    char     * newlist        = NULL;
-    uint32_t   newlist_size   = 0;
-    uint32_t   newlist_length = 0;
-    char       identPlusVers[2*KMOD_MAX_NAME];
-    uint32_t   identPlusVersLength;
+    u_long len;
 
-    if (!aKext->kmod_info) {
+    if (!kmod_info) {
         return;  // do not goto finish here b/c of lock
     }
 
-    IORecursiveLockLock(sKextLock);
-
-    clock_get_uptime(&last_unloaded_timestamp);
-    last_unloaded_address = (void *)aKext->kmod_info->address;
-    last_unloaded_size = aKext->kmod_info->size;
-
-
-    identPlusVersLength = assemble_identifier_and_version(aKext->kmod_info,
-        identPlusVers);
-    if (!identPlusVersLength) {
+    len = assemble_identifier_and_version( kmod_info,
+        (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
+        (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf) );
+    if (!len) {
         printf("error saving unloaded kext info\n");
         goto finish;
     }
 
-    newlist_length = identPlusVersLength;
-    newlist_size = newlist_length + 1;
-    newlist = (char *)kalloc(newlist_size);
-    
-    if (!newlist) {
-        printf("couldn't allocate kext panic log buffer\n");
-        goto finish;
-    }
-    
-    newlist[0] = '\0';
-
-    strlcpy(newlist, identPlusVers, newlist_size);
-
-    if (unloaded_kext_paniclist) {
-        kfree(unloaded_kext_paniclist, unloaded_kext_paniclist_size);
+    if (isLoading) {
+        last_loaded_strlen = len;
+        last_loaded_address = (void *)kmod_info->address;
+        last_loaded_size = kmod_info->size;
+        clock_get_uptime(&last_loaded_timestamp);
+    } else {
+        last_unloaded_strlen = len;
+        last_unloaded_address = (void *)kmod_info->address;
+        last_unloaded_size = kmod_info->size;
+        clock_get_uptime(&last_unloaded_timestamp);
     }
-    unloaded_kext_paniclist = newlist;
-    unloaded_kext_paniclist_size = newlist_size;
-    unloaded_kext_paniclist_length = newlist_length;
 
 finish:
-    IORecursiveLockUnlock(sKextLock);
     return;
 }
 
 /*********************************************************************
 *********************************************************************/
-#if __LP64__
-#define __kLoadSizeEscape  "0x%lld"
-#else
-#define __kLoadSizeEscape  "0x%ld"
-#endif /* __LP64__ */
-
 /* static */
 void
 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
 {
-    printf_func("unloaded kexts:\n");
-    if (unloaded_kext_paniclist &&
-        pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) unloaded_kext_paniclist) &&
-        unloaded_kext_paniclist[0]) {
+    if (last_loaded_strlen) {
+        printf_func("last loaded kext at %llu: %.*s (addr %p, size %lu)\n",
+            AbsoluteTime_to_scalar(&last_loaded_timestamp),
+            last_loaded_strlen, last_loaded_str_buf,
+            last_loaded_address, last_loaded_size);
+    }
 
-        printf_func(
-            "%.*s (addr %p, size " __kLoadSizeEscape ") - last unloaded %llu\n",
-            unloaded_kext_paniclist_length, unloaded_kext_paniclist,
-            last_unloaded_address, last_unloaded_size,
-            AbsoluteTime_to_scalar(&last_unloaded_timestamp));
-    } else {
-        printf_func("(none)\n");
+    if (last_unloaded_strlen) {
+        printf_func("last unloaded kext at %llu: %.*s (addr %p, size %lu)\n",
+            AbsoluteTime_to_scalar(&last_unloaded_timestamp),
+            last_unloaded_strlen, last_unloaded_str_buf,
+            last_unloaded_address, last_unloaded_size);
     }
+
     printf_func("loaded kexts:\n");
     if (loaded_kext_paniclist &&
         pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
         loaded_kext_paniclist[0]) {
 
-        printf_func("%.*s", loaded_kext_paniclist_length, loaded_kext_paniclist);
+        printf_func("%.*s",
+                    strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
+                    loaded_kext_paniclist);
     } else {
         printf_func("(none)\n");
     }
@@ -8694,529 +11505,382 @@ OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
 }
 
 /*********************************************************************
+* Assumes sKextLock is held.
 *********************************************************************/
-#if __ppc__ || __i386__
 /* static */
-kern_return_t
-OSKext::getKmodInfo(
-    kmod_info_array_t      * kmodList,
-    mach_msg_type_number_t * kmodCount)
+void
+OSKext::updateLoadedKextSummaries(void)
 {
     kern_return_t result = KERN_FAILURE;
-    vm_offset_t data;
-    kmod_info_t * k, * kmod_info_scan_ptr;
-    kmod_reference_t * r, * ref_scan_ptr;
-    int ref_count;
-    unsigned size = 0;
-
-    *kmodList = (kmod_info_t *)0;
-    *kmodCount = 0;
-
-    IORecursiveLockLock(sKextLock);
+    OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
+    OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
+    OSKext *aKext;
+    vm_map_offset_t start, end;
+    size_t summarySize = 0;
+    size_t size;
+    u_int count;
+    u_int maxKexts;
+    u_int i, j;
+    OSKextActiveAccount * accountingList;
+    OSKextActiveAccount * prevAccountingList;
+    uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
+    
+    prevAccountingList = NULL;
+    prevAccountingListCount = 0;
 
-    k = kmod;
-    while (k) {
-        size += sizeof(kmod_info_t);
-        r = k->reference_list;
-        while (r) {
-            size +=sizeof(kmod_reference_t);
-            r = r->next;
-        }
-        k = k->next;
+#if DEVELOPMENT || DEBUG
+    if (IORecursiveLockHaveLock(sKextLock) == false) {
+        panic("sKextLock must be held");
     }
-    if (!size) {
-        result = KERN_SUCCESS;
-        goto finish;
+#endif
+    
+    IOLockLock(sKextSummariesLock);
+    
+    count = sLoadedKexts->getCount();
+    for (i = 0, maxKexts = 0; i < count; ++i) {
+        aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
+        maxKexts += (aKext && aKext->isExecutable());
     }
-
-    result = kmem_alloc(kernel_map, &data, size);
-    if (result != KERN_SUCCESS) {
-        goto finish;
+    
+    if (!maxKexts) goto finish;
+    if (maxKexts < kOSKextTypicalLoadCount) maxKexts = kOSKextTypicalLoadCount;
+    
+    /* Calculate the size needed for the new summary headers.
+     */
+    
+    size = sizeof(*gLoadedKextSummaries);
+    size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
+    size = round_page(size);
+    
+    if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
+        if (gLoadedKextSummaries) {
+            kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
+            gLoadedKextSummaries = NULL;
+            gLoadedKextSummariesTimestamp = mach_absolute_time();
+            sLoadedKextSummariesAllocSize = 0;
+        }
+        result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size, VM_KERN_MEMORY_OSKEXT);
+        if (result != KERN_SUCCESS) goto finish;
+        summaryHeader = summaryHeaderAlloc;
+        summarySize = size;
+    }
+    else {
+        summaryHeader = gLoadedKextSummaries;
+        summarySize = sLoadedKextSummariesAllocSize;
+        
+        start = (vm_map_offset_t) summaryHeader;
+        end = start + summarySize;
+        result = vm_map_protect(kernel_map,
+                                start,
+                                end,
+                                VM_PROT_DEFAULT,
+                                FALSE);
+        if (result != KERN_SUCCESS) goto finish;
     }
+    
+    /* Populate the summary header.
+     */
+    
+    bzero(summaryHeader, summarySize);
+    summaryHeader->version = kOSKextLoadedKextSummaryVersion;
+    summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
 
-   /* Copy each kmod_info struct sequentially into the data buffer.
-    * Set each struct's nonzero 'next' pointer back to itself as a sentinel;
-    * the kernel space address is used to match refs, and a zero 'next' flags
-    * the end of kmod_infos in the data buffer and the beginning of references.
-    */
-    k = kmod;
-    kmod_info_scan_ptr = (kmod_info_t *)data;
-    while (k) {
-        *kmod_info_scan_ptr = *k;
-        if (k->next) {
-            kmod_info_scan_ptr->next = k;
+    /* Populate each kext summary.
+     */
+    
+    count = sLoadedKexts->getCount();
+    accountingListAlloc = 0;
+    for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
+        aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
+        if (!aKext || !aKext->isExecutable()) {
+            continue;
         }
-        kmod_info_scan_ptr++;
-        k = k->next;
+        
+        aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
+        summaryHeader->numSummaries++;
+       accountingListAlloc++;
     }
 
-   /* Now add references after the kmod_info structs in the same buffer.
-    * Update each kmod_info with the ref_count so we can associate
-    * references with kmod_info structs.
-    */
-    k = kmod;
-    ref_scan_ptr = (kmod_reference_t *)kmod_info_scan_ptr;
-    kmod_info_scan_ptr = (kmod_info_t *)data;
-    while (k) {
-        r = k->reference_list;
-        ref_count = 0;
-        while (r) {
-           /* Note the last kmod_info in the data buffer has its next == 0.
-            * Since there can only be one like that, 
-            * this case is handled by the caller.
-            */
-            *ref_scan_ptr = *r;
-            ref_scan_ptr++;
-            r = r->next;
-            ref_count++;
+    accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
+    accountingListCount = 0;
+    for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
+        aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
+        if (!aKext || !aKext->isExecutable()) {
+            continue;
         }
-       /* Stuff the # of refs into the 'reference_list' field of the kmod_info
-        * struct for the client to interpret.
-        */
-        kmod_info_scan_ptr->reference_list = (kmod_reference_t *)(long)ref_count;
-        kmod_info_scan_ptr++;
-        k = k->next;
+
+       OSKextActiveAccount activeAccount;
+       aKext->updateActiveAccount(&activeAccount);
+       // order by address
+       for (idx = 0; idx < accountingListCount; idx++)
+       {
+           if (activeAccount.address < accountingList[idx].address) break;
+       }
+       bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
+       accountingList[idx] = activeAccount;
+       accountingListCount++;
     }
+    assert(accountingListCount == accountingListAlloc);
+    /* Write protect the buffer and move it into place.
+     */
     
-    result = vm_map_copyin(kernel_map, data, size, TRUE, (vm_map_copy_t *)kmodList);
-    if (result != KERN_SUCCESS) {
+    start = (vm_map_offset_t) summaryHeader;
+    end = start + summarySize;
+
+    result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
+    if (result != KERN_SUCCESS)
         goto finish;
-    }
 
-    *kmodCount = size;
-    result = KERN_SUCCESS;
+    gLoadedKextSummaries = summaryHeader;
+    gLoadedKextSummariesTimestamp = mach_absolute_time();
+    sLoadedKextSummariesAllocSize = summarySize;
+    summaryHeaderAlloc = NULL;
+
+   /* Call the magic breakpoint function through a static function pointer so
+    * the compiler can't optimize the function away.
+    */
+    if (sLoadedKextSummariesUpdated) (*sLoadedKextSummariesUpdated)();
+
+    IOSimpleLockLock(sKextAccountsLock);
+    prevAccountingList      = sKextAccounts;
+    prevAccountingListCount = sKextAccountsCount;
+    sKextAccounts           = accountingList;
+    sKextAccountsCount      = accountingListCount;
+    IOSimpleLockUnlock(sKextAccountsLock);
 
 finish:
-    IORecursiveLockUnlock(sKextLock);
+    IOLockUnlock(sKextSummariesLock);
 
-    if (result != KERN_SUCCESS && data) {
-        kmem_free(kernel_map, data, size);
-        *kmodList = (kmod_info_t *)0;
-        *kmodCount = 0;
+   /* If we had to allocate a new buffer but failed to generate the summaries,
+    * free that now.
+    */
+    if (summaryHeaderAlloc) {
+        kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
     }
-    return result;
+    if (prevAccountingList) {
+        IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
+    }
+
+    return;
 }
-#endif /* __ppc__ || __i386__ */
-#if PRAGMA_MARK
-#pragma mark MAC Framework Support
-#endif
+
 /*********************************************************************
 *********************************************************************/
-#if CONFIG_MACF_KEXT
-/* MAC Framework support */
+void
+OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
+{
+    OSData *uuid;
 
-/* 
- * define IOC_DEBUG to display run-time debugging information
- * #define IOC_DEBUG 1
- */
+    strlcpy(summary->name, getIdentifierCString(), 
+        sizeof(summary->name));
 
-#ifdef IOC_DEBUG
-#define DPRINTF(x)    printf x
-#else
-#define IOC_DEBUG
-#define DPRINTF(x)
-#endif
+    uuid = copyUUID();
+    if (uuid) {
+        memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
+        OSSafeReleaseNULL(uuid);
+    }
+
+    summary->address = kmod_info->address;
+    summary->size = kmod_info->size;
+    summary->version = getVersion();
+    summary->loadTag = kmod_info->id;
+    summary->flags = 0;
+    summary->reference_list = (uint64_t) kmod_info->reference_list;
+
+    return;
+}
 
 /*********************************************************************
 *********************************************************************/
-static bool
-MACFObjectIsPrimitiveType(OSObject * obj)
+
+void
+OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
 {
-    const OSMetaClass * typeID = NULL;  // do not release
+    kernel_mach_header_t     *hdr = NULL;
+    kernel_segment_command_t *seg = NULL;
 
-    typeID = OSTypeIDInst(obj);
-    if (typeID == OSTypeID(OSString) || typeID == OSTypeID(OSNumber) ||
-        typeID == OSTypeID(OSBoolean) || typeID == OSTypeID(OSData)) {
+    hdr = (kernel_mach_header_t *)kmod_info->address;
 
-        return true;
+    if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO)) {
+        /* If this kext supports split segments, use the first
+         * executable segment as the range for instructions
+         * (and thus for backtracing.
+         */
+        for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
+            if (seg->initprot & VM_PROT_EXECUTE) {
+                break;
+            }
+        }
     }
-    return false;
-}
 
-/*********************************************************************
-*********************************************************************/
-static int
-MACFLengthForObject(OSObject * obj)
-{
-    const OSMetaClass * typeID = NULL;  // do not release
-    int len;
-
-    typeID = OSTypeIDInst(obj);
-    if (typeID == OSTypeID(OSString)) {
-        OSString * stringObj = OSDynamicCast(OSString, obj);
-        len = stringObj->getLength() + 1;
-    } else if (typeID == OSTypeID(OSNumber)) {
-        len = sizeof("4294967295");    /* UINT32_MAX */
-    } else if (typeID == OSTypeID(OSBoolean)) {
-        OSBoolean * boolObj = OSDynamicCast(OSBoolean, obj);
-        len = boolObj->isTrue() ? sizeof("true") : sizeof("false");
-    } else if (typeID == OSTypeID(OSData)) {
-        OSData * dataObj = OSDynamicCast(OSData, obj);
-        len = dataObj->getLength();
+    bzero(accountp, sizeof(*accountp));
+    if (seg) {
+        accountp->address = seg->vmaddr;
+        if (accountp->address) {
+            accountp->address_end = seg->vmaddr + seg->vmsize;
+        }
     } else {
-        len = 0;
+        /* For non-split kexts and for kexts without executable
+         * segments, just use the kmod_info range (as the kext
+         * is either all in one range or should not show up in
+         * instruction backtraces).
+         */
+        accountp->address = kmod_info->address;
+        if (accountp->address) {
+            accountp->address_end = kmod_info->address + kmod_info->size;
+        }
     }
-    return len;
+    accountp->account = this->account;
 }
 
-/*********************************************************************
-*********************************************************************/
-static void
-MACFInitElementFromObject(
-    struct mac_module_data_element * element,
-    OSObject                       * value)
-{
-    const OSMetaClass * typeID = NULL;  // do not release
-
-    typeID = OSTypeIDInst(value);
-    if (typeID == OSTypeID(OSString)) {
-        OSString * stringObj = OSDynamicCast(OSString, value);
-        element->value_type = MAC_DATA_TYPE_PRIMITIVE;
-        element->value_size = stringObj->getLength() + 1;
-        DPRINTF(("osdict: string %s size %d\n", 
-            stringObj->getCStringNoCopy(), element->value_size));
-        memcpy(element->value, stringObj->getCStringNoCopy(),
-            element->value_size);
-    } else if (typeID == OSTypeID(OSNumber)) {
-        OSNumber * numberObj = OSDynamicCast(OSNumber, value);
-        element->value_type = MAC_DATA_TYPE_PRIMITIVE;
-        element->value_size = sprintf(element->value, "%u",
-            numberObj->unsigned32BitValue()) + 1;
-    } else if (typeID == OSTypeID(OSBoolean)) {
-        OSBoolean * boolObj = OSDynamicCast(OSBoolean, value);
-        element->value_type = MAC_DATA_TYPE_PRIMITIVE;
-        if (boolObj->isTrue()) {
-            strcpy(element->value, "true");
-            element->value_size = 5;
-        } else {
-            strcpy(element->value, "false");
-            element->value_size = 6;
-        }
-    } else if (typeID == OSTypeID(OSData)) {
-        OSData * dataObj = OSDynamicCast(OSData, value);
-        element->value_type = MAC_DATA_TYPE_PRIMITIVE;
-        element->value_size = dataObj->getLength();
-        DPRINTF(("osdict: data size %d\n", dataObj->getLength()));
-        memcpy(element->value, dataObj->getBytesNoCopy(),
-            element->value_size);
+extern "C" const vm_allocation_site_t * 
+OSKextGetAllocationSiteForCaller(uintptr_t address)
+{
+    OSKextActiveAccount *  active;
+    vm_allocation_site_t * site;
+    vm_allocation_site_t * releasesite;
+
+    uint32_t baseIdx;
+    uint32_t lim;
+
+    IOSimpleLockLock(sKextAccountsLock);
+    site = releasesite = NULL;
+    
+    // bsearch sKextAccounts list
+    for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1)
+    {
+       active = &sKextAccounts[baseIdx + (lim >> 1)];
+       if ((address >= active->address) && (address < active->address_end))
+       {
+           site = &active->account->site;
+           if (!site->tag) vm_tag_alloc_locked(site, &releasesite);
+           break;
+       }
+       else if (address > active->address) 
+       {       
+           // move right
+           baseIdx += (lim >> 1) + 1;
+           lim--;
+       }
+       // else move left
+    }
+    IOSimpleLockUnlock(sKextAccountsLock);
+    if (releasesite) kern_allocation_name_release(releasesite);
+
+    return (site);
+}
+
+extern "C" uint32_t 
+OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
+{
+    OSKextAccount * account = (typeof(account)) site;
+    const char    * kname;
+
+    if (name)
+    {
+        if (account->kext) kname = account->kext->getIdentifierCString();
+        else               kname = "<>";
+        strlcpy(name, kname, namelen);
     }
-    return;
+
+    return (account->loadTag);
+}
+
+extern "C" void 
+OSKextFreeSite(vm_allocation_site_t * site)
+{
+    OSKextAccount * freeAccount = (typeof(freeAccount)) site;
+    IODelete(freeAccount, OSKextAccount, 1);
 }
 
 /*********************************************************************
-* This function takes an OSDictionary and returns a struct mac_module_data
-* list.
 *********************************************************************/
-static struct mac_module_data *
-MACFEncodeOSDictionary(OSDictionary * dict)
+    
+#if CONFIG_KEC_FIPS
+    
+#if PRAGMA_MARK
+#pragma mark Kernel External Components for FIPS compliance
+#endif
+    
+/*********************************************************************
+ * Kernel External Components for FIPS compliance (KEC_FIPS)
+ *********************************************************************/
+static void * 
+GetAppleTEXTHashForKext(OSKext * theKext, OSDictionary *theInfoDict)
 {
-    struct mac_module_data         * result      = NULL;  // do not free
-    const OSMetaClass              * typeID      = NULL;  // do not release
-    OSString                       * key         = NULL;  // do not release
-    OSCollectionIterator           * keyIterator = NULL;  // must release
-    struct mac_module_data_element * element     = NULL;  // do not free
-    unsigned int                     strtabsize  = 0;
-    unsigned int                     listtabsize = 0;
-    unsigned int                     dicttabsize = 0;
-    unsigned int                     nkeys       = 0;
-    unsigned int                     datalen     = 0;
-    char                           * strtab      = NULL;  // do not free
-    char                           * listtab     = NULL;  // do not free
-    char                           * dicttab     = NULL;  // do not free
-    vm_offset_t                      data_addr   = 0;
+    AppleTEXTHash_t         my_ath = {2, 0, NULL};
+    AppleTEXTHash_t *       my_athp = NULL;         // do not release
+    OSData *                segmentHash = NULL;     // do not release
     
-    keyIterator = OSCollectionIterator::withCollection(dict);
-    if (!keyIterator) {
-        goto finish;
+    if (theKext == NULL || theInfoDict == NULL) {
+        return(NULL);
     }
     
-    /* Iterate over OSModuleData to figure out total size */
-    while ( (key = OSDynamicCast(OSString, keyIterator->getNextObject())) ) {
-        
-        // Get the key's value and determine its type
-        OSObject * value = dict->getObject(key);
-        if (!value) {
-            continue;
-        }
-        
-        typeID = OSTypeIDInst(value);
-        if (MACFObjectIsPrimitiveType(value)) {
-            strtabsize += MACFLengthForObject(value);
-        }
-        else if (typeID == OSTypeID(OSArray)) {
-            unsigned int k, cnt, nents;
-            OSArray * arrayObj = OSDynamicCast(OSArray, value);
-            
-            nents = 0;
-            cnt = arrayObj->getCount();
-            for (k = 0; k < cnt; k++) {
-                value = arrayObj->getObject(k);
-                typeID = OSTypeIDInst(value);
-                if (MACFObjectIsPrimitiveType(value)) {
-                    listtabsize += MACFLengthForObject(value);
-                    nents++;
-                }
-                else if (typeID == OSTypeID(OSDictionary)) {
-                    unsigned int           dents = 0;
-                    OSDictionary         * dictObj      = NULL;  // do not release
-                    OSString             * dictkey      = NULL;  // do not release
-                    OSCollectionIterator * dictIterator = NULL;  // must release
-                    
-                    dictObj = OSDynamicCast(OSDictionary, value);
-                    dictIterator = OSCollectionIterator::withCollection(dictObj);
-                    if (!dictIterator) {
-                        goto finish;
-                    }
-                    while ((dictkey = OSDynamicCast(OSString,
-                        dictIterator->getNextObject()))) {
-
-                        OSObject * dictvalue = NULL;  // do not release
-                        
-                        dictvalue = dictObj->getObject(dictkey);
-                        if (!dictvalue) {
-                            continue;
-                        }
-                        if (MACFObjectIsPrimitiveType(dictvalue)) {
-                            strtabsize += MACFLengthForObject(dictvalue);
-                        } else {
-                            continue; /* Only handle primitive types here. */
-                        }
-                       /*
-                        * Allow for the "arraynnn/" prefix in the key length.
-                        */
-                        strtabsize += dictkey->getLength() + 1;
-                        dents++;
-                    }
-                    dictIterator->release();
-                    if (dents-- > 0) {
-                        dicttabsize += sizeof(struct mac_module_data_list) +
-                        dents * sizeof(struct mac_module_data_element);
-                        nents++;
-                    }
-                }
-                else {
-                    continue; /* Skip everything else. */
-                }
-            }
-            if (nents == 0) {
-                continue;
-            }
-            listtabsize += sizeof(struct mac_module_data_list) +
-                (nents - 1) * sizeof(struct mac_module_data_element);
-        } else {
-            continue; /* skip anything else */
-        }
-        strtabsize += key->getLength() + 1;
-        nkeys++;
-    }
-    if (nkeys == 0) {
-        goto finish;
+    // Get the part of the plist associate with kAppleTextHashesKey and let
+    // the crypto library do further parsing (slice/architecture)
+    segmentHash = OSDynamicCast(OSData, theInfoDict->getObject(kAppleTextHashesKey));
+    // Support for ATH v1 while rolling out ATH v2 without revision locking submissions
+    // Remove this when v2 PLIST are supported
+    if (segmentHash == NULL) {
+        // If this fails, we may be dealing with a v1 PLIST
+        OSDictionary *          textHashDict = NULL;    // do not release
+        textHashDict = OSDynamicCast(OSDictionary, theInfoDict->getObject(kAppleTextHashesKey));
+        if (textHashDict == NULL) {
+            return(NULL);
+        }
+        my_ath.ath_version=1;
+        segmentHash = OSDynamicCast(OSData,textHashDict->getObject(ARCHNAME));
+    } // end of v2 rollout
+
+    if (segmentHash == NULL) {
+        return(NULL);
     }
     
-   /*
-    * Allocate and fill in the module data structures.
-    */
-    datalen = sizeof(struct mac_module_data) +
-        sizeof(mac_module_data_element) * (nkeys - 1) +
-    strtabsize + listtabsize + dicttabsize;
-    DPRINTF(("osdict: datalen %d strtabsize %d listtabsize %d dicttabsize %d\n", 
-        datalen, strtabsize, listtabsize, dicttabsize));
-    if (kmem_alloc(kernel_map, &data_addr, datalen) != KERN_SUCCESS) {
-        goto finish;
+    // KEC_FIPS type kexts never unload so we don't have to clean up our 
+    // AppleTEXTHash_t
+    if (kmem_alloc(kernel_map, (vm_offset_t *) &my_athp, 
+                   sizeof(AppleTEXTHash_t), VM_KERN_MEMORY_OSKEXT) != KERN_SUCCESS) {
+        return(NULL);
     }
-    result = (mac_module_data *)data_addr;
-    result->base_addr = data_addr;
-    result->size = datalen;
-    result->count = nkeys;
-    strtab = (char *)&result->data[nkeys];
-    listtab = strtab + strtabsize;
-    dicttab = listtab + listtabsize;
-    DPRINTF(("osdict: data_addr %p strtab %p listtab %p dicttab %p end %p\n", 
-        data_addr, strtab, listtab, dicttab, data_addr + datalen));
     
-    keyIterator->reset();
-    nkeys = 0;
-    element = &result->data[0];
-    DPRINTF(("osdict: element %p\n", element));
-    while ( (key = OSDynamicCast(OSString, keyIterator->getNextObject())) ) {
-        
-        // Get the key's value and determine its type
-        OSObject * value = dict->getObject(key);
-        if (!value) {
-            continue;
-        }
+    memcpy(my_athp, &my_ath, sizeof(my_ath));
+    my_athp->ath_length = segmentHash->getLength();
+    if (my_athp->ath_length > 0) {
+        my_athp->ath_hash = (void *)segmentHash->getBytesNoCopy();
+    }
         
-        /* Store key */
-        DPRINTF(("osdict: element @%p\n", element));
-        element->key = strtab;
-        element->key_size = key->getLength() + 1;
-        DPRINTF(("osdict: key %s size %d @%p\n", key->getCStringNoCopy(),
-            element->key_size, strtab));
-        memcpy(element->key, key->getCStringNoCopy(), element->key_size);
+#if 0
+    OSKextLog(theKext,
+              kOSKextLogErrorLevel |
+              kOSKextLogGeneralFlag,
+              "Kext %s ath_version %d ath_length %d ath_hash %p",
+              theKext->getIdentifierCString(), 
+              my_athp->ath_version,
+              my_athp->ath_length,
+              my_athp->ath_hash); 
+#endif
         
-        typeID = OSTypeIDInst(value);
-        if (MACFObjectIsPrimitiveType(value)) {
-            /* Store value */
-            element->value = element->key + element->key_size;
-            DPRINTF(("osdict: primitive element value %p\n", element->value));
-            MACFInitElementFromObject(element, value);
-            strtab += element->key_size + element->value_size;
-            DPRINTF(("osdict: new strtab %p\n", strtab));
-        } else if (typeID == OSTypeID(OSArray)) {
-            unsigned int k, cnt, nents;
-            char *astrtab;
-            struct mac_module_data_list *arrayhd;
-            struct mac_module_data_element *ele;
-            OSArray *arrayObj = OSDynamicCast(OSArray, value);
-            
-            element->value = listtab;
-            DPRINTF(("osdict: array element value %p\n", element->value));
-            element->value_type = MAC_DATA_TYPE_ARRAY;
-            arrayhd = (struct mac_module_data_list *)element->value;
-            arrayhd->type = 0;
-            DPRINTF(("osdict: arrayhd %p\n", arrayhd));
-            nents = 0;
-            astrtab = strtab + element->key_size;
-            ele = &(arrayhd->list[0]);
-            cnt = arrayObj->getCount();
-            for (k = 0; k < cnt; k++) {
-                value = arrayObj->getObject(k);
-                DPRINTF(("osdict: array ele %d @%p\n", nents, ele));
-                ele->key = NULL;
-                ele->key_size = 0;
-                typeID = OSTypeIDInst(value);
-                if (MACFObjectIsPrimitiveType(value)) {
-                    if (arrayhd->type != 0 &&
-                        arrayhd->type != MAC_DATA_TYPE_PRIMITIVE) {
-
-                        continue;
-                    }
-                    arrayhd->type = MAC_DATA_TYPE_PRIMITIVE;
-                    ele->value = astrtab;
-                    MACFInitElementFromObject(ele, value);
-                    astrtab += ele->value_size;
-                    DPRINTF(("osdict: array new astrtab %p\n", astrtab));
-                } else if (typeID == OSTypeID(OSDictionary)) {
-                    unsigned int                     dents;
-                    char                           * dstrtab      = NULL;  // do not free
-                    OSDictionary                   * dictObj      = NULL;  // do not release
-                    OSString                       * dictkey      = NULL;  // do not release
-                    OSCollectionIterator           * dictIterator = NULL;  // must release
-                    struct mac_module_data_list    * dicthd       = NULL;  // do not free
-                    struct mac_module_data_element * dele         = NULL;  // do not free
-                    
-                    if (arrayhd->type != 0 &&
-                        arrayhd->type != MAC_DATA_TYPE_DICT) {
-
-                        continue;
-                    }
-                    dictObj = OSDynamicCast(OSDictionary, value);
-                    dictIterator = OSCollectionIterator::withCollection(dictObj);
-                    if (!dictIterator) {
-                        goto finish;
-                    }
-                    DPRINTF(("osdict: dict\n"));
-                    ele->value = dicttab;
-                    ele->value_type = MAC_DATA_TYPE_DICT;
-                    dicthd = (struct mac_module_data_list *)ele->value;
-                    DPRINTF(("osdict: dicthd %p\n", dicthd));
-                    dstrtab = astrtab;
-                    dents = 0;
-                    while ((dictkey = OSDynamicCast(OSString,
-                        dictIterator->getNextObject()))) {
-
-                        OSObject * dictvalue = NULL;  // do not release
-                        
-                        dictvalue = dictObj->getObject(dictkey);
-                        if (!dictvalue) {
-                            continue;
-                        }
-                        dele = &(dicthd->list[dents]);
-                        DPRINTF(("osdict: dict ele %d @%p\n", dents, dele));
-                        if (MACFObjectIsPrimitiveType(dictvalue)) {
-                            dele->key = dstrtab;
-                            dele->key_size = dictkey->getLength() + 1;
-                            DPRINTF(("osdict: dictkey %s size %d @%p\n",
-                                dictkey->getCStringNoCopy(), dictkey->getLength(), dstrtab));
-                            memcpy(dele->key, dictkey->getCStringNoCopy(),
-                                dele->key_size);
-                            dele->value = dele->key + dele->key_size;
-                            MACFInitElementFromObject(dele, dictvalue);
-                            dstrtab += dele->key_size + dele->value_size;
-                            DPRINTF(("osdict: dict new dstrtab %p\n", dstrtab));
-                        } else {
-                            continue;    /* Only handle primitive types here. */
-                        }
-                        dents++;
-                    }
-                    dictIterator->release();
-                    if (dents == 0) {
-                        continue;
-                    }
-                    arrayhd->type = MAC_DATA_TYPE_DICT;
-                    ele->value_size = sizeof(struct mac_module_data_list) +
-                        (dents - 1) * sizeof(struct mac_module_data_element);
-                    DPRINTF(("osdict: dict ele size %d ents %d\n", ele->value_size, dents));
-                    dicttab += ele->value_size;
-                    DPRINTF(("osdict: new dicttab %p\n", dicttab));
-                    dicthd->count = dents;
-                    astrtab = dstrtab;
-                } else {
-                    continue;        /* Skip everything else. */
-                }
-                nents++;
-                ele++;
-            }
-            if (nents == 0) {
-                continue;
-            }
-            element->value_size = sizeof(struct mac_module_data_list) +
-                (nents - 1) * sizeof(struct mac_module_data_element);
-            listtab += element->value_size;
-            DPRINTF(("osdict: new listtab %p\n", listtab));
-            arrayhd->count = nents;
-            strtab = astrtab;
-            DPRINTF(("osdict: new strtab %p\n", strtab));
-        } else {
-            continue;        /* skip anything else */
-        }
-        element++;
-    }
-    DPRINTF(("result list @%p, key %p value %p\n",
-        result, result->data[0].key, result->data[0].value));
-finish:
-    if (keyIterator) keyIterator->release();
-    return result;
+    return( (void *) my_athp );
 }
+    
+#endif // CONFIG_KEC_FIPS
 
-/*********************************************************************
-* This function takes a plist and looks for an OSModuleData dictionary.
-* If it is found, an encoded copy is returned. The value must be
-* kmem_free()'d.
-*********************************************************************/
-static void *
-MACFCopyModuleDataForKext(
-    OSKext                 * theKext,
-    mach_msg_type_number_t * datalen)
-
+#if CONFIG_IMAGEBOOT
+int OSKextGetUUIDForName(const char *name, uuid_t uuid)
 {
-    struct mac_module_data * result         = NULL;
-    OSDictionary           * kextModuleData = NULL;  // do not release
-    vm_map_copy_t            copy           = 0;
-    
-    kextModuleData = OSDynamicCast(OSDictionary,
-        theKext->getPropertyForHostArch("OSModuleData"));
-    if (!kextModuleData) {
-        goto finish;
-    }
-    
-    result = MACFEncodeOSDictionary(kextModuleData);
-    if (!result) {
-        goto finish;
-    }
-    *datalen = module_data->size;
+       OSKext *kext = OSKext::lookupKextWithIdentifier(name);
+       if (!kext) {
+               return 1;
+       }
 
-finish:
-    return (void *)result;
+       OSData *uuid_data = kext->copyUUID();
+       if (uuid_data) {
+               memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
+               OSSafeReleaseNULL(uuid_data);
+               return 0;
+       }
+
+       return 1;
 }
-#endif /* CONFIG_MACF_KEXT */
+#endif
+