/* * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * 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 #if !KERNEL #include #endif #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld" #include #include "kxld_array.h" #include "kxld_dict.h" #include "kxld_kext.h" #include "kxld_state.h" #include "kxld_sym.h" #include "kxld_symtab.h" #include "kxld_util.h" #include "kxld_vtable.h" #define LINK_STATE_MAGIC 0xF00DD00D #define CIGAM_ETATS_KNIL 0x0DD00DF0 #define LINK_STATE_MAGIC_64 0xCAFEF00D #define CIGAM_ETATS_KNIL_64 0x0DF0FECA #define LINK_STATE_VERSION 1 static kern_return_t init_string_index(KXLDDict *strings, KXLDArray *tmps, KXLDSymtabIterator *iter, const KXLDArray *vtables, u_int nsymentries, u_long *strsize); static kern_return_t add_string_to_index(KXLDDict *strings, const char *str, KXLDArray *tmps, u_int *tmpi, u_long *stroff); static kern_return_t create_link_state(u_char **_file, u_long *_filesize, const KXLDKext *kext, KXLDSymtabIterator *iter, const KXLDArray *vtables, KXLDDict *strings, u_int nsyms, u_int nsymentries, u_long strsize); static boolean_t state_is_32_bit(KXLDLinkStateHdr *state); #if KXLD_USER_OR_ILP32 static kern_return_t get_symbols_32(KXLDState *state, KXLDDict *defined_symbols, KXLDDict *obsolete_symbols); static kern_return_t copy_symbols_32(u_char *file, u_long *data_offset, KXLDSymtabIterator *iter, const KXLDDict *strings); static kern_return_t copy_vtables_32(u_char *file, u_long *header_offset, u_long *data_offset, const KXLDArray *vtables, const KXLDDict *strings); #endif /* KXLD_USER_OR_ILP32*/ #if KXLD_USER_OR_LP64 static kern_return_t get_symbols_64(KXLDState *state, KXLDDict *defined_symbols, KXLDDict *obsolete_symbols); static kern_return_t copy_symbols_64(u_char *file, u_long *data_offset, KXLDSymtabIterator *iter, const KXLDDict *strings); static kern_return_t copy_vtables_64(u_char *file, u_long *header_offset, u_long *data_offset, const KXLDArray *vtables, const KXLDDict *strings); #endif /* KXLD_USER_OR_ILP64 */ #if !KERNEL static boolean_t swap_link_state(u_char *state); static void swap_link_state_32(u_char *state); static void swap_link_state_64(u_char *state); static boolean_t unswap_link_state(u_char *state); static void unswap_link_state_32(u_char *state); static void unswap_link_state_64(u_char *state); static void swap_state_hdr(KXLDLinkStateHdr *state_hdr); static void swap_vtable_hdr(KXLDVTableHdr *vtable_hdr); static void swap_sym_entry_32(KXLDSymEntry32 *entry); static void swap_sym_entry_64(KXLDSymEntry64 *entry); #endif /******************************************************************************* *******************************************************************************/ kern_return_t kxld_state_init_from_file(KXLDState *state, u_char *file, KXLDArray *section_order __unused) { kern_return_t rval = KERN_FAILURE; KXLDLinkStateHdr *hdr = (KXLDLinkStateHdr *) file; #if KXLD_USER_OR_OBJECT KXLDSectionName *dstname = NULL; KXLDSectionName *srcname = NULL; #endif KXLDVTableHdr *vhdr = NULL; KXLDVTable *vtable = NULL; u_int i = 0; check(state); check(file); #if !KERNEL /* Swap the link state file to host byte order for as long this kxld_state * object owns the file. */ state->swap = swap_link_state(file); #endif require_action(hdr->magic == LINK_STATE_MAGIC || hdr->magic == LINK_STATE_MAGIC_64, finish, rval=KERN_FAILURE); state->file = file; #if KXLD_USER_OR_OBJECT if (section_order && !section_order->nitems && hdr->nsects) { rval = kxld_array_init(section_order, sizeof(*dstname), hdr->nsects); require_noerr(rval, finish); srcname = (KXLDSectionName *) (file + hdr->sectoff); for (i = 0; i < hdr->nsects; ++i, ++srcname) { dstname = kxld_array_get_item(section_order, i); memcpy(dstname, srcname, sizeof(*srcname)); } } #endif rval = kxld_array_init(&state->vtables, sizeof(*vtable), hdr->nvtables); require_noerr(rval, finish); vhdr = (KXLDVTableHdr *) (file + hdr->voff); for (i = 0; i < hdr->nvtables; ++i, ++vhdr) { vtable = kxld_array_get_item(&state->vtables, i); KXLD_3264_FUNC(kxld_is_32_bit(hdr->cputype), rval, kxld_vtable_init_from_link_state_32, kxld_vtable_init_from_link_state_64, vtable, file, vhdr); require_noerr(rval, finish); } rval = KERN_SUCCESS; finish: return rval; } /******************************************************************************* *******************************************************************************/ void kxld_state_clear(KXLDState *state) { KXLDVTable *vtable = NULL; u_int i = 0; check(state); #if !KERNEL /* We use kxld_state objects to wrap the link state files. Whenever the * file is wrapped by a kxld_state object, the file is kept in host byte * order. Once we are done, we must return it to target byte order. */ if (state->swap) (void)unswap_link_state(state->file); #endif state->file = NULL; state->swap = FALSE; for (i = 0; i < state->vtables.nitems; ++i) { vtable = kxld_array_get_item(&state->vtables, i); kxld_vtable_clear(vtable); } kxld_array_reset(&state->vtables); } /******************************************************************************* *******************************************************************************/ void kxld_state_deinit(KXLDState *state) { KXLDVTable *vtable = NULL; u_int i = 0; check(state); #if !KERNEL if (state->file && state->swap) (void)unswap_link_state(state->file); #endif for (i = 0; i < state->vtables.maxitems; ++i) { vtable = kxld_array_get_slot(&state->vtables, i); kxld_vtable_deinit(vtable); } kxld_array_deinit(&state->vtables); bzero(state, sizeof(*state)); } /******************************************************************************* *******************************************************************************/ u_int kxld_state_get_num_symbols(KXLDState *state) { KXLDLinkStateHdr *hdr = (KXLDLinkStateHdr *) state->file; return hdr->nsyms; } /******************************************************************************* *******************************************************************************/ kern_return_t kxld_state_get_symbols(KXLDState *state, KXLDDict *defined_symbols, KXLDDict *obsolete_symbols) { KXLDLinkStateHdr * hdr = (KXLDLinkStateHdr *) state->file; kern_return_t rval = KERN_FAILURE; check(state); check(defined_symbols); check(obsolete_symbols); require_action(hdr->magic == LINK_STATE_MAGIC || hdr->magic == LINK_STATE_MAGIC_64, finish, rval=KERN_FAILURE); KXLD_3264_FUNC(state_is_32_bit(hdr), rval, get_symbols_32, get_symbols_64, state, defined_symbols, obsolete_symbols); require_noerr(rval, finish); rval = KERN_SUCCESS; finish: return rval; } #if KXLD_USER_OR_ILP32 /******************************************************************************* *******************************************************************************/ static kern_return_t get_symbols_32(KXLDState *state, KXLDDict *defined_symbols, KXLDDict *obsolete_symbols) { kern_return_t rval = KERN_FAILURE; KXLDLinkStateHdr *hdr = (KXLDLinkStateHdr *) state->file; KXLDSymEntry32 *entry = NULL; const char *name = NULL; u_int i = 0; entry = (KXLDSymEntry32 *) (state->file + hdr->symoff); for (i = 0; i < hdr->nsyms; ++i, ++entry) { name = (const char *) (state->file + entry->nameoff); rval = kxld_dict_insert(defined_symbols, name, &entry->addr); require_noerr(rval, finish); if (entry->flags & KXLD_SYM_OBSOLETE) { rval = kxld_dict_insert(obsolete_symbols, name, &entry->addr); require_noerr(rval, finish); } } rval = KERN_SUCCESS; finish: return rval; } #endif /* KXLD_USER_OR_ILP32 */ #if KXLD_USER_OR_LP64 /******************************************************************************* *******************************************************************************/ static kern_return_t get_symbols_64(KXLDState *state, KXLDDict *defined_symbols, KXLDDict *obsolete_symbols) { kern_return_t rval = KERN_FAILURE; KXLDLinkStateHdr *hdr = (KXLDLinkStateHdr *) state->file; KXLDSymEntry64 *entry = NULL; const char *name = NULL; u_int i = 0; entry = (KXLDSymEntry64 *) (state->file + hdr->symoff); for (i = 0; i < hdr->nsyms; ++i, ++entry) { name = (const char *) (state->file + entry->nameoff); rval = kxld_dict_insert(defined_symbols, name, &entry->addr); require_noerr(rval, finish); if (entry->flags & KXLD_SYM_OBSOLETE) { rval = kxld_dict_insert(obsolete_symbols, name, &entry->addr); require_noerr(rval, finish); } } rval = KERN_SUCCESS; finish: return rval; } #endif /* KXLD_USER_OR_LP64 */ /******************************************************************************* *******************************************************************************/ u_int kxld_state_get_num_vtables(KXLDState *state) { return state->vtables.nitems; } /******************************************************************************* *******************************************************************************/ kern_return_t kxld_state_get_vtables(KXLDState *state, KXLDDict *patched_vtables) { kern_return_t rval = KERN_FAILURE; KXLDVTable *vtable = NULL; u_int i = 0; check(state); check(patched_vtables); for (i = 0; i < state->vtables.nitems; ++i) { vtable = kxld_array_get_item(&state->vtables, i); rval = kxld_dict_insert(patched_vtables, vtable->name, vtable); require_noerr(rval, finish); } rval = KERN_SUCCESS; finish: return rval; } /******************************************************************************* *******************************************************************************/ void kxld_state_get_cputype(const KXLDState *state, cpu_type_t *cputype, cpu_subtype_t *cpusubtype) { KXLDLinkStateHdr *hdr = (KXLDLinkStateHdr *) state->file; check(state); check(cputype); check(cpusubtype); *cputype = hdr->cputype; *cpusubtype = hdr->cpusubtype; } /******************************************************************************* *******************************************************************************/ kern_return_t kxld_state_export_kext_to_file(KXLDKext *kext, u_char **file, u_long *filesize, KXLDDict *strings, KXLDArray *tmps) { kern_return_t rval = KERN_FAILURE; KXLDSymtabIterator iter; const KXLDSymtab *symtab = NULL; const KXLDArray *vtables = NULL; const KXLDVTable *vtable = NULL; u_int nsyms = 0; u_int nsymentries = 0; u_int i = 0; u_long strsize = 0; check(kext); check(file); check(tmps); bzero(&iter, sizeof(iter)); /* Get the vtables and symbol tables from the kext */ kxld_kext_get_vtables(kext, &vtables); symtab = kxld_kext_get_symtab(kext); require_action(symtab, finish, rval=KERN_FAILURE); /* Count the number of symentries we'll need in the linkstate */ kxld_symtab_iterator_init(&iter, symtab, kxld_sym_is_exported, FALSE); nsyms = kxld_symtab_iterator_get_num_remaining(&iter); nsymentries = nsyms; for (i = 0; i < vtables->nitems; ++i) { vtable = kxld_array_get_item(vtables, i); nsymentries += vtable->entries.nitems; } /* Initialize the string index */ rval = init_string_index(strings, tmps, &iter, vtables, nsymentries, &strsize); require_noerr(rval, finish); /* Create the linkstate file */ rval = create_link_state(file, filesize, kext, &iter, vtables, strings, nsyms, nsymentries, strsize); require_noerr(rval, finish); /* Swap if necessary */ #if !KERNEL if (kxld_kext_target_needs_swap(kext)) unswap_link_state(*file); #endif /* !KERNEL */ rval = KERN_SUCCESS; finish: return rval; } /******************************************************************************* *******************************************************************************/ static kern_return_t init_string_index(KXLDDict *strings, KXLDArray *tmps, KXLDSymtabIterator *iter, const KXLDArray *vtables, u_int nsymentries, u_long *_strsize) { kern_return_t rval = KERN_SUCCESS; const KXLDSym *sym = NULL; const KXLDVTable *vtable = NULL; const KXLDVTableEntry *ventry = NULL; u_long strsize = 0; u_int tmpi = 0; u_int i = 0; u_int j = 0; check(strings); check(tmps); check(iter); check(vtables); check(_strsize); *_strsize = 0; /* Initialize the string dictionary and string offset array */ rval = kxld_dict_init(strings, kxld_dict_string_hash, kxld_dict_string_cmp, nsymentries); require_noerr(rval, finish); rval = kxld_array_init(tmps, sizeof(u_long), nsymentries); require_noerr(rval, finish); /* Add all of the strings from the symbol table to the dictionary */ kxld_symtab_iterator_reset(iter); while ((sym = kxld_symtab_iterator_get_next(iter))) { rval = add_string_to_index(strings, sym->name, tmps, &tmpi, &strsize); require_noerr(rval, finish); } /* Add all of the strings from the vtables entries to the dictionary */ for (i = 0; i < vtables->nitems; ++i) { vtable = kxld_array_get_item(vtables, i); rval = add_string_to_index(strings, vtable->name, tmps, &tmpi, &strsize); require_noerr(rval, finish); for (j = 0; j < vtable->entries.nitems; ++j) { ventry = kxld_array_get_item(&vtable->entries, j); if (ventry->patched.name) { rval = add_string_to_index(strings, ventry->patched.name, tmps, &tmpi, &strsize); require_noerr(rval, finish); } } } *_strsize = strsize; rval = KERN_SUCCESS; finish: return rval; } /******************************************************************************* *******************************************************************************/ static kern_return_t add_string_to_index(KXLDDict *strings, const char *str, KXLDArray *tmps, u_int *tmpi, u_long *stroff) { kern_return_t rval = KERN_FAILURE; u_long *tmpp = NULL; if (!kxld_dict_find(strings, str)) { tmpp = kxld_array_get_item(tmps, (*tmpi)++); *tmpp = *stroff; rval = kxld_dict_insert(strings, str, tmpp); require_noerr(rval, finish); *stroff += strlen(str) + 1; } rval = KERN_SUCCESS; finish: return rval; } /******************************************************************************* *******************************************************************************/ static boolean_t state_is_32_bit(KXLDLinkStateHdr *state) { return kxld_is_32_bit(state->cputype); } /******************************************************************************* *******************************************************************************/ static kern_return_t create_link_state(u_char **_file, u_long *_filesize, const KXLDKext *kext, KXLDSymtabIterator *iter, const KXLDArray *vtables, KXLDDict *strings, u_int nsyms, u_int nsymentries, u_long strsize) { kern_return_t rval = KERN_SUCCESS; u_char *file = NULL; KXLDLinkStateHdr *hdr = NULL; KXLDDictIterator striter; #if KXLD_USER_OR_OBJECT KXLDSectionName *dstsectname = NULL; KXLDSectionName *srcsectname = NULL; const KXLDArray *section_order = NULL; u_int i = 0; #endif const char *name = NULL; char *dstname = NULL; u_long *stridx = 0; u_long hsize = 0; u_long dsize = 0; u_long filesize = 0; u_long hoff = 0; u_long doff = 0; u_long stroff = 0; check(_file); check(iter); check(vtables); check(strings); *_file = NULL; *_filesize = 0; #if KXLD_USER_OR_OBJECT section_order = kxld_kext_get_section_order(kext); #endif /* Calculate header and data size */ hsize = sizeof(KXLDLinkStateHdr); hsize += vtables->nitems * sizeof(KXLDVTableHdr); #if KXLD_USER_OR_OBJECT if (section_order) { hsize += section_order->nitems * sizeof(KXLDSectionName); } #endif if (kxld_kext_is_32_bit(kext)) { dsize = nsymentries * sizeof(KXLDSymEntry32); } else { dsize = nsymentries * sizeof(KXLDSymEntry64); } filesize = hsize + dsize + strsize; hoff = 0; doff = hsize; stroff = hsize + dsize; /* Allocate the link state */ file = kxld_alloc_pageable(filesize); require_action(file, finish, rval=KERN_RESOURCE_SHORTAGE); /* Initialize link state header */ hdr = (KXLDLinkStateHdr *) file; hoff += sizeof(*hdr); if (state_is_32_bit(hdr)) { hdr->magic = LINK_STATE_MAGIC; } else { hdr->magic = LINK_STATE_MAGIC_64; } hdr->version = LINK_STATE_VERSION; kxld_kext_get_cputype(kext, &hdr->cputype, &hdr->cpusubtype); hdr->nsects = 0; hdr->nvtables = vtables->nitems; hdr->nsyms = nsyms; #if KXLD_USER_OR_OBJECT if (section_order) { hdr->nsects = section_order->nitems; hdr->sectoff = (uint32_t) hoff; dstsectname = (KXLDSectionName *) (file + hoff); hoff += section_order->nitems * sizeof(*dstsectname); for (i = 0; i < section_order->nitems; ++i, ++dstsectname) { srcsectname = kxld_array_get_item(section_order, i); memcpy(dstsectname, srcsectname, sizeof(*srcsectname)); } } #endif hdr->voff = (uint32_t) hoff; hdr->symoff = (uint32_t) doff; /* Copy strings */ kxld_dict_iterator_init(&striter, strings); kxld_dict_iterator_get_next(&striter, (const void **) &name, (void **) &stridx); while (name) { *stridx += stroff; dstname = (char *) (file + *stridx); strlcpy(dstname, name, filesize - *stridx); kxld_dict_iterator_get_next(&striter, (const void **) &name, (void **) &stridx); } /* Copy symbols */ KXLD_3264_FUNC(state_is_32_bit(hdr), rval, copy_symbols_32, copy_symbols_64, file, &doff, iter, strings); require_noerr(rval, finish); /* Copy vtables */ KXLD_3264_FUNC(state_is_32_bit(hdr), rval, copy_vtables_32, copy_vtables_64, file, &hoff, &doff, vtables, strings); require_noerr(rval, finish); *_file = file; *_filesize = filesize; file = NULL; rval = KERN_SUCCESS; finish: if (file) { kxld_page_free(file, filesize); file = NULL; } return rval; } #if KXLD_USER_OR_ILP32 /******************************************************************************* *******************************************************************************/ static kern_return_t copy_symbols_32(u_char *file, u_long *data_offset, KXLDSymtabIterator *iter, const KXLDDict *strings) { kern_return_t rval = KERN_FAILURE; KXLDSymEntry32 *symentry = NULL; const KXLDSym *sym = NULL; u_long *stridx = 0; kxld_symtab_iterator_reset(iter); while ((sym = kxld_symtab_iterator_get_next(iter))) { symentry = (KXLDSymEntry32 *) (file + *data_offset); stridx = kxld_dict_find(strings, sym->name); require_action(stridx, finish, rval=KERN_FAILURE); /* Initialize the symentry */ symentry->nameoff = (uint32_t) *stridx; if (sym->predicates.is_thumb) { symentry->addr = (uint32_t) sym->link_addr | 1; } else { symentry->addr = (uint32_t) sym->link_addr; } symentry->flags = 0; /* Set any flags */ symentry->flags |= (kxld_sym_is_obsolete(sym)) ? KXLD_SYM_OBSOLETE : 0; *data_offset += sizeof(*symentry); } rval = KERN_SUCCESS; finish: return rval; } #endif /* KXLD_USER_OR_ILP32 */ #if KXLD_USER_OR_LP64 /******************************************************************************* *******************************************************************************/ static kern_return_t copy_symbols_64(u_char *file, u_long *data_offset, KXLDSymtabIterator *iter, const KXLDDict *strings) { kern_return_t rval = KERN_FAILURE; KXLDSymEntry64 *symentry = NULL; const KXLDSym *sym = NULL; u_long *stridx = 0; kxld_symtab_iterator_reset(iter); while ((sym = kxld_symtab_iterator_get_next(iter))) { symentry = (KXLDSymEntry64 *) (file + *data_offset); stridx = kxld_dict_find(strings, sym->name); require_action(stridx, finish, rval=KERN_FAILURE); /* Initialize the symentry */ symentry->nameoff = (uint32_t) *stridx; symentry->addr = (uint64_t) sym->link_addr; symentry->flags = 0; /* Set any flags */ symentry->flags |= (kxld_sym_is_obsolete(sym)) ? KXLD_SYM_OBSOLETE : 0; *data_offset += sizeof(*symentry); } rval = KERN_SUCCESS; finish: return rval; } #endif /* KXLD_USER_OR_LP64 */ #if KXLD_USER_OR_ILP32 /******************************************************************************* *******************************************************************************/ static kern_return_t copy_vtables_32(u_char *file, u_long *header_offset, u_long *data_offset, const KXLDArray *vtables, const KXLDDict *strings) { kern_return_t rval = KERN_FAILURE; KXLDVTable *vtable = NULL; KXLDVTableHdr *vhdr = NULL; KXLDVTableEntry *ventry = NULL; KXLDSymEntry32 *symentry = NULL; u_long *stridx = 0; u_int i = 0; u_int j = 0; for (i = 0; i < vtables->nitems; ++i) { vtable = kxld_array_get_item(vtables, i); stridx = kxld_dict_find(strings, vtable->name); require_action(stridx, finish, rval=KERN_FAILURE); vhdr = (KXLDVTableHdr *) (file + *header_offset); vhdr->nameoff = (uint32_t) *stridx; vhdr->nentries = vtable->entries.nitems; vhdr->vtableoff = (uint32_t) (*data_offset); *header_offset += sizeof(*vhdr); for(j = 0; j < vtable->entries.nitems; ++j) { ventry = kxld_array_get_item(&vtable->entries, j); symentry = (KXLDSymEntry32 *) (file + *data_offset); if (ventry->patched.name) { stridx = kxld_dict_find(strings, ventry->patched.name); require_action(stridx, finish, rval=KERN_FAILURE); symentry->nameoff = (uint32_t) *stridx; symentry->addr = (uint32_t) ventry->patched.addr; } else { symentry->nameoff = 0; symentry->addr = 0; } *data_offset += sizeof(*symentry); } } rval = KERN_SUCCESS; finish: return rval; } #endif /* KXLD_USER_OR_ILP32 */ #if KXLD_USER_OR_LP64 /******************************************************************************* *******************************************************************************/ static kern_return_t copy_vtables_64(u_char *file, u_long *header_offset, u_long *data_offset, const KXLDArray *vtables, const KXLDDict *strings) { kern_return_t rval = KERN_FAILURE; KXLDVTable *vtable = NULL; KXLDVTableHdr *vhdr = NULL; KXLDVTableEntry *ventry = NULL; KXLDSymEntry64 *symentry = NULL; u_long *stridx = 0; u_int i = 0; u_int j = 0; for (i = 0; i < vtables->nitems; ++i) { vtable = kxld_array_get_item(vtables, i); stridx = kxld_dict_find(strings, vtable->name); require_action(stridx, finish, rval=KERN_FAILURE); vhdr = (KXLDVTableHdr *) (file + *header_offset); vhdr->nameoff = (uint32_t) *stridx; vhdr->nentries = vtable->entries.nitems; vhdr->vtableoff = (uint32_t) (*data_offset); *header_offset += sizeof(*vhdr); for(j = 0; j < vtable->entries.nitems; ++j) { ventry = kxld_array_get_item(&vtable->entries, j); symentry = (KXLDSymEntry64 *) (file + *data_offset); if (ventry->patched.name) { stridx = kxld_dict_find(strings, ventry->patched.name); require_action(stridx, finish, rval=KERN_FAILURE); symentry->nameoff = (uint32_t) *stridx; symentry->addr = (uint64_t) ventry->patched.addr; } else { symentry->nameoff = 0; symentry->addr = 0; } *data_offset += sizeof(*symentry); } } rval = KERN_SUCCESS; finish: return rval; } #endif /* KXLD_USER_OR_LP64 */ #if !KERNEL /******************************************************************************* *******************************************************************************/ static boolean_t swap_link_state(u_char *state) { KXLDLinkStateHdr *state_hdr = (KXLDLinkStateHdr *) state; if (state_hdr->magic == CIGAM_ETATS_KNIL) { swap_link_state_32(state); return TRUE; } else if (state_hdr->magic == CIGAM_ETATS_KNIL_64) { swap_link_state_64(state); return TRUE; } return FALSE; } /******************************************************************************* *******************************************************************************/ static void swap_link_state_32(u_char *state) { KXLDLinkStateHdr *state_hdr = NULL; KXLDVTableHdr *vtable_hdr = NULL; KXLDSymEntry32 *entry = NULL; u_int i = 0; u_int j = 0; state_hdr = (KXLDLinkStateHdr *) state; if (state_hdr->magic != CIGAM_ETATS_KNIL) return; /* Swap the header */ swap_state_hdr(state_hdr); /* Swap the symbols */ entry = (KXLDSymEntry32 *) (state + state_hdr->symoff); for (i = 0; i < state_hdr->nsyms; ++i, ++entry) { swap_sym_entry_32(entry); } /* Swap the vtable headers and entries */ vtable_hdr = (KXLDVTableHdr *) (state + state_hdr->voff); for (i = 0; i < state_hdr->nvtables; ++i, ++vtable_hdr) { swap_vtable_hdr(vtable_hdr); entry = (KXLDSymEntry32 *) (state + vtable_hdr->vtableoff); for (j = 0; j < vtable_hdr->nentries; ++j, ++entry) { swap_sym_entry_32(entry); } } } /******************************************************************************* *******************************************************************************/ static void swap_link_state_64(u_char *state) { KXLDLinkStateHdr *state_hdr = NULL; KXLDVTableHdr *vtable_hdr = NULL; KXLDSymEntry64 *entry = NULL; u_int i = 0; u_int j = 0; state_hdr = (KXLDLinkStateHdr *) state; if (state_hdr->magic != CIGAM_ETATS_KNIL_64) return; /* Swap the header */ swap_state_hdr(state_hdr); /* Swap the symbols */ entry = (KXLDSymEntry64 *) (state + state_hdr->symoff); for (i = 0; i < state_hdr->nsyms; ++i, ++entry) { swap_sym_entry_64(entry); } /* Swap the vtable headers and entries */ vtable_hdr = (KXLDVTableHdr *) (state + state_hdr->voff); for (i = 0; i < state_hdr->nvtables; ++i, ++vtable_hdr) { swap_vtable_hdr(vtable_hdr); entry = (KXLDSymEntry64 *) (state + vtable_hdr->vtableoff); for (j = 0; j < vtable_hdr->nentries; ++j, ++entry) { swap_sym_entry_64(entry); } } } /******************************************************************************* *******************************************************************************/ static boolean_t unswap_link_state(u_char *state) { KXLDLinkStateHdr *state_hdr = (KXLDLinkStateHdr *) state; if (state_hdr->magic == LINK_STATE_MAGIC) { unswap_link_state_32(state); return TRUE; } else if (state_hdr->magic == LINK_STATE_MAGIC_64) { unswap_link_state_64(state); return TRUE; } return FALSE; } /******************************************************************************* *******************************************************************************/ static void unswap_link_state_32(u_char *state) { KXLDLinkStateHdr *state_hdr = NULL; KXLDVTableHdr *vtable_hdr = NULL; KXLDSymEntry32 *entry = NULL; u_int i = 0; u_int j = 0; state_hdr = (KXLDLinkStateHdr *) state; if (state_hdr->magic != LINK_STATE_MAGIC) return; /* Unswap the vtables and their headers */ vtable_hdr = (KXLDVTableHdr *) (state + state_hdr->voff); for (i = 0; i < state_hdr->nvtables; ++i, ++vtable_hdr) { entry = (KXLDSymEntry32 *) (state + vtable_hdr->vtableoff); for (j = 0; j < vtable_hdr->nentries; ++j, ++entry) { swap_sym_entry_32(entry); } swap_vtable_hdr(vtable_hdr); } /* Unswap the symbols themselves */ entry = (KXLDSymEntry32 *) (state + state_hdr->symoff); for (i = 0; i < state_hdr->nsyms; ++i, ++entry) { swap_sym_entry_32(entry); } /* Unswap the header */ swap_state_hdr(state_hdr); } /******************************************************************************* *******************************************************************************/ static void unswap_link_state_64(u_char *state) { KXLDLinkStateHdr *state_hdr = NULL; KXLDVTableHdr *vtable_hdr = NULL; KXLDSymEntry64 *entry = NULL; u_int i = 0; u_int j = 0; state_hdr = (KXLDLinkStateHdr *) state; if (state_hdr->magic != LINK_STATE_MAGIC_64) return; /* Unswap the vtables and their headers */ vtable_hdr = (KXLDVTableHdr *) (state + state_hdr->voff); for (i = 0; i < state_hdr->nvtables; ++i, ++vtable_hdr) { entry = (KXLDSymEntry64 *) (state + vtable_hdr->vtableoff); for (j = 0; j < vtable_hdr->nentries; ++j, ++entry) { swap_sym_entry_64(entry); } swap_vtable_hdr(vtable_hdr); } /* Unswap the symbols themselves */ entry = (KXLDSymEntry64 *) (state + state_hdr->symoff); for (i = 0; i < state_hdr->nsyms; ++i, ++entry) { swap_sym_entry_64(entry); } /* Unswap the header */ swap_state_hdr(state_hdr); } /******************************************************************************* *******************************************************************************/ static void swap_state_hdr(KXLDLinkStateHdr *state_hdr) { state_hdr->magic = OSSwapInt32(state_hdr->magic); state_hdr->version = OSSwapInt32(state_hdr->version); state_hdr->cputype = OSSwapInt32(state_hdr->cputype); state_hdr->cpusubtype = OSSwapInt32(state_hdr->cpusubtype); state_hdr->nsects = OSSwapInt32(state_hdr->nsects); state_hdr->sectoff = OSSwapInt32(state_hdr->sectoff); state_hdr->nvtables = OSSwapInt32(state_hdr->nvtables); state_hdr->voff = OSSwapInt32(state_hdr->voff); state_hdr->nsyms = OSSwapInt32(state_hdr->nsyms); state_hdr->symoff = OSSwapInt32(state_hdr->symoff); } /******************************************************************************* *******************************************************************************/ static void swap_vtable_hdr(KXLDVTableHdr *vtable_hdr) { vtable_hdr->nameoff = OSSwapInt32(vtable_hdr->nameoff); vtable_hdr->vtableoff = OSSwapInt32(vtable_hdr->vtableoff); vtable_hdr->nentries = OSSwapInt32(vtable_hdr->nentries); } /******************************************************************************* *******************************************************************************/ static void swap_sym_entry_32(KXLDSymEntry32 *entry) { entry->nameoff = OSSwapInt32(entry->nameoff); entry->addr = OSSwapInt32(entry->addr); } /******************************************************************************* *******************************************************************************/ static void swap_sym_entry_64(KXLDSymEntry64 *entry) { entry->nameoff = OSSwapInt32(entry->nameoff); entry->addr = OSSwapInt64(entry->addr); } #endif /* !KERNEL */