gems-kernel/source/THIRDPARTY/xnu/libkern/kxld/kxld_util.c
2024-06-03 11:29:39 -05:00

914 lines
25 KiB
C

/*
* Copyright (c) 2007-2016 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#include <stdarg.h>
#include <string.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
#if KERNEL
#include <kern/kalloc.h>
#include <libkern/libkern.h>
#include <mach/vm_param.h>
#include <vm/vm_kern.h>
#else
#include <stdio.h>
#define __SPI_AVAILABLE(...)
#include <stdlib.h>
#include <mach/mach_init.h>
#include <mach-o/swap.h>
#endif
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
#include <AssertMacros.h>
#include "kxld_util.h"
/* swap_ functions are deprecated */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#if !KERNEL
static void unswap_macho_32(u_char *file, enum NXByteOrder host_order,
enum NXByteOrder target_order);
static void unswap_macho_64(u_char *file, enum NXByteOrder host_order,
enum NXByteOrder target_order);
#endif /* !KERNEL */
#if DEBUG
static unsigned long num_allocations = 0;
static unsigned long num_frees = 0;
static unsigned long bytes_allocated = 0;
static unsigned long bytes_freed = 0;
#endif
static KXLDLoggingCallback s_logging_callback = NULL;
static char s_callback_name[64] = "internal";
static void *s_callback_data = NULL;
#if !KERNEL
static boolean_t s_cross_link_enabled = FALSE;
/* Can't use PAGE_SIZE here because it is not a compile-time constant.
* However from inspection below, s_cross_link_page_size is not used
* unless s_cross_link_enabled is TRUE, and s_cross_link_enabled is
* only set to TRUE when a client specifies the value. So the
* default should never be used in practice,
*/
static kxld_size_t s_cross_link_page_size;
#endif
/*******************************************************************************
*******************************************************************************/
void
kxld_set_logging_callback(KXLDLoggingCallback logging_callback)
{
s_logging_callback = logging_callback;
}
/*******************************************************************************
*******************************************************************************/
void
kxld_set_logging_callback_data(const char *name, void *user_data)
{
if (name) {
(void)strlcpy(s_callback_name, name, sizeof(s_callback_name));
/* disallow format strings in the kxld logging callback name */
for (size_t i = 0; i < sizeof(s_callback_name); i++) {
if (s_callback_name[i] == '%') {
s_callback_name[i] = '.';
}
}
} else {
(void)strlcpy(s_callback_name, "internal", sizeof(s_callback_name));
}
s_callback_data = user_data;
}
/*******************************************************************************
*******************************************************************************/
void
kxld_log(KXLDLogSubsystem subsystem, KXLDLogLevel level,
const char *in_format, ...)
{
char stack_buffer[256];
char *alloc_buffer = NULL;
char *format = stack_buffer;
u_int length = 0;
va_list ap;
if (s_logging_callback) {
length = snprintf(stack_buffer, sizeof(stack_buffer), "kxld[%s]: %s",
s_callback_name, in_format);
if (length >= sizeof(stack_buffer)) {
length += 1;
alloc_buffer = kxld_alloc(length);
if (!alloc_buffer) {
return;
}
snprintf(alloc_buffer, length, "kxld[%s]: %s",
s_callback_name, in_format);
format = alloc_buffer;
}
va_start(ap, in_format);
s_logging_callback(subsystem, level, format, ap, s_callback_data);
va_end(ap);
if (alloc_buffer) {
kxld_free(alloc_buffer, length);
}
}
}
/* We'll use kalloc for any page-based allocations under this threshold, and
* kmem_alloc otherwise.
*/
#define KALLOC_MAX 16 * 1024
/*******************************************************************************
*******************************************************************************/
void *
kxld_calloc(size_t size)
{
void * ptr = NULL;
#if KERNEL
ptr = kheap_alloc_tag(KHEAP_DEFAULT, size, Z_WAITOK | Z_ZERO,
VM_KERN_MEMORY_OSKEXT);
#else
ptr = calloc(1, size);
#endif
#if DEBUG
if (ptr) {
++num_allocations;
bytes_allocated += size;
}
#endif
return ptr;
}
void *
kxld_alloc(size_t size)
{
void * ptr = NULL;
#if KERNEL
ptr = kheap_alloc_tag(KHEAP_DEFAULT, size, Z_WAITOK | Z_ZERO,
VM_KERN_MEMORY_OSKEXT);
#else
ptr = malloc(size);
#endif
#if DEBUG
if (ptr) {
++num_allocations;
bytes_allocated += size;
}
#endif
return ptr;
}
/*******************************************************************************
*******************************************************************************/
void *
kxld_page_alloc_untracked(size_t size)
{
void * ptr = NULL;
size = round_page(size);
#if KERNEL
ptr = kheap_alloc_tag(KHEAP_DEFAULT, size, Z_WAITOK | Z_ZERO,
VM_KERN_MEMORY_OSKEXT);
#else /* !KERNEL */
ptr = calloc(1, size);
#endif /* KERNEL */
return ptr;
}
/*******************************************************************************
*******************************************************************************/
void *
kxld_page_alloc(size_t size)
{
void * ptr = NULL;
ptr = kxld_page_alloc_untracked(size);
#if DEBUG
if (ptr) {
++num_allocations;
bytes_allocated += round_page(size);
}
#endif /* DEBUG */
return ptr;
}
/*******************************************************************************
*******************************************************************************/
void
kxld_free(void *ptr, size_t size __unused)
{
#if DEBUG
++num_frees;
bytes_freed += size;
#endif
#if KERNEL
kheap_free(KHEAP_DEFAULT, ptr, size);
#else
free(ptr);
#endif
}
/*******************************************************************************
*******************************************************************************/
void
kxld_page_free_untracked(void *ptr, size_t size __unused)
{
#if KERNEL
kheap_free(KHEAP_DEFAULT, ptr, round_page(size));
#else /* !KERNEL */
free(ptr);
#endif /* KERNEL */
}
/*******************************************************************************
*******************************************************************************/
void
kxld_page_free(void *ptr, size_t size)
{
#if DEBUG
++num_frees;
bytes_freed += round_page(size);
#endif /* DEBUG */
kxld_page_free_untracked(ptr, size);
}
/*******************************************************************************
*******************************************************************************/
kern_return_t
validate_and_swap_macho_32(u_char *file, u_long size
#if !KERNEL
, enum NXByteOrder host_order
#endif /* !KERNEL */
)
{
kern_return_t rval = KERN_FAILURE;
struct mach_header *mach_hdr = (struct mach_header *) ((void *) file);
struct load_command *load_hdr = NULL;
struct segment_command *seg_hdr = NULL;
struct section *sects = NULL;
struct relocation_info *relocs = NULL;
struct symtab_command *symtab_hdr = NULL;
struct nlist *symtab = NULL;
u_long offset = 0;
u_int cmd = 0;
u_int cmdsize = 0;
u_int i = 0;
u_int j = 0;
#if !KERNEL
boolean_t swap = FALSE;
#endif /* !KERNEL */
check(file);
check(size);
/* Verify that the file is big enough for the mach header */
require_action(size >= sizeof(*mach_hdr), finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
offset = sizeof(*mach_hdr);
#if !KERNEL
/* Swap the mach header if necessary */
if (mach_hdr->magic == MH_CIGAM) {
swap = TRUE;
(void) swap_mach_header(mach_hdr, host_order);
}
#endif /* !KERNEL */
/* Validate the mach_header's magic number */
require_action(mach_hdr->magic == MH_MAGIC, finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO
"Invalid magic number: 0x%x.", mach_hdr->magic));
/* If in the running kernel, and asked to validate the kernel
* (which is the only file of type MH_EXECUTE we should ever see),
* then just assume it's ok or we wouldn't be running to begin with.
*/
#if KERNEL
if (mach_hdr->filetype == MH_EXECUTE) {
rval = KERN_SUCCESS;
goto finish;
}
#endif /* KERNEL */
/* Validate and potentially swap the load commands */
for (i = 0; i < mach_hdr->ncmds; ++i, offset += cmdsize) {
/* Get the load command and size */
load_hdr = (struct load_command *) ((void *) (file + offset));
cmd = load_hdr->cmd;
cmdsize = load_hdr->cmdsize;
#if !KERNEL
if (swap) {
cmd = OSSwapInt32(load_hdr->cmd);
cmdsize = OSSwapInt32(load_hdr->cmdsize);
}
#endif /* !KERNEL */
/* Verify that the file is big enough to contain the load command */
require_action(size >= offset + cmdsize, finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
switch (cmd) {
case LC_SEGMENT:
/* Get and swap the segment header */
seg_hdr = (struct segment_command *) load_hdr;
#if !KERNEL
if (swap) {
swap_segment_command(seg_hdr, host_order);
}
#endif /* !KERNEL */
/* Get and swap the section headers */
sects = (struct section *) &seg_hdr[1];
#if !KERNEL
if (swap) {
swap_section(sects, seg_hdr->nsects, host_order);
}
#endif /* !KERNEL */
/* Ignore segments with no vm size */
if (!seg_hdr->vmsize) {
continue;
}
/* Verify that the file is big enough for the segment data. */
require_action(size >= seg_hdr->fileoff + seg_hdr->filesize, finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
for (j = 0; j < seg_hdr->nsects; ++j) {
/* Verify that, if the section is not to be zero filled on
* demand, that file is big enough for the section's data.
*/
require_action((sects[j].flags & S_ZEROFILL) ||
(size >= sects[j].offset + sects[j].size), finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
/* Verify that the file is big enough for the section's
* relocation entries.
*/
require_action(size >=
sects[j].reloff + sects[j].nreloc * sizeof(*relocs), finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
/* Swap the relocation entries */
relocs = (struct relocation_info *) ((void *) (file + sects[j].reloff));
#if !KERNEL
if (swap) {
swap_relocation_info(relocs, sects[j].nreloc,
host_order);
}
#endif /* !KERNEL */
}
break;
case LC_SYMTAB:
/* Get and swap the symtab header */
symtab_hdr = (struct symtab_command *) load_hdr;
#if !KERNEL
if (swap) {
swap_symtab_command(symtab_hdr, host_order);
}
#endif /* !KERNEL */
/* Verify that the file is big enough for the symbol table */
require_action(size >=
symtab_hdr->symoff + symtab_hdr->nsyms * sizeof(*symtab), finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
/* Verify that the file is big enough for the string table */
require_action(size >= symtab_hdr->stroff + symtab_hdr->strsize, finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
#if !KERNEL
/* Swap the symbol table entries */
symtab = (struct nlist *) ((void *) (file + symtab_hdr->symoff));
if (swap) {
swap_nlist(symtab, symtab_hdr->nsyms, host_order);
}
#endif /* !KERNEL */
break;
default:
#if !KERNEL
/* Swap the load command */
if (swap) {
swap_load_command(load_hdr, host_order);
}
#endif /* !KERNEL */
break;
}
}
rval = KERN_SUCCESS;
finish:
return rval;
}
/*******************************************************************************
*******************************************************************************/
kern_return_t
validate_and_swap_macho_64(u_char *file, u_long size
#if !KERNEL
, enum NXByteOrder host_order
#endif /* !KERNEL */
)
{
kern_return_t rval = KERN_FAILURE;
struct mach_header_64 *mach_hdr = (struct mach_header_64 *) ((void *) file);
struct load_command *load_hdr = NULL;
struct segment_command_64 *seg_hdr = NULL;
struct section_64 *sects = NULL;
struct relocation_info *relocs = NULL;
struct symtab_command *symtab_hdr = NULL;
struct nlist_64 *symtab = NULL;
u_long offset = 0;
u_int cmd = 0;
u_int cmdsize = 0;
u_int i = 0;
u_int j = 0;
#if !KERNEL
boolean_t swap = FALSE;
#endif /* !KERNEL */
check(file);
check(size);
/* Verify that the file is big enough for the mach header */
require_action(size >= sizeof(*mach_hdr), finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
offset = sizeof(*mach_hdr);
#if !KERNEL
/* Swap the mach header if necessary */
if (mach_hdr->magic == MH_CIGAM_64) {
swap = TRUE;
(void) swap_mach_header_64(mach_hdr, host_order);
}
#endif /* !KERNEL */
/* Validate the mach_header's magic number */
require_action(mach_hdr->magic == MH_MAGIC_64, finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO
"Invalid magic number: 0x%x.", mach_hdr->magic));
/* If in the running kernel, and asked to validate the kernel
* (which is the only file of type MH_EXECUTE we should ever see),
* then just assume it's ok or we wouldn't be running to begin with.
*/
#if KERNEL
if (mach_hdr->filetype == MH_EXECUTE) {
rval = KERN_SUCCESS;
goto finish;
}
#endif /* KERNEL */
/* Validate and potentially swap the load commands */
for (i = 0; i < mach_hdr->ncmds; ++i, offset += cmdsize) {
/* Get the load command and size */
load_hdr = (struct load_command *) ((void *) (file + offset));
cmd = load_hdr->cmd;
cmdsize = load_hdr->cmdsize;
#if !KERNEL
if (swap) {
cmd = OSSwapInt32(load_hdr->cmd);
cmdsize = OSSwapInt32(load_hdr->cmdsize);
}
#endif /* !KERNEL */
/* Verify that the file is big enough to contain the load command */
require_action(size >= offset + cmdsize, finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
switch (cmd) {
case LC_SEGMENT_64:
/* Get and swap the segment header */
seg_hdr = (struct segment_command_64 *) ((void *) load_hdr);
#if !KERNEL
if (swap) {
swap_segment_command_64(seg_hdr, host_order);
}
#endif /* !KERNEL */
/* Get and swap the section headers */
sects = (struct section_64 *) &seg_hdr[1];
#if !KERNEL
if (swap) {
swap_section_64(sects, seg_hdr->nsects, host_order);
}
#endif /* !KERNEL */
/* If the segment has no vm footprint, skip it */
if (!seg_hdr->vmsize) {
continue;
}
/* Verify that the file is big enough for the segment data. */
require_action(size >= seg_hdr->fileoff + seg_hdr->filesize, finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
for (j = 0; j < seg_hdr->nsects; ++j) {
/* Verify that, if the section is not to be zero filled on
* demand, that file is big enough for the section's data.
*/
require_action((sects[j].flags & S_ZEROFILL) ||
(size >= sects[j].offset + sects[j].size), finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
/* Verify that the file is big enough for the section's
* relocation entries.
*/
require_action(size >=
sects[j].reloff + sects[j].nreloc * sizeof(*relocs), finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
/* Swap the relocation entries */
relocs = (struct relocation_info *) ((void *) (file + sects[j].reloff));
#if !KERNEL
if (swap) {
swap_relocation_info(relocs, sects[j].nreloc,
host_order);
}
#endif /* !KERNEL */
}
break;
case LC_SYMTAB:
/* Get and swap the symtab header */
symtab_hdr = (struct symtab_command *) load_hdr;
#if !KERNEL
if (swap) {
swap_symtab_command(symtab_hdr, host_order);
}
#endif /* !KERNEL */
/* Verify that the file is big enough for the symbol table */
require_action(size >=
symtab_hdr->symoff + symtab_hdr->nsyms * sizeof(*symtab), finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
/* Verify that the file is big enough for the string table */
require_action(size >= symtab_hdr->stroff + symtab_hdr->strsize, finish,
rval = KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
#if !KERNEL
/* Swap the symbol table entries */
symtab = (struct nlist_64 *) ((void *) (file + symtab_hdr->symoff));
if (swap) {
swap_nlist_64(symtab, symtab_hdr->nsyms, host_order);
}
#endif /* !KERNEL */
break;
default:
#if !KERNEL
/* Swap the load command */
if (swap) {
swap_load_command(load_hdr, host_order);
}
#endif /* !KERNEL */
break;
}
}
rval = KERN_SUCCESS;
finish:
return rval;
}
#if !KERNEL
/*******************************************************************************
*******************************************************************************/
void
unswap_macho(u_char *file, enum NXByteOrder host_order,
enum NXByteOrder target_order)
{
struct mach_header *hdr = (struct mach_header *) ((void *) file);
if (!hdr) {
return;
}
if (hdr->magic == MH_MAGIC) {
unswap_macho_32(file, host_order, target_order);
} else if (hdr->magic == MH_MAGIC_64) {
unswap_macho_64(file, host_order, target_order);
}
}
/*******************************************************************************
*******************************************************************************/
static void
unswap_macho_32(u_char *file, enum NXByteOrder host_order,
enum NXByteOrder target_order)
{
struct mach_header *mach_hdr = (struct mach_header *) ((void *) file);
struct load_command *load_hdr = NULL;
struct segment_command *seg_hdr = NULL;
struct section *sects = NULL;
struct symtab_command *symtab_hdr = NULL;
struct nlist *symtab = NULL;
u_long offset = 0;
u_int cmd = 0;
u_int size = 0;
u_int i = 0;
check(file);
if (target_order == host_order) {
return;
}
offset = sizeof(*mach_hdr);
for (i = 0; i < mach_hdr->ncmds; ++i, offset += size) {
load_hdr = (struct load_command *) ((void *) (file + offset));
cmd = load_hdr->cmd;
size = load_hdr->cmdsize;
switch (cmd) {
case LC_SEGMENT:
seg_hdr = (struct segment_command *) load_hdr;
sects = (struct section *) &seg_hdr[1];
/* We don't need to unswap relocations because this function is
* called when linking is completed (so there are no relocations).
*/
swap_section(sects, seg_hdr->nsects, target_order);
swap_segment_command(seg_hdr, target_order);
break;
case LC_SYMTAB:
symtab_hdr = (struct symtab_command *) load_hdr;
symtab = (struct nlist*) ((void *) (file + symtab_hdr->symoff));
swap_nlist(symtab, symtab_hdr->nsyms, target_order);
swap_symtab_command(symtab_hdr, target_order);
break;
default:
swap_load_command(load_hdr, target_order);
break;
}
}
(void) swap_mach_header(mach_hdr, target_order);
}
/*******************************************************************************
*******************************************************************************/
static void
unswap_macho_64(u_char *file, enum NXByteOrder host_order,
enum NXByteOrder target_order)
{
struct mach_header_64 *mach_hdr = (struct mach_header_64 *) ((void *) file);
struct load_command *load_hdr = NULL;
struct segment_command_64 *seg_hdr = NULL;
struct section_64 *sects = NULL;
struct symtab_command *symtab_hdr = NULL;
struct nlist_64 *symtab = NULL;
u_long offset = 0;
u_int cmd = 0;
u_int size = 0;
u_int i = 0;
check(file);
if (target_order == host_order) {
return;
}
offset = sizeof(*mach_hdr);
for (i = 0; i < mach_hdr->ncmds; ++i, offset += size) {
load_hdr = (struct load_command *) ((void *) (file + offset));
cmd = load_hdr->cmd;
size = load_hdr->cmdsize;
switch (cmd) {
case LC_SEGMENT_64:
seg_hdr = (struct segment_command_64 *) ((void *) load_hdr);
sects = (struct section_64 *) &seg_hdr[1];
/* We don't need to unswap relocations because this function is
* called when linking is completed (so there are no relocations).
*/
swap_section_64(sects, seg_hdr->nsects, target_order);
swap_segment_command_64(seg_hdr, target_order);
break;
case LC_SYMTAB:
symtab_hdr = (struct symtab_command *) load_hdr;
symtab = (struct nlist_64 *) ((void *) (file + symtab_hdr->symoff));
swap_nlist_64(symtab, symtab_hdr->nsyms, target_order);
swap_symtab_command(symtab_hdr, target_order);
break;
default:
swap_load_command(load_hdr, target_order);
break;
}
}
(void) swap_mach_header_64(mach_hdr, target_order);
}
#endif /* !KERNEL */
/*******************************************************************************
*******************************************************************************/
kxld_addr_t
kxld_align_address(kxld_addr_t address, u_int align)
{
kxld_addr_t alignment = (1 << align);
kxld_addr_t low_bits = 0;
if (!align) {
return address;
}
low_bits = (address) & (alignment - 1);
if (low_bits) {
address += (alignment - low_bits);
}
return address;
}
/*******************************************************************************
*******************************************************************************/
boolean_t
kxld_is_32_bit(cpu_type_t cputype)
{
return !(cputype & CPU_ARCH_ABI64);
}
/*******************************************************************************
*******************************************************************************/
void
kxld_print_memory_report(void)
{
#if DEBUG
kxld_log(kKxldLogLinking, kKxldLogExplicit, "kxld memory usage report:\n"
"\tNumber of allocations: %8lu\n"
"\tNumber of frees: %8lu\n"
"\tAverage allocation size: %8lu\n"
"\tTotal bytes allocated: %8lu\n"
"\tTotal bytes freed: %8lu\n"
"\tTotal bytes leaked: %8lu",
num_allocations, num_frees, bytes_allocated / num_allocations,
bytes_allocated, bytes_freed, bytes_allocated - bytes_freed);
#endif
}
/*********************************************************************
*********************************************************************/
#if !KERNEL
boolean_t
kxld_set_cross_link_page_size(kxld_size_t target_page_size)
{
// verify radix 2
if ((target_page_size != 0) &&
((target_page_size & (target_page_size - 1)) == 0)) {
s_cross_link_enabled = TRUE;
s_cross_link_page_size = target_page_size;
return TRUE;
} else {
return FALSE;
}
}
#endif /* !KERNEL */
/*********************************************************************
*********************************************************************/
kxld_size_t
kxld_get_effective_page_size(void)
{
#if KERNEL
return PAGE_SIZE;
#else
if (s_cross_link_enabled) {
return s_cross_link_page_size;
} else {
return PAGE_SIZE;
}
#endif /* KERNEL */
}
/*********************************************************************
*********************************************************************/
kxld_addr_t
kxld_round_page_cross_safe(kxld_addr_t offset)
{
#if KERNEL
return round_page(offset);
#else
// assume s_cross_link_page_size is power of 2
if (s_cross_link_enabled) {
return (offset + (s_cross_link_page_size - 1)) &
(~(s_cross_link_page_size - 1));
} else {
return round_page(offset);
}
#endif /* KERNEL */
}
#if SPLIT_KEXTS_DEBUG
void
kxld_show_split_info(splitKextLinkInfo *info)
{
kxld_log(kKxldLogLinking, kKxldLogErr,
"splitKextLinkInfo: \n"
"kextExecutable %p to %p kextSize %lu \n"
"linkedKext %p to %p linkedKextSize %lu \n"
"vmaddr_TEXT %p vmaddr_TEXT_EXEC %p "
"vmaddr_DATA %p vmaddr_DATA_CONST %p "
"vmaddr_LLVM_COV %p vmaddr_LINKEDIT %p",
(void *) info->kextExecutable,
(void *) (info->kextExecutable + info->kextSize),
info->kextSize,
(void*) info->linkedKext,
(void*) (info->linkedKext + info->linkedKextSize),
info->linkedKextSize,
(void *) info->vmaddr_TEXT,
(void *) info->vmaddr_TEXT_EXEC,
(void *) info->vmaddr_DATA,
(void *) info->vmaddr_DATA_CONST,
(void *) info->vmaddr_LLVM_COV,
(void *) info->vmaddr_LINKEDIT);
}
boolean_t
isTargetKextName(const char * the_name)
{
if (the_name && 0 == strcmp(the_name, KXLD_TARGET_KEXT)) {
return TRUE;
}
return FALSE;
}
#endif
#pragma clang diagnostic pop