mirror of
https://github.com/darlinghq/darling.git
synced 2024-11-23 12:19:43 +00:00
Upgrade to dyld-733.6
This commit is contained in:
parent
0fdb4caa71
commit
c14b6598b5
@ -7,7 +7,7 @@ function(add_darling_static_library name)
|
||||
cmake_parse_arguments(STATIC_LIB "FAT" "" "SOURCES" ${ARGN})
|
||||
|
||||
set(CMAKE_AR "${CMAKE_BINARY_DIR}/src/external/cctools-port/cctools/ar/x86_64-apple-darwin11-ar")
|
||||
set(CMAKE_RANLIB "${CMAKE_BINARY_DIR}/src/external/cctools-port/cctools/misc/ranlib")
|
||||
set(CMAKE_RANLIB "${CMAKE_BINARY_DIR}/src/external/cctools-port/cctools/ar/x86_64-apple-darwin11-ranlib")
|
||||
add_library(${name} STATIC ${STATIC_LIB_SOURCES})
|
||||
|
||||
set_property(TARGET ${name} APPEND_STRING PROPERTY COMPILE_FLAGS " -B ${CMAKE_BINARY_DIR}/src/external/cctools-port/cctools/misc/")
|
||||
|
@ -116,6 +116,23 @@
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* __API_TO_BE_DEPRECATED is used as a version number in API that will be deprecated
|
||||
* in an upcoming release. This soft deprecation is an intermediate step before formal
|
||||
* deprecation to notify developers about the API before compiler warnings are generated.
|
||||
* You can find all places in your code that use soft deprecated API by redefining the
|
||||
* value of this macro to your current minimum deployment target, for example:
|
||||
* (macOS)
|
||||
* clang -D__API_TO_BE_DEPRECATED=10.12 <other compiler flags>
|
||||
* (iOS)
|
||||
* clang -D__API_TO_BE_DEPRECATED=11.0 <other compiler flags>
|
||||
*/
|
||||
|
||||
#ifndef __API_TO_BE_DEPRECATED
|
||||
#define __API_TO_BE_DEPRECATED 100000
|
||||
#endif
|
||||
|
||||
#ifndef __MAC_10_0
|
||||
#define __MAC_10_0 1000
|
||||
#define __MAC_10_1 1010
|
||||
#define __MAC_10_2 1020
|
||||
@ -137,6 +154,15 @@
|
||||
#define __MAC_10_12_1 101201
|
||||
#define __MAC_10_12_2 101202
|
||||
#define __MAC_10_12_4 101204
|
||||
#define __MAC_10_13 101300
|
||||
#define __MAC_10_13_1 101301
|
||||
#define __MAC_10_13_2 101302
|
||||
#define __MAC_10_13_4 101304
|
||||
#define __MAC_10_14 101400
|
||||
#define __MAC_10_14_1 101401
|
||||
#define __MAC_10_14_4 101404
|
||||
#define __MAC_10_15 101500
|
||||
#define __MAC_10_15_1 101501
|
||||
/* __MAC_NA is not defined to a value but is uses as a token by macros to indicate that the API is unavailable */
|
||||
|
||||
#define __IPHONE_2_0 20000
|
||||
@ -168,6 +194,18 @@
|
||||
#define __IPHONE_10_1 100100
|
||||
#define __IPHONE_10_2 100200
|
||||
#define __IPHONE_10_3 100300
|
||||
#define __IPHONE_11_0 110000
|
||||
#define __IPHONE_11_1 110100
|
||||
#define __IPHONE_11_2 110200
|
||||
#define __IPHONE_11_3 110300
|
||||
#define __IPHONE_11_4 110400
|
||||
#define __IPHONE_12_0 120000
|
||||
#define __IPHONE_12_1 120100
|
||||
#define __IPHONE_12_2 120200
|
||||
#define __IPHONE_12_3 120300
|
||||
#define __IPHONE_13_0 130000
|
||||
#define __IPHONE_13_1 130100
|
||||
#define __IPHONE_13_2 130200
|
||||
/* __IPHONE_NA is not defined to a value but is uses as a token by macros to indicate that the API is unavailable */
|
||||
|
||||
#define __TVOS_9_0 90000
|
||||
@ -177,6 +215,17 @@
|
||||
#define __TVOS_10_0_1 100001
|
||||
#define __TVOS_10_1 100100
|
||||
#define __TVOS_10_2 100200
|
||||
#define __TVOS_11_0 110000
|
||||
#define __TVOS_11_1 110100
|
||||
#define __TVOS_11_2 110200
|
||||
#define __TVOS_11_3 110300
|
||||
#define __TVOS_11_4 110400
|
||||
#define __TVOS_12_0 120000
|
||||
#define __TVOS_12_1 120100
|
||||
#define __TVOS_12_2 120200
|
||||
#define __TVOS_12_3 120300
|
||||
#define __TVOS_13_0 130000
|
||||
#define __TVOS_13_1 130100
|
||||
|
||||
#define __WATCHOS_1_0 10000
|
||||
#define __WATCHOS_2_0 20000
|
||||
@ -186,6 +235,18 @@
|
||||
#define __WATCHOS_3_1 30100
|
||||
#define __WATCHOS_3_1_1 30101
|
||||
#define __WATCHOS_3_2 30200
|
||||
#define __WATCHOS_4_0 40000
|
||||
#define __WATCHOS_4_1 40100
|
||||
#define __WATCHOS_4_2 40200
|
||||
#define __WATCHOS_4_3 40300
|
||||
#define __WATCHOS_5_0 50000
|
||||
#define __WATCHOS_5_1 50100
|
||||
#define __WATCHOS_5_2 50200
|
||||
#define __WATCHOS_6_0 60000
|
||||
#define __WATCHOS_6_0_1 60001
|
||||
|
||||
#define __DRIVERKIT_19_0 190000
|
||||
#endif /* __MAC_10_0 */
|
||||
|
||||
#include <AvailabilityInternal.h>
|
||||
|
||||
@ -197,11 +258,44 @@
|
||||
__AVAILABILITY_INTERNAL##_iosIntro##_DEP##_iosDep##_MSG(_msg)
|
||||
|
||||
#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
|
||||
|
||||
#if defined(__has_builtin)
|
||||
#if __has_builtin(__is_target_arch)
|
||||
#if __has_builtin(__is_target_vendor)
|
||||
#if __has_builtin(__is_target_os)
|
||||
#if __has_builtin(__is_target_environment)
|
||||
#if __has_builtin(__is_target_variant_os)
|
||||
#if __has_builtin(__is_target_variant_environment)
|
||||
#if (__is_target_arch(x86_64) && __is_target_vendor(apple) && ((__is_target_os(ios) && __is_target_environment(macabi)) || (__is_target_variant_os(ios) && __is_target_variant_environment(macabi))))
|
||||
#define __OSX_AVAILABLE_STARTING(_osx, _ios) __AVAILABILITY_INTERNAL##_osx __AVAILABILITY_INTERNAL##_ios
|
||||
#define __OSX_AVAILABLE_BUT_DEPRECATED(_osxIntro, _osxDep, _iosIntro, _iosDep) \
|
||||
__AVAILABILITY_INTERNAL##_osxIntro##_DEP##_osxDep __AVAILABILITY_INTERNAL##_iosIntro##_DEP##_iosDep
|
||||
#define __OSX_AVAILABLE_BUT_DEPRECATED_MSG(_osxIntro, _osxDep, _iosIntro, _iosDep, _msg) \
|
||||
__AVAILABILITY_INTERNAL##_osxIntro##_DEP##_osxDep##_MSG(_msg) __AVAILABILITY_INTERNAL##_iosIntro##_DEP##_iosDep##_MSG(_msg)
|
||||
#endif /* # if __is_target_arch... */
|
||||
#endif /* #if __has_builtin(__is_target_variant_environment) */
|
||||
#endif /* #if __has_builtin(__is_target_variant_os) */
|
||||
#endif /* #if __has_builtin(__is_target_environment) */
|
||||
#endif /* #if __has_builtin(__is_target_os) */
|
||||
#endif /* #if __has_builtin(__is_target_vendor) */
|
||||
#endif /* #if __has_builtin(__is_target_arch) */
|
||||
#endif /* #if defined(__has_builtin) */
|
||||
|
||||
#ifndef __OSX_AVAILABLE_STARTING
|
||||
#if defined(__has_attribute) && defined(__has_feature)
|
||||
#if __has_attribute(availability)
|
||||
#define __OSX_AVAILABLE_STARTING(_osx, _ios) __AVAILABILITY_INTERNAL##_osx
|
||||
#define __OSX_AVAILABLE_BUT_DEPRECATED(_osxIntro, _osxDep, _iosIntro, _iosDep) \
|
||||
__AVAILABILITY_INTERNAL##_osxIntro##_DEP##_osxDep
|
||||
#define __OSX_AVAILABLE_BUT_DEPRECATED_MSG(_osxIntro, _osxDep, _iosIntro, _iosDep, _msg) \
|
||||
__AVAILABILITY_INTERNAL##_osxIntro##_DEP##_osxDep##_MSG(_msg)
|
||||
#else
|
||||
#define __OSX_AVAILABLE_STARTING(_osx, _ios)
|
||||
#define __OSX_AVAILABLE_BUT_DEPRECATED(_osxIntro, _osxDep, _iosIntro, _iosDep)
|
||||
#define __OSX_AVAILABLE_BUT_DEPRECATED_MSG(_osxIntro, _osxDep, _iosIntro, _iosDep, _msg)
|
||||
#endif
|
||||
#endif
|
||||
#endif /* __OSX_AVAILABLE_STARTING */
|
||||
|
||||
#else
|
||||
#define __OSX_AVAILABLE_STARTING(_osx, _ios)
|
||||
@ -364,14 +458,24 @@
|
||||
#define __SWIFT_UNAVAILABLE_MSG(_msg)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Macros for defining which versions/platform a given symbol can be used.
|
||||
|
||||
@see http://clang.llvm.org/docs/AttributeReference.html#availability
|
||||
|
||||
* Note that these macros are only compatible with clang compilers that
|
||||
* support the following target selection options:
|
||||
*
|
||||
* -mmacosx-version-min
|
||||
* -miphoneos-version-min
|
||||
* -mwatchos-version-min
|
||||
* -mtvos-version-min
|
||||
*/
|
||||
|
||||
/*
|
||||
#if defined(__has_feature) && defined(__has_attribute)
|
||||
#if __has_attribute(availability)
|
||||
|
||||
/*
|
||||
* API Introductions
|
||||
*
|
||||
* Use to specify the release that a particular API became available.
|
||||
@ -383,11 +487,14 @@
|
||||
* __API_AVAILABLE(macos(10.10))
|
||||
* __API_AVAILABLE(macos(10.9), ios(10.0))
|
||||
* __API_AVAILABLE(macos(10.4), ios(8.0), watchos(2.0), tvos(10.0))
|
||||
* __API_AVAILABLE(driverkit(19.0))
|
||||
*/
|
||||
#define __API_AVAILABLE(...) __API_AVAILABLE_GET_MACRO(__VA_ARGS__,__API_AVAILABLE4, __API_AVAILABLE3, __API_AVAILABLE2, __API_AVAILABLE1)(__VA_ARGS__)
|
||||
#define __API_AVAILABLE(...) __API_AVAILABLE_GET_MACRO(__VA_ARGS__,__API_AVAILABLE7, __API_AVAILABLE6, __API_AVAILABLE5, __API_AVAILABLE4, __API_AVAILABLE3, __API_AVAILABLE2, __API_AVAILABLE1, 0)(__VA_ARGS__)
|
||||
|
||||
#define __API_AVAILABLE_BEGIN(...) _Pragma("clang attribute push") __API_AVAILABLE_BEGIN_GET_MACRO(__VA_ARGS__,__API_AVAILABLE_BEGIN7, __API_AVAILABLE_BEGIN6, __API_AVAILABLE_BEGIN5, __API_AVAILABLE_BEGIN4, __API_AVAILABLE_BEGIN3, __API_AVAILABLE_BEGIN2, __API_AVAILABLE_BEGIN1, 0)(__VA_ARGS__)
|
||||
#define __API_AVAILABLE_END _Pragma("clang attribute pop")
|
||||
|
||||
/*
|
||||
/*
|
||||
* API Deprecations
|
||||
*
|
||||
* Use to specify the release that a particular API became unavailable.
|
||||
@ -403,10 +510,16 @@
|
||||
* __API_DEPRECATED_WITH_REPLACEMENT("-setName:", tvos(10.0, 10.4), ios(9.0, 10.0))
|
||||
* __API_DEPRECATED_WITH_REPLACEMENT("SomeClassName", macos(10.4, 10.6), watchos(2.0, 3.0))
|
||||
*/
|
||||
#define __API_DEPRECATED(...) __API_DEPRECATED_MSG_GET_MACRO(__VA_ARGS__,__API_DEPRECATED_MSG5,__API_DEPRECATED_MSG4,__API_DEPRECATED_MSG3,__API_DEPRECATED_MSG2,__API_DEPRECATED_MSG1)(__VA_ARGS__)
|
||||
#define __API_DEPRECATED_WITH_REPLACEMENT(...) __API_DEPRECATED_REP_GET_MACRO(__VA_ARGS__,__API_DEPRECATED_REP5,__API_DEPRECATED_REP4,__API_DEPRECATED_REP3,__API_DEPRECATED_REP2,__API_DEPRECATED_REP1)(__VA_ARGS__)
|
||||
#define __API_DEPRECATED(...) __API_DEPRECATED_MSG_GET_MACRO(__VA_ARGS__,__API_DEPRECATED_MSG8,__API_DEPRECATED_MSG7,__API_DEPRECATED_MSG6,__API_DEPRECATED_MSG5,__API_DEPRECATED_MSG4,__API_DEPRECATED_MSG3,__API_DEPRECATED_MSG2,__API_DEPRECATED_MSG1, 0)(__VA_ARGS__)
|
||||
#define __API_DEPRECATED_WITH_REPLACEMENT(...) __API_DEPRECATED_REP_GET_MACRO(__VA_ARGS__,__API_DEPRECATED_REP8,__API_DEPRECATED_REP7,__API_DEPRECATED_REP6,__API_DEPRECATED_REP5,__API_DEPRECATED_REP4,__API_DEPRECATED_REP3,__API_DEPRECATED_REP2,__API_DEPRECATED_REP1, 0)(__VA_ARGS__)
|
||||
|
||||
/*
|
||||
#define __API_DEPRECATED_BEGIN(...) _Pragma("clang attribute push") __API_DEPRECATED_BEGIN_MSG_GET_MACRO(__VA_ARGS__,__API_DEPRECATED_BEGIN_MSG8,__API_DEPRECATED_BEGIN_MSG7, __API_DEPRECATED_BEGIN_MSG6, __API_DEPRECATED_BEGIN_MSG5, __API_DEPRECATED_BEGIN_MSG4, __API_DEPRECATED_BEGIN_MSG3, __API_DEPRECATED_BEGIN_MSG2, __API_DEPRECATED_BEGIN_MSG1, 0)(__VA_ARGS__)
|
||||
#define __API_DEPRECATED_END _Pragma("clang attribute pop")
|
||||
|
||||
#define __API_DEPRECATED_WITH_REPLACEMENT_BEGIN(...) _Pragma("clang attribute push") __API_DEPRECATED_BEGIN_REP_GET_MACRO(__VA_ARGS__,__API_DEPRECATED_BEGIN_REP8,__API_DEPRECATED_BEGIN_REP7, __API_DEPRECATED_BEGIN_REP6, __API_DEPRECATED_BEGIN_REP5, __API_DEPRECATED_BEGIN_REP4, __API_DEPRECATED_BEGIN_REP3, __API_DEPRECATED_BEGIN_REP2, __API_DEPRECATED_BEGIN_REP1, 0)(__VA_ARGS__)
|
||||
#define __API_DEPRECATED_WITH_REPLACEMENT_END _Pragma("clang attribute pop")
|
||||
|
||||
/*
|
||||
* API Unavailability
|
||||
* Use to specify that an API is unavailable for a particular platform.
|
||||
*
|
||||
@ -414,6 +527,68 @@
|
||||
* __API_UNAVAILABLE(macos)
|
||||
* __API_UNAVAILABLE(watchos, tvos)
|
||||
*/
|
||||
#define __API_UNAVAILABLE(...) __API_UNAVAILABLE_GET_MACRO(__VA_ARGS__,__API_UNAVAILABLE3,__API_UNAVAILABLE2,__API_UNAVAILABLE1)(__VA_ARGS__)
|
||||
#define __API_UNAVAILABLE(...) __API_UNAVAILABLE_GET_MACRO(__VA_ARGS__,__API_UNAVAILABLE7,__API_UNAVAILABLE6,__API_UNAVAILABLE5,__API_UNAVAILABLE4,__API_UNAVAILABLE3,__API_UNAVAILABLE2,__API_UNAVAILABLE1, 0)(__VA_ARGS__)
|
||||
|
||||
#define __API_UNAVAILABLE_BEGIN(...) _Pragma("clang attribute push") __API_UNAVAILABLE_BEGIN_GET_MACRO(__VA_ARGS__,__API_UNAVAILABLE_BEGIN7,__API_UNAVAILABLE_BEGIN6, __API_UNAVAILABLE_BEGIN5, __API_UNAVAILABLE_BEGIN4, __API_UNAVAILABLE_BEGIN3, __API_UNAVAILABLE_BEGIN2, __API_UNAVAILABLE_BEGIN1, 0)(__VA_ARGS__)
|
||||
#define __API_UNAVAILABLE_END _Pragma("clang attribute pop")
|
||||
#else
|
||||
|
||||
/*
|
||||
* Evaluate to nothing for compilers that don't support availability.
|
||||
*/
|
||||
|
||||
#define __API_AVAILABLE(...)
|
||||
#define __API_AVAILABLE_BEGIN(...)
|
||||
#define __API_AVAILABLE_END
|
||||
#define __API_DEPRECATED(...)
|
||||
#define __API_DEPRECATED_WITH_REPLACEMENT(...)
|
||||
#define __API_DEPRECATED_BEGIN(...)
|
||||
#define __API_DEPRECATED_END
|
||||
#define __API_DEPRECATED_WITH_REPLACEMENT_BEGIN(...)
|
||||
#define __API_DEPRECATED_WITH_REPLACEMENT_END
|
||||
#define __API_UNAVAILABLE(...)
|
||||
#define __API_UNAVAILABLE_BEGIN(...)
|
||||
#define __API_UNAVAILABLE_END
|
||||
#endif /* __has_attribute(availability) */
|
||||
#else
|
||||
|
||||
/*
|
||||
* Evaluate to nothing for compilers that don't support clang language extensions.
|
||||
*/
|
||||
|
||||
#define __API_AVAILABLE(...)
|
||||
#define __API_AVAILABLE_BEGIN(...)
|
||||
#define __API_AVAILABLE_END
|
||||
#define __API_DEPRECATED(...)
|
||||
#define __API_DEPRECATED_WITH_REPLACEMENT(...)
|
||||
#define __API_DEPRECATED_BEGIN(...)
|
||||
#define __API_DEPRECATED_END
|
||||
#define __API_DEPRECATED_WITH_REPLACEMENT_BEGIN(...)
|
||||
#define __API_DEPRECATED_WITH_REPLACEMENT_END
|
||||
#define __API_UNAVAILABLE(...)
|
||||
#define __API_UNAVAILABLE_BEGIN(...)
|
||||
#define __API_UNAVAILABLE_END
|
||||
#endif /* #if defined(__has_feature) && defined(__has_attribute) */
|
||||
|
||||
#if __has_include(<AvailabilityProhibitedInternal.h>)
|
||||
#include <AvailabilityProhibitedInternal.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If SPI decorations have not been defined elsewhere, disable them.
|
||||
*/
|
||||
|
||||
#ifndef __SPI_AVAILABLE
|
||||
#define __SPI_AVAILABLE(...)
|
||||
#endif
|
||||
|
||||
#ifndef __SPI_DEPRECATED
|
||||
#define __SPI_DEPRECATED(...)
|
||||
#endif
|
||||
|
||||
#ifndef __SPI_DEPRECATED_WITH_REPLACEMENT
|
||||
#define __SPI_DEPRECATED_WITH_REPLACEMENT(...)
|
||||
#endif
|
||||
|
||||
#endif /* __AVAILABILITY__ */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -78,10 +78,10 @@
|
||||
#include <sys/_types/_int32_t.h>
|
||||
#include <sys/_types/_int64_t.h>
|
||||
|
||||
typedef unsigned char u_int8_t;
|
||||
typedef unsigned short u_int16_t;
|
||||
typedef unsigned int u_int32_t;
|
||||
typedef unsigned long long u_int64_t;
|
||||
#include <sys/_types/_u_int8_t.h>
|
||||
#include <sys/_types/_u_int16_t.h>
|
||||
#include <sys/_types/_u_int32_t.h>
|
||||
#include <sys/_types/_u_int64_t.h>
|
||||
|
||||
#if __LP64__
|
||||
typedef int64_t register_t;
|
||||
|
150
platform-include/kern/exc_guard.h
Normal file
150
platform-include/kern/exc_guard.h
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 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@
|
||||
*/
|
||||
/*
|
||||
* Mach Operating System
|
||||
* Copyright (c) 1989 Carnegie-Mellon University
|
||||
* Copyright (c) 1988 Carnegie-Mellon University
|
||||
* Copyright (c) 1987 Carnegie-Mellon University
|
||||
* All rights reserved. The CMU software License Agreement specifies
|
||||
* the terms and conditions for use and redistribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* EXC_GUARD related macros, namespace etc.
|
||||
*/
|
||||
|
||||
#ifndef _EXC_GUARD_H_
|
||||
#define _EXC_GUARD_H_
|
||||
|
||||
/*
|
||||
* EXC_GUARD exception code namespace.
|
||||
*
|
||||
* code:
|
||||
* +-------------------+----------------+--------------+
|
||||
* |[63:61] guard type | [60:32] flavor | [31:0] target|
|
||||
* +-------------------+----------------+--------------+
|
||||
*
|
||||
* subcode:
|
||||
* +---------------------------------------------------+
|
||||
* |[63:0] guard identifier |
|
||||
* +---------------------------------------------------+
|
||||
*/
|
||||
|
||||
#define EXC_GUARD_DECODE_GUARD_TYPE(code) \
|
||||
((((uint64_t)(code)) >> 61) & 0x7ull)
|
||||
#define EXC_GUARD_DECODE_GUARD_FLAVOR(code) \
|
||||
((((uint64_t)(code)) >> 32) & 0x1fffffff)
|
||||
#define EXC_GUARD_DECODE_GUARD_TARGET(code) \
|
||||
((uint32_t)(code))
|
||||
|
||||
/* EXC_GUARD types */
|
||||
|
||||
#define GUARD_TYPE_NONE 0x0
|
||||
|
||||
/*
|
||||
* Mach port guards use the exception codes like this:
|
||||
*
|
||||
* code:
|
||||
* +-----------------------------+----------------+-----------------+
|
||||
* |[63:61] GUARD_TYPE_MACH_PORT | [60:32] flavor | [31:0] port name|
|
||||
* +-----------------------------+----------------+-----------------+
|
||||
*
|
||||
* subcode:
|
||||
* +----------------------------------------------------------------+
|
||||
* |[63:0] guard identifier |
|
||||
* +----------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#define GUARD_TYPE_MACH_PORT 0x1 /* guarded mach port */
|
||||
|
||||
/*
|
||||
* File descriptor guards use the exception codes this:
|
||||
*
|
||||
* code:
|
||||
* +-----------------------------+----------------+-----------------+
|
||||
* |[63:61] GUARD_TYPE_FD | [60:32] flavor | [31:0] fd |
|
||||
* +-----------------------------+----------------+-----------------+
|
||||
*
|
||||
* subcode:
|
||||
* +----------------------------------------------------------------+
|
||||
* |[63:0] guard identifier |
|
||||
* +----------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#define GUARD_TYPE_FD 0x2 /* guarded file descriptor */
|
||||
|
||||
/*
|
||||
* User generated guards use the exception codes this:
|
||||
*
|
||||
* code:
|
||||
* +-----------------------------+----------------+-----------------+
|
||||
* |[63:61] GUARD_TYPE_USER | [60:32] unused | [31:0] namespc |
|
||||
* +-----------------------------+----------------+-----------------+
|
||||
*
|
||||
* subcode:
|
||||
* +----------------------------------------------------------------+
|
||||
* |[63:0] reason_code |
|
||||
* +----------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#define GUARD_TYPE_USER 0x3 /* Userland assertions */
|
||||
|
||||
/*
|
||||
* Vnode guards use the exception codes like this:
|
||||
*
|
||||
* code:
|
||||
* +-----------------------------+----------------+-----------------+
|
||||
* |[63:61] GUARD_TYPE_VN | [60:32] flavor | [31:0] pid |
|
||||
* +-----------------------------+----------------+-----------------+
|
||||
*
|
||||
* subcode:
|
||||
* +----------------------------------------------------------------+
|
||||
* |[63:0] guard identifier |
|
||||
* +----------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#define GUARD_TYPE_VN 0x4 /* guarded vnode */
|
||||
|
||||
/*
|
||||
* VM guards use the exception codes like this:
|
||||
*
|
||||
* code:
|
||||
* +-------------------------------+----------------+-----------------+
|
||||
* |[63:61] GUARD_TYPE_VIRT_MEMORY | [60:32] flavor | [31:0] unused |
|
||||
* +-------------------------------+----------------+-----------------+
|
||||
*
|
||||
* subcode:
|
||||
* +----------------------------------------------------------------+
|
||||
* |[63:0] offset |
|
||||
* +----------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#define GUARD_TYPE_VIRT_MEMORY 0x5 /* VM operation violating guard */
|
||||
|
||||
|
||||
#endif /* _EXC_GUARD_H_ */
|
214
platform-include/kern/exc_resource.h
Normal file
214
platform-include/kern/exc_resource.h
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2012 Apple Computer, 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@
|
||||
*/
|
||||
/*
|
||||
* Mach Operating System
|
||||
* Copyright (c) 1989 Carnegie-Mellon University
|
||||
* Copyright (c) 1988 Carnegie-Mellon University
|
||||
* Copyright (c) 1987 Carnegie-Mellon University
|
||||
* All rights reserved. The CMU software License Agreement specifies
|
||||
* the terms and conditions for use and redistribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* EXC_RESOURCE related macros, namespace etc.
|
||||
*/
|
||||
|
||||
#ifndef _EXC_RESOURCE_H_
|
||||
#define _EXC_RESOURCE_H_
|
||||
|
||||
/*
|
||||
* Generic exception code format:
|
||||
*
|
||||
* code:
|
||||
* +----------------------------------------------------------+
|
||||
* |[63:61] type | [60:58] flavor | [57:0] type-specific data |
|
||||
* +----------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
/* EXC_RESOURCE type and flavor decoding routines */
|
||||
#define EXC_RESOURCE_DECODE_RESOURCE_TYPE(code) \
|
||||
(((code) >> 61) & 0x7ULL)
|
||||
#define EXC_RESOURCE_DECODE_FLAVOR(code) \
|
||||
(((code) >> 58) & 0x7ULL)
|
||||
|
||||
/* EXC_RESOURCE Types */
|
||||
#define RESOURCE_TYPE_CPU 1
|
||||
#define RESOURCE_TYPE_WAKEUPS 2
|
||||
#define RESOURCE_TYPE_MEMORY 3
|
||||
#define RESOURCE_TYPE_IO 4
|
||||
#define RESOURCE_TYPE_THREADS 5
|
||||
|
||||
/* RESOURCE_TYPE_CPU flavors */
|
||||
#define FLAVOR_CPU_MONITOR 1
|
||||
#define FLAVOR_CPU_MONITOR_FATAL 2
|
||||
|
||||
/*
|
||||
* RESOURCE_TYPE_CPU exception code & subcode.
|
||||
*
|
||||
* This is sent by the kernel when the CPU usage monitor
|
||||
* is tripped. [See proc_set_cpumon_params()]
|
||||
*
|
||||
* code:
|
||||
* +-----------------------------------------------+
|
||||
* |[63:61] RESOURCE |[60:58] FLAVOR_CPU_ |[57:32] |
|
||||
* |_TYPE_CPU |MONITOR[_FATAL] |Unused |
|
||||
* +-----------------------------------------------+
|
||||
* |[31:7] Interval (sec) | [6:0] CPU limit (%)|
|
||||
* +-----------------------------------------------+
|
||||
*
|
||||
* subcode:
|
||||
* +-----------------------------------------------+
|
||||
* | | [6:0] % of CPU |
|
||||
* | | actually consumed |
|
||||
* +-----------------------------------------------+
|
||||
*
|
||||
*/
|
||||
|
||||
/* RESOURCE_TYPE_CPU decoding macros */
|
||||
#define EXC_RESOURCE_CPUMONITOR_DECODE_INTERVAL(code) \
|
||||
(((code) >> 7) & 0x1FFFFFFULL)
|
||||
#define EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE(code) \
|
||||
((code) & 0x7FULL)
|
||||
#define EXC_RESOURCE_CPUMONITOR_DECODE_PERCENTAGE_OBSERVED(subcode) \
|
||||
((subcode) & 0x7FULL)
|
||||
|
||||
|
||||
/* RESOURCE_TYPE_WAKEUPS flavors */
|
||||
#define FLAVOR_WAKEUPS_MONITOR 1
|
||||
|
||||
/*
|
||||
* RESOURCE_TYPE_WAKEUPS exception code & subcode.
|
||||
*
|
||||
* This is sent by the kernel when the platform idle
|
||||
* wakeups monitor is tripped.
|
||||
* [See proc_set_wakeupsmon_params()]
|
||||
*
|
||||
* code:
|
||||
* +-----------------------------------------------+
|
||||
* |[63:61] RESOURCE |[60:58] FLAVOR_ |[57:32] |
|
||||
* |_TYPE_WAKEUPS |WAKEUPS_MONITOR |Unused |
|
||||
* +-----------------------------------------------+
|
||||
* | [31:20] Observation | [19:0] # of wakeups |
|
||||
* | interval (sec) | permitted (per sec) |
|
||||
* +-----------------------------------------------+
|
||||
*
|
||||
* subcode:
|
||||
* +-----------------------------------------------+
|
||||
* | | [19:0] # of wakeups |
|
||||
* | | observed (per sec) |
|
||||
* +-----------------------------------------------+
|
||||
*
|
||||
*/
|
||||
|
||||
#define EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_PERMITTED(code) \
|
||||
((code) & 0xFFFULL)
|
||||
#define EXC_RESOURCE_CPUMONITOR_DECODE_OBSERVATION_INTERVAL(code) \
|
||||
(((code) >> 20) & 0xFFFFFULL)
|
||||
#define EXC_RESOURCE_CPUMONITOR_DECODE_WAKEUPS_OBSERVED(subcode) \
|
||||
((subcode) & 0xFFFFFULL)
|
||||
|
||||
/* RESOURCE_TYPE_MEMORY flavors */
|
||||
#define FLAVOR_HIGH_WATERMARK 1
|
||||
|
||||
/*
|
||||
* RESOURCE_TYPE_MEMORY / FLAVOR_HIGH_WATERMARK
|
||||
* exception code & subcode.
|
||||
*
|
||||
* This is sent by the kernel when a task crosses its high
|
||||
* watermark memory limit.
|
||||
*
|
||||
* code:
|
||||
* +------------------------------------------------+
|
||||
* |[63:61] RESOURCE |[60:58] FLAVOR_HIGH_ |[57:32] |
|
||||
* |_TYPE_MEMORY |WATERMARK |Unused |
|
||||
* +------------------------------------------------+
|
||||
* | | [12:0] HWM limit (MB)|
|
||||
* +------------------------------------------------+
|
||||
*
|
||||
* subcode:
|
||||
* +------------------------------------------------+
|
||||
* | unused |
|
||||
* +------------------------------------------------+
|
||||
*
|
||||
*/
|
||||
|
||||
#define EXC_RESOURCE_HWM_DECODE_LIMIT(code) \
|
||||
((code) & 0x1FFFULL)
|
||||
|
||||
/* RESOURCE_TYPE_IO flavors */
|
||||
#define FLAVOR_IO_PHYSICAL_WRITES 1
|
||||
#define FLAVOR_IO_LOGICAL_WRITES 2
|
||||
|
||||
/*
|
||||
* RESOURCE_TYPE_IO exception code & subcode.
|
||||
*
|
||||
* This is sent by the kernel when a task crosses its
|
||||
* I/O limits.
|
||||
*
|
||||
* code:
|
||||
* +-----------------------------------------------+
|
||||
* |[63:61] RESOURCE |[60:58] FLAVOR_IO_ |[57:32] |
|
||||
* |_TYPE_IO |PHYSICAL/LOGICAL |Unused |
|
||||
* +-----------------------------------------------+
|
||||
* |[31:15] Interval (sec) | [14:0] Limit (MB) |
|
||||
* +-----------------------------------------------+
|
||||
*
|
||||
* subcode:
|
||||
* +-----------------------------------------------+
|
||||
* | | [14:0] I/O Count |
|
||||
* | | (in MB) |
|
||||
* +-----------------------------------------------+
|
||||
*
|
||||
*/
|
||||
|
||||
/* RESOURCE_TYPE_IO decoding macros */
|
||||
#define EXC_RESOURCE_IO_DECODE_INTERVAL(code) \
|
||||
(((code) >> 15) & 0x1FFFFULL)
|
||||
#define EXC_RESOURCE_IO_DECODE_LIMIT(code) \
|
||||
((code) & 0x7FFFULL)
|
||||
#define EXC_RESOURCE_IO_OBSERVED(subcode) \
|
||||
((subcode) & 0x7FFFULL)
|
||||
|
||||
|
||||
/*
|
||||
* RESOURCE_TYPE_THREADS exception code & subcode
|
||||
*
|
||||
* This is sent by the kernel when a task crosses its
|
||||
* thread limit.
|
||||
*/
|
||||
|
||||
#define EXC_RESOURCE_THREADS_DECODE_THREADS(code) \
|
||||
((code) & 0x7FFFULL)
|
||||
|
||||
/* RESOURCE_TYPE_THREADS flavors */
|
||||
#define FLAVOR_THREADS_HIGH_WATERMARK 1
|
||||
|
||||
|
||||
|
||||
#endif /* _EXC_RESOURCE_H_ */
|
1268
platform-include/kern/kcdata.h
Normal file
1268
platform-include/kern/kcdata.h
Normal file
File diff suppressed because it is too large
Load Diff
58
platform-include/kern/kern_cdata.h
Normal file
58
platform-include/kern/kern_cdata.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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@
|
||||
*/
|
||||
|
||||
#ifndef _KERN_CDATA_H_
|
||||
#define _KERN_CDATA_H_
|
||||
|
||||
#include <kern/kcdata.h>
|
||||
#include <mach/mach_types.h>
|
||||
|
||||
/*
|
||||
* Do not use these macros!
|
||||
*
|
||||
* Instead, you should use kcdata_iter_* functions defined in kcdata.h. These
|
||||
* macoros have no idea where the kcdata buffer ends, so they are all unsafe.
|
||||
*/
|
||||
#define KCDATA_ITEM_HEADER_SIZE (sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint64_t))
|
||||
#define KCDATA_ITEM_ITER(item) kcdata_iter_unsafe((void*)(item))
|
||||
#define KCDATA_ITEM_TYPE(item) kcdata_iter_type(KCDATA_ITEM_ITER(item))
|
||||
#define KCDATA_ITEM_SIZE(item) kcdata_iter_size(KCDATA_ITEM_ITER(item))
|
||||
#define KCDATA_ITEM_FLAGS(item) kcdata_iter_flags(KCDATA_ITEM_ITER(item))
|
||||
#define KCDATA_ITEM_ARRAY_GET_EL_TYPE(item) kcdata_iter_array_elem_type(KCDATA_ITEM_ITER(item))
|
||||
#define KCDATA_ITEM_ARRAY_GET_EL_COUNT(item) kcdata_iter_array_elem_count(KCDATA_ITEM_ITER(item))
|
||||
#define KCDATA_ITEM_ARRAY_GET_EL_SIZE(item) kcdata_iter_array_elem_size(KCDATA_ITEM_ITER(item))
|
||||
#define KCDATA_CONTAINER_ID(item) kcdata_iter_container_id(KCDATA_ITEM_ITER(item))
|
||||
#define KCDATA_ITEM_NEXT_HEADER(itemx) (kcdata_iter_next(KCDATA_ITEM_ITER(itemx)).item)
|
||||
#define KCDATA_ITEM_FOREACH(head) for (; KCDATA_ITEM_TYPE(head) != KCDATA_TYPE_BUFFER_END; (head) = KCDATA_ITEM_NEXT_HEADER(head))
|
||||
#define KCDATA_ITEM_DATA_PTR(item) kcdata_iter_payload(KCDATA_ITEM_ITER(item))
|
||||
#define KCDATA_ITEM_FIND_TYPE(itemx, type) (kcdata_iter_find_type(KCDATA_ITEM_ITER(itemx), type).item)
|
||||
#define kcdata_get_container_type(buffer) kcdata_iter_container_type(KCDATA_ITEM_ITER(buffer))
|
||||
#define kcdata_get_data_with_desc(buf, desc, data) kcdata_iter_get_data_with_desc(KCDATA_ITEM_ITER(buf),desc,data,NULL)
|
||||
/* Do not use these macros! */
|
||||
|
||||
#endif /* _KERN_CDATA_H_ */
|
@ -72,6 +72,36 @@ extern const NXArchInfo *NXGetArchInfoFromName(const char *name);
|
||||
extern const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype,
|
||||
cpu_subtype_t cpusubtype);
|
||||
|
||||
/* The above interfaces that return pointers to NXArchInfo structs in normal
|
||||
* cases returns a pointer from the array returned in NXGetAllArchInfos().
|
||||
* In some cases when the cputype is CPU_TYPE_I386 or CPU_TYPE_POWERPC it will
|
||||
* retun malloc(3)'ed NXArchInfo struct which contains a string in the
|
||||
* description field also a malloc(3)'ed pointer. To allow programs not to
|
||||
* leak memory they can call NXFreeArchInfo() on pointers returned from the
|
||||
* above interfaces. Since this is a new API on older systems can use the
|
||||
* code below. Going forward the above interfaces will only return pointers
|
||||
* from the array returned in NXGetAllArchInfos().
|
||||
*/
|
||||
extern void NXFreeArchInfo(const NXArchInfo *x);
|
||||
|
||||
/* The code that can be used for NXFreeArchInfo() when it is not available is:
|
||||
*
|
||||
* static void NXFreeArchInfo(
|
||||
* const NXArchInfo *x)
|
||||
* {
|
||||
* const NXArchInfo *p;
|
||||
*
|
||||
* p = NXGetAllArchInfos();
|
||||
* while(p->name != NULL){
|
||||
* if(x == p)
|
||||
* return;
|
||||
* p++;
|
||||
* }
|
||||
* free((char *)x->description);
|
||||
* free((NXArchInfo *)x);
|
||||
* }
|
||||
*/
|
||||
|
||||
/* NXFindBestFatArch() is passed a cputype and cpusubtype and a set of
|
||||
* fat_arch structs and selects the best one that matches (if any) and returns
|
||||
* a pointer to that fat_arch struct (or NULL). The fat_arch structs must be
|
||||
@ -86,6 +116,21 @@ extern struct fat_arch *NXFindBestFatArch(cpu_type_t cputype,
|
||||
struct fat_arch *fat_archs,
|
||||
uint32_t nfat_archs);
|
||||
|
||||
/* NXFindBestFatArch_64() is passed a cputype and cpusubtype and a set of
|
||||
* fat_arch_64 structs and selects the best one that matches (if any) and
|
||||
* returns a pointer to that fat_arch_64 struct (or NULL). The fat_arch_64
|
||||
* structs must be in the host byte order and correct such that the fat_archs64
|
||||
* really points to enough memory for nfat_arch structs. It is possible that
|
||||
* this routine could fail if new cputypes or cpusubtypes are added and an old
|
||||
* version of this routine is used. But if there is an exact match between the
|
||||
* cputype and cpusubtype and one of the fat_arch_64 structs this routine will
|
||||
* always succeed.
|
||||
*/
|
||||
extern struct fat_arch_64 *NXFindBestFatArch_64(cpu_type_t cputype,
|
||||
cpu_subtype_t cpusubtype,
|
||||
struct fat_arch_64 *fat_archs64,
|
||||
uint32_t nfat_archs);
|
||||
|
||||
/* NXCombineCpuSubtypes() returns the resulting cpusubtype when combining two
|
||||
* different cpusubtypes for the specified cputype. If the two cpusubtypes
|
||||
* can't be combined (the specific subtypes are mutually exclusive) -1 is
|
||||
|
@ -35,6 +35,12 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __DRIVERKIT_19_0
|
||||
#define DYLD_DRIVERKIT_UNAVAILABLE __API_UNAVAILABLE(driverkit)
|
||||
#else
|
||||
#define DYLD_DRIVERKIT_UNAVAILABLE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following functions allow you to iterate through all loaded images.
|
||||
* This is not a thread safe operation. Another thread can add or remove
|
||||
@ -93,8 +99,18 @@ extern int _NSGetExecutablePath(char* buf, uint32_t* bufsize) __
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Registers a function to be called when the current thread terminates.
|
||||
* Called by c++ compiler to implement destructors on thread_local object variables.
|
||||
*/
|
||||
extern void _tlv_atexit(void (*termFunc)(void* objAddr), void* objAddr) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0);
|
||||
|
||||
|
||||
/*
|
||||
* Never called. On-disk thread local variables contain a pointer to this. Once
|
||||
* the thread local is prepared, the pointer changes to a real handler such as tlv_get_addr.
|
||||
*/
|
||||
extern void _tlv_bootstrap(void) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) DYLD_DRIVERKIT_UNAVAILABLE ;
|
||||
|
||||
/*
|
||||
* The following dyld API's are deprecated as of Mac OS X 10.5. They are either
|
||||
@ -134,24 +150,25 @@ typedef enum {
|
||||
|
||||
typedef struct __NSObjectFileImage* NSObjectFileImage;
|
||||
|
||||
/* NSObjectFileImage can only be used with MH_BUNDLE files */
|
||||
extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName, NSObjectFileImage *objectFileImage) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void *address, size_t size, NSObjectFileImage *objectFileImage) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool NSDestroyObjectFileImage(NSObjectFileImage objectFileImage) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
|
||||
extern uint32_t NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern const char* NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern uint32_t NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern const char* NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal, bool *tentative_definition) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage objectFileImage, const char* symbolName) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
|
||||
extern void* NSGetSectionDataInObjectFileImage(NSObjectFileImage objectFileImage, const char* segmentName, const char* sectionName, size_t *size) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool NSHasModInitObjectFileImage(NSObjectFileImage objectFileImage) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
|
||||
/* NSObjectFileImage can only be used with MH_BUNDLE files */
|
||||
extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName, NSObjectFileImage *objectFileImage) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "dlopen()");
|
||||
extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void *address, size_t size, NSObjectFileImage *objectFileImage) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "");
|
||||
extern bool NSDestroyObjectFileImage(NSObjectFileImage objectFileImage) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "dlclose()");
|
||||
|
||||
extern uint32_t NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "");
|
||||
extern const char* NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "");
|
||||
extern uint32_t NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "");
|
||||
extern const char* NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal, bool *tentative_definition) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "");
|
||||
extern bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage objectFileImage, const char* symbolName) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.4, "dlsym()");
|
||||
extern void* NSGetSectionDataInObjectFileImage(NSObjectFileImage objectFileImage, const char* segmentName, const char* sectionName, size_t *size) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "getsectiondata()");
|
||||
|
||||
typedef struct __NSModule* NSModule;
|
||||
extern const char* NSNameOfModule(NSModule m) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern const char* NSLibraryNameForModule(NSModule m) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern const char* NSNameOfModule(NSModule m) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "");
|
||||
extern const char* NSLibraryNameForModule(NSModule m) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "");
|
||||
|
||||
extern NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName, uint32_t options) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName, uint32_t options) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "dlopen()");
|
||||
#define NSLINKMODULE_OPTION_NONE 0x0
|
||||
#define NSLINKMODULE_OPTION_BINDNOW 0x1
|
||||
#define NSLINKMODULE_OPTION_PRIVATE 0x2
|
||||
@ -159,27 +176,27 @@ extern NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* modu
|
||||
#define NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES 0x8
|
||||
#define NSLINKMODULE_OPTION_TRAILING_PHYS_NAME 0x10
|
||||
|
||||
extern bool NSUnLinkModule(NSModule module, uint32_t options) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool NSUnLinkModule(NSModule module, uint32_t options) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "");
|
||||
#define NSUNLINKMODULE_OPTION_NONE 0x0
|
||||
#define NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED 0x1
|
||||
#define NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES 0x2
|
||||
|
||||
/* symbol API */
|
||||
typedef struct __NSSymbol* NSSymbol;
|
||||
extern bool NSIsSymbolNameDefined(const char* symbolName) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool NSIsSymbolNameDefinedInImage(const struct mach_header* image, const char* symbolName) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
|
||||
extern NSSymbol NSLookupAndBindSymbol(const char* symbolName) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
|
||||
extern NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
|
||||
extern NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern NSSymbol NSLookupSymbolInImage(const struct mach_header* image, const char* symbolName, uint32_t options) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool NSIsSymbolNameDefined(const char* symbolName) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.4, "dlsym()");
|
||||
extern bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.4, "dlsym()");
|
||||
extern bool NSIsSymbolNameDefinedInImage(const struct mach_header* image, const char* symbolName) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.4, "dlsym()");
|
||||
extern NSSymbol NSLookupAndBindSymbol(const char* symbolName) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.4, "dlsym()");
|
||||
extern NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.4, "dlsym()");
|
||||
extern NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "dlsym()");
|
||||
extern NSSymbol NSLookupSymbolInImage(const struct mach_header* image, const char* symbolName, uint32_t options) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "dlsym()");
|
||||
#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
|
||||
#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 0x1
|
||||
#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY 0x2
|
||||
#define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
|
||||
extern const char* NSNameOfSymbol(NSSymbol symbol) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern void * NSAddressOfSymbol(NSSymbol symbol) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern NSModule NSModuleForSymbol(NSSymbol symbol) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern const char* NSNameOfSymbol(NSSymbol symbol) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "");
|
||||
extern void * NSAddressOfSymbol(NSSymbol symbol) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "dlsym()");
|
||||
extern NSModule NSModuleForSymbol(NSSymbol symbol) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "dladdr()");
|
||||
|
||||
/* error handling API */
|
||||
typedef enum {
|
||||
@ -207,7 +224,7 @@ typedef enum {
|
||||
NSOtherErrorInvalidArgs
|
||||
} NSOtherErrorNumbers;
|
||||
|
||||
extern void NSLinkEditError(NSLinkEditErrors *c, int *errorNumber, const char** fileName, const char** errorString) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern void NSLinkEditError(NSLinkEditErrors *c, int *errorNumber, const char** fileName, const char** errorString) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "dlerror()");
|
||||
|
||||
typedef struct {
|
||||
void (*undefined)(const char* symbolName);
|
||||
@ -216,28 +233,27 @@ typedef struct {
|
||||
const char* fileName, const char* errorString);
|
||||
} NSLinkEditErrorHandlers;
|
||||
|
||||
extern void NSInstallLinkEditErrorHandlers(const NSLinkEditErrorHandlers *handlers) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern void NSInstallLinkEditErrorHandlers(const NSLinkEditErrorHandlers *handlers) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "");
|
||||
|
||||
extern bool NSAddLibrary(const char* pathName) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool NSAddLibraryWithSearching(const char* pathName) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
|
||||
extern const struct mach_header* NSAddImage(const char* image_name, uint32_t options) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool NSAddLibrary(const char* pathName) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.4, "dlopen()");
|
||||
extern bool NSAddLibraryWithSearching(const char* pathName) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.4, "dlopen()");
|
||||
extern const struct mach_header* NSAddImage(const char* image_name, uint32_t options) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "dlopen()");
|
||||
#define NSADDIMAGE_OPTION_NONE 0x0
|
||||
#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
|
||||
#define NSADDIMAGE_OPTION_WITH_SEARCHING 0x2
|
||||
#define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
|
||||
#define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8
|
||||
|
||||
extern bool _dyld_present(void) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool _dyld_launched_prebound(void) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool _dyld_all_twolevel_modules_prebound(void) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern void _dyld_bind_objc_module(const void* objc_module) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool _dyld_bind_fully_image_containing_address(const void* address) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool _dyld_image_containing_address(const void* address) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern void _dyld_lookup_and_bind(const char* symbol_name, void **address, NSModule* module) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
|
||||
extern void _dyld_lookup_and_bind_with_hint(const char* symbol_name, const char* library_name_hint, void** address, NSModule* module) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
|
||||
extern void _dyld_lookup_and_bind_fully(const char* symbol_name, void** address, NSModule* module) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern bool _dyld_present(void) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "always true");
|
||||
extern bool _dyld_launched_prebound(void) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "moot");
|
||||
extern bool _dyld_all_twolevel_modules_prebound(void) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.3, 10.5, "moot");
|
||||
extern bool _dyld_bind_fully_image_containing_address(const void* address) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "dlopen(RTLD_NOW)");
|
||||
extern bool _dyld_image_containing_address(const void* address) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.3, 10.5, "dladdr()");
|
||||
extern void _dyld_lookup_and_bind(const char* symbol_name, void **address, NSModule* module) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.4, "dlsym()");
|
||||
extern void _dyld_lookup_and_bind_with_hint(const char* symbol_name, const char* library_name_hint, void** address, NSModule* module) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.4, "dlsym()");
|
||||
extern void _dyld_lookup_and_bind_fully(const char* symbol_name, void** address, NSModule* module) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.1, 10.5, "dlsym()");
|
||||
|
||||
extern const struct mach_header* _dyld_get_image_header_containing_address(const void* address) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
|
||||
extern const struct mach_header* _dyld_get_image_header_containing_address(const void* address) __API_UNAVAILABLE(ios, tvos, watchos) DYLD_DRIVERKIT_UNAVAILABLE __OSX_DEPRECATED(10.3, 10.5, "dladdr()");
|
||||
|
||||
|
||||
#if __cplusplus
|
||||
|
@ -25,10 +25,11 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#ifndef MLDR_BUILD
|
||||
#include <mach/mach.h>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#if defined(__cplusplus) && (BUILDING_LIBDYLD || BUILDING_DYLD)
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -36,6 +37,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Beginning in Mac OS X 10.4, this is how gdb discovers which mach-o images are loaded in a process.
|
||||
*
|
||||
@ -77,12 +79,10 @@ struct dyld_image_info {
|
||||
/* then file has been modified since dyld loaded it */
|
||||
};
|
||||
|
||||
#ifndef MLDR_BUILD
|
||||
struct dyld_uuid_info {
|
||||
const struct mach_header* imageLoadAddress; /* base address image is mapped into */
|
||||
uuid_t imageUUID; /* UUID of image */
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef void (*dyld_image_notifier)(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]);
|
||||
|
||||
@ -94,11 +94,17 @@ enum { dyld_error_kind_none=0,
|
||||
dyld_error_kind_symbol_missing=4
|
||||
};
|
||||
|
||||
/* internal limit */
|
||||
#define DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT 8
|
||||
|
||||
struct dyld_all_image_infos {
|
||||
uint32_t version; /* 1 in Mac OS X 10.4 and 10.5 */
|
||||
uint32_t infoArrayCount;
|
||||
#if defined(__cplusplus) && (BUILDING_LIBDYLD || BUILDING_DYLD)
|
||||
std::atomic<const struct dyld_image_info*> infoArray;
|
||||
#else
|
||||
const struct dyld_image_info* infoArray;
|
||||
#endif
|
||||
dyld_image_notifier notification;
|
||||
bool processDetachedFromSharedRegion;
|
||||
/* the following fields are only in version 2 (Mac OS X 10.6, iPhoneOS 2.0) and later */
|
||||
@ -130,11 +136,27 @@ struct dyld_all_image_infos {
|
||||
uintptr_t sharedCacheSlide;
|
||||
/* the following field is only in version 13 (Mac OS X 10.9, iOS 7.0) and later */
|
||||
uint8_t sharedCacheUUID[16];
|
||||
/* the following field is only in version 14 (Mac OS X 10.9, iOS 7.0) and later */
|
||||
uintptr_t reserved[16];
|
||||
/* the following field is only in version 15 (macOS 10.12, iOS 10.0) and later */
|
||||
uintptr_t sharedCacheBaseAddress;
|
||||
#if defined(__cplusplus) && (BUILDING_LIBDYLD || BUILDING_DYLD)
|
||||
// We want this to be atomic in libdyld so that we can see updates when we map it shared
|
||||
std::atomic<uint64_t> infoArrayChangeTimestamp;
|
||||
#else
|
||||
uint64_t infoArrayChangeTimestamp;
|
||||
#endif
|
||||
const char* dyldPath;
|
||||
mach_port_t notifyPorts[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT];
|
||||
#if __LP64__
|
||||
uintptr_t reserved[13-(DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT/2)];
|
||||
#else
|
||||
uintptr_t reserved[13-DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT];
|
||||
#endif
|
||||
/* the following field is only in version 16 (macOS 10.13, iOS 11.0) and later */
|
||||
uintptr_t compact_dyld_image_info_addr;
|
||||
size_t compact_dyld_image_info_size;
|
||||
uint32_t platform; // FIXME: really a dyld_platform_t, but those aren't exposed here.
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Beginning in Mac OS X 10.5, this is how gdb discovers where the shared cache is in a process.
|
||||
* Images that are in the shared cache have their segments rearranged, so when using imageFilePath
|
||||
@ -153,7 +175,7 @@ struct dyld_shared_cache_ranges {
|
||||
uintptr_t length;
|
||||
} ranges[4]; /* max regions */
|
||||
};
|
||||
extern struct dyld_shared_cache_ranges dyld_shared_cache_ranges;
|
||||
extern struct dyld_shared_cache_ranges dyld_shared_cache_ranges __attribute__((visibility("hidden")));
|
||||
|
||||
|
||||
|
||||
|
@ -43,8 +43,13 @@
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef __APPLE__
|
||||
typedef int cpu_type_t;
|
||||
typedef int cpu_subtype_t;
|
||||
#else
|
||||
#include <mach/machine.h>
|
||||
#include <architecture/byte_order.h>
|
||||
#endif
|
||||
|
||||
#define FAT_MAGIC 0xcafebabe
|
||||
#define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */
|
||||
|
238
platform-include/mach-o/fixup-chains.h
Normal file
238
platform-include/mach-o/fixup-chains.h
Normal file
@ -0,0 +1,238 @@
|
||||
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
|
||||
*
|
||||
* Copyright (c) 2018 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#ifndef __MACH_O_FIXUP_CHAINS__
|
||||
#define __MACH_O_FIXUP_CHAINS__
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
//#define LC_DYLD_EXPORTS_TRIE 0x80000033 // used with linkedit_data_command
|
||||
//#define LC_DYLD_CHAINED_FIXUPS 0x80000034 // used with linkedit_data_command, payload is dyld_chained_fixups_header
|
||||
|
||||
|
||||
// header of the LC_DYLD_CHAINED_FIXUPS payload
|
||||
struct dyld_chained_fixups_header
|
||||
{
|
||||
uint32_t fixups_version; // 0
|
||||
uint32_t starts_offset; // offset of dyld_chained_starts_in_image in chain_data
|
||||
uint32_t imports_offset; // offset of imports table in chain_data
|
||||
uint32_t symbols_offset; // offset of symbol strings in chain_data
|
||||
uint32_t imports_count; // number of imported symbol names
|
||||
uint32_t imports_format; // DYLD_CHAINED_IMPORT*
|
||||
uint32_t symbols_format; // 0 => uncompressed, 1 => zlib compressed
|
||||
};
|
||||
|
||||
// This struct is embedded in LC_DYLD_CHAINED_FIXUPS payload
|
||||
struct dyld_chained_starts_in_image
|
||||
{
|
||||
uint32_t seg_count;
|
||||
uint32_t seg_info_offset[1]; // each entry is offset into this struct for that segment
|
||||
// followed by pool of dyld_chain_starts_in_segment data
|
||||
};
|
||||
|
||||
// This struct is embedded in dyld_chain_starts_in_image
|
||||
// and passed down to the kernel for page-in linking
|
||||
struct dyld_chained_starts_in_segment
|
||||
{
|
||||
uint32_t size; // size of this (amount kernel needs to copy)
|
||||
uint16_t page_size; // 0x1000 or 0x4000
|
||||
uint16_t pointer_format; // DYLD_CHAINED_PTR_*
|
||||
uint64_t segment_offset; // offset in memory to start of segment
|
||||
uint32_t max_valid_pointer; // for 32-bit OS, any value beyond this is not a pointer
|
||||
uint16_t page_count; // how many pages are in array
|
||||
uint16_t page_start[1]; // each entry is offset in each page of first element in chain
|
||||
// or DYLD_CHAINED_PTR_START_NONE if no fixups on page
|
||||
// uint16_t chain_starts[1]; // some 32-bit formats may require multiple starts per page.
|
||||
// for those, if high bit is set in page_starts[], then it
|
||||
// is index into chain_starts[] which is a list of starts
|
||||
// the last of which has the high bit set
|
||||
};
|
||||
|
||||
enum {
|
||||
DYLD_CHAINED_PTR_START_NONE = 0xFFFF, // used in page_start[] to denote a page with no fixups
|
||||
DYLD_CHAINED_PTR_START_MULTI = 0x8000, // used in page_start[] to denote a page which has multiple starts
|
||||
DYLD_CHAINED_PTR_START_LAST = 0x8000, // used in chain_starts[] to denote last start in list for page
|
||||
};
|
||||
|
||||
// This struct is embedded in __TEXT,__chain_starts section in firmware
|
||||
struct dyld_chained_starts_offsets
|
||||
{
|
||||
uint32_t pointer_format; // DYLD_CHAINED_PTR_32_FIRMWARE
|
||||
uint32_t starts_count; // number of starts in array
|
||||
uint32_t chain_starts[1]; // array chain start offsets
|
||||
};
|
||||
|
||||
|
||||
// values for dyld_chained_starts_in_segment.pointer_format
|
||||
enum {
|
||||
DYLD_CHAINED_PTR_ARM64E = 1,
|
||||
DYLD_CHAINED_PTR_64 = 2,
|
||||
DYLD_CHAINED_PTR_32 = 3,
|
||||
DYLD_CHAINED_PTR_32_CACHE = 4,
|
||||
DYLD_CHAINED_PTR_32_FIRMWARE = 5,
|
||||
};
|
||||
|
||||
|
||||
// DYLD_CHAINED_PTR_ARM64E
|
||||
struct dyld_chained_ptr_arm64e_rebase
|
||||
{
|
||||
uint64_t target : 43, // vmaddr
|
||||
high8 : 8,
|
||||
next : 11, // 8-byte stide
|
||||
bind : 1, // == 0
|
||||
auth : 1; // == 0
|
||||
};
|
||||
|
||||
// DYLD_CHAINED_PTR_ARM64E
|
||||
struct dyld_chained_ptr_arm64e_bind
|
||||
{
|
||||
uint64_t ordinal : 16,
|
||||
zero : 16,
|
||||
addend : 19,
|
||||
next : 11, // 8-byte stide
|
||||
bind : 1, // == 1
|
||||
auth : 1; // == 0
|
||||
};
|
||||
|
||||
// DYLD_CHAINED_PTR_ARM64E
|
||||
struct dyld_chained_ptr_arm64e_auth_rebase
|
||||
{
|
||||
uint64_t target : 32, // runtimeOffset
|
||||
diversity : 16,
|
||||
addrDiv : 1,
|
||||
key : 2,
|
||||
next : 11, // 8-byte stide
|
||||
bind : 1, // == 0
|
||||
auth : 1; // == 1
|
||||
};
|
||||
|
||||
// DYLD_CHAINED_PTR_ARM64E
|
||||
struct dyld_chained_ptr_arm64e_auth_bind
|
||||
{
|
||||
uint64_t ordinal : 16,
|
||||
zero : 16,
|
||||
diversity : 16,
|
||||
addrDiv : 1,
|
||||
key : 2,
|
||||
next : 11, // 8-byte stide
|
||||
bind : 1, // == 1
|
||||
auth : 1; // == 1
|
||||
};
|
||||
|
||||
// DYLD_CHAINED_PTR_64
|
||||
struct dyld_chained_ptr_64_rebase
|
||||
{
|
||||
uint64_t target : 36, // vmaddr, 64GB max image size
|
||||
high8 : 8, // top 8 bits set to this after slide added
|
||||
reserved : 7, // all zeros
|
||||
next : 12, // 4-byte stride
|
||||
bind : 1; // == 0
|
||||
};
|
||||
|
||||
// DYLD_CHAINED_PTR_64
|
||||
struct dyld_chained_ptr_64_bind
|
||||
{
|
||||
uint64_t ordinal : 24,
|
||||
addend : 8, // 0 thru 255
|
||||
reserved : 19, // all zeros
|
||||
next : 12, // 4-byte stride
|
||||
bind : 1; // == 1
|
||||
};
|
||||
|
||||
// DYLD_CHAINED_PTR_32
|
||||
// Note: for DYLD_CHAINED_PTR_32 some non-pointer values are co-opted into the chain
|
||||
// as out of range rebases. If an entry in the chain is > max_valid_pointer, then it
|
||||
// is not a pointer. To restore the value, subtract off the bias, which is
|
||||
// (64MB+max_valid_pointer)/2.
|
||||
struct dyld_chained_ptr_32_rebase
|
||||
{
|
||||
uint32_t target : 26, // vmaddr, 64MB max image size
|
||||
next : 5, // 4-byte stride
|
||||
bind : 1; // == 0
|
||||
};
|
||||
|
||||
// DYLD_CHAINED_PTR_32
|
||||
struct dyld_chained_ptr_32_bind
|
||||
{
|
||||
uint32_t ordinal : 20,
|
||||
addend : 6, // 0 thru 63
|
||||
next : 5, // 4-byte stride
|
||||
bind : 1; // == 1
|
||||
};
|
||||
|
||||
// DYLD_CHAINED_PTR_32_CACHE
|
||||
struct dyld_chained_ptr_32_cache_rebase
|
||||
{
|
||||
uint32_t target : 30, // 1GB max dyld cache TEXT and DATA
|
||||
next : 2; // 4-byte stride
|
||||
};
|
||||
|
||||
|
||||
// DYLD_CHAINED_PTR_32_FIRMWARE
|
||||
struct dyld_chained_ptr_32_firmware_rebase
|
||||
{
|
||||
uint32_t target : 26, // 64MB max firmware TEXT and DATA
|
||||
next : 6; // 4-byte stride
|
||||
};
|
||||
|
||||
|
||||
|
||||
// values for dyld_chained_fixups_header.imports_format
|
||||
enum {
|
||||
DYLD_CHAINED_IMPORT = 1,
|
||||
DYLD_CHAINED_IMPORT_ADDEND = 2,
|
||||
DYLD_CHAINED_IMPORT_ADDEND64 = 3,
|
||||
};
|
||||
|
||||
// DYLD_CHAINED_IMPORT
|
||||
struct dyld_chained_import
|
||||
{
|
||||
uint32_t lib_ordinal : 8,
|
||||
weak_import : 1,
|
||||
name_offset : 23;
|
||||
};
|
||||
|
||||
// DYLD_CHAINED_IMPORT_ADDEND
|
||||
struct dyld_chained_import_addend
|
||||
{
|
||||
uint32_t lib_ordinal : 8,
|
||||
weak_import : 1,
|
||||
name_offset : 23;
|
||||
int32_t addend;
|
||||
};
|
||||
|
||||
// DYLD_CHAINED_IMPORT_ADDEND64
|
||||
struct dyld_chained_import_addend64
|
||||
{
|
||||
uint64_t lib_ordinal : 16,
|
||||
weak_import : 1,
|
||||
reserved : 15,
|
||||
name_offset : 32;
|
||||
uint64_t addend;
|
||||
};
|
||||
|
||||
#endif // __MACH_O_FIXUP_CHAINS__
|
||||
|
@ -1,4 +1,3 @@
|
||||
// Modified by Lubos Dolezel for Darling build
|
||||
/*
|
||||
* Copyright (c) 1999-2010 Apple Inc. All Rights Reserved.
|
||||
*
|
||||
@ -28,10 +27,32 @@
|
||||
* This file describes the format of mach object files.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <mach/vm_prot.h>
|
||||
|
||||
#ifndef __APPLE__
|
||||
typedef int cpu_type_t;
|
||||
typedef int cpu_subtype_t;
|
||||
typedef int vm_prot_t;
|
||||
#else
|
||||
|
||||
/*
|
||||
* <mach/machine.h> is needed here for the cpu_type_t and cpu_subtype_t types
|
||||
* and contains the constants for the possible values of these types.
|
||||
*/
|
||||
#include <mach/machine.h>
|
||||
|
||||
/*
|
||||
* <mach/vm_prot.h> is needed here for the vm_prot_t type and contains the
|
||||
* constants that are or'ed together for the possible values of this type.
|
||||
*/
|
||||
#include <mach/vm_prot.h>
|
||||
|
||||
/*
|
||||
* <machine/thread_status.h> is expected to define the flavors of the thread
|
||||
* states and the structures of those flavors for each machine.
|
||||
*/
|
||||
#include <mach/machine/thread_status.h>
|
||||
#include <architecture/byte_order.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The 32-bit mach header appears at the very beginning of the object file for
|
||||
@ -196,6 +217,22 @@ struct mach_header_64 {
|
||||
#define MH_APP_EXTENSION_SAFE 0x02000000 /* The code was linked for use in an
|
||||
application extension. */
|
||||
|
||||
#define MH_NLIST_OUTOFSYNC_WITH_DYLDINFO 0x04000000 /* The external symbols
|
||||
listed in the nlist symbol table do
|
||||
not include all the symbols listed in
|
||||
the dyld info. */
|
||||
|
||||
#define MH_SIM_SUPPORT 0x08000000 /* Allow LC_MIN_VERSION_MACOS and
|
||||
LC_BUILD_VERSION load commands with
|
||||
the platforms macOS, macCatalyst,
|
||||
iOSSimulator, tvOSSimulator and
|
||||
watchOSSimulator. */
|
||||
|
||||
#define MH_DYLIB_IN_CACHE 0x80000000 /* Only for use on dylibs. When this bit
|
||||
is set, the dylib is part of the dyld
|
||||
shared cache, rather than loose in
|
||||
the filesystem. */
|
||||
|
||||
/*
|
||||
* The load commands directly follow the mach_header. The total size of all
|
||||
* of the commands is given by the sizeofcmds field in the mach_header. All
|
||||
@ -288,7 +325,10 @@ struct load_command {
|
||||
#define LC_LINKER_OPTIMIZATION_HINT 0x2E /* optimization hints in MH_OBJECT files */
|
||||
#define LC_VERSION_MIN_TVOS 0x2F /* build for AppleTV min OS version */
|
||||
#define LC_VERSION_MIN_WATCHOS 0x30 /* build for Watch min OS version */
|
||||
|
||||
#define LC_NOTE 0x31 /* arbitrary data included within a Mach-O file */
|
||||
#define LC_BUILD_VERSION 0x32 /* build for platform min OS version */
|
||||
#define LC_DYLD_EXPORTS_TRIE (0x33 | LC_REQ_DYLD) /* used with linkedit_data_command, payload is trie */
|
||||
#define LC_DYLD_CHAINED_FIXUPS (0x34 | LC_REQ_DYLD) /* used with linkedit_data_command */
|
||||
|
||||
/*
|
||||
* A variable length string in a load command is represented by an lc_str
|
||||
@ -366,6 +406,9 @@ struct segment_command_64 { /* for 64-bit architectures */
|
||||
first page of the segment is not
|
||||
protected. All other pages of the
|
||||
segment are protected. */
|
||||
#define SG_READ_ONLY 0x10 /* This segment is made read-only after fixups */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* A segment is made up of zero or more sections. Non-MH_OBJECT files have
|
||||
@ -491,6 +534,8 @@ struct section_64 { /* for 64-bit architectures */
|
||||
#define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15 /* functions to call
|
||||
to initialize TLV
|
||||
values */
|
||||
#define S_INIT_FUNC_OFFSETS 0x16 /* 32-bit offsets to
|
||||
initializers */
|
||||
|
||||
/*
|
||||
* Constants for the section attributes part of the flags field of a section
|
||||
@ -752,14 +797,14 @@ struct dylinker_command {
|
||||
* Thread commands contain machine-specific data structures suitable for
|
||||
* use in the thread state primitives. The machine specific data structures
|
||||
* follow the struct thread_command as follows.
|
||||
* Each flavor of machine specific data structure is preceded by an unsigned
|
||||
* long constant for the flavor of that data structure, an uint32_t
|
||||
* that is the count of longs of the size of the state data structure and then
|
||||
* Each flavor of machine specific data structure is preceded by an uint32_t
|
||||
* constant for the flavor of that data structure, an uint32_t that is the
|
||||
* count of uint32_t's of the size of the state data structure and then
|
||||
* the state data structure follows. This triple may be repeated for many
|
||||
* flavors. The constants for the flavors, counts and state data structure
|
||||
* definitions are expected to be in the header file <machine/thread_status.h>.
|
||||
* These machine specific data structures sizes must be multiples of
|
||||
* 4 bytes The cmdsize reflects the total size of the thread_command
|
||||
* 4 bytes. The cmdsize reflects the total size of the thread_command
|
||||
* and all of the sizes of the constants for the flavors, counts and state
|
||||
* data structures.
|
||||
*
|
||||
@ -773,7 +818,7 @@ struct thread_command {
|
||||
uint32_t cmd; /* LC_THREAD or LC_UNIXTHREAD */
|
||||
uint32_t cmdsize; /* total size of this command */
|
||||
/* uint32_t flavor flavor of thread state */
|
||||
/* uint32_t count count of longs in thread state */
|
||||
/* uint32_t count count of uint32_t's in thread state */
|
||||
/* struct XXX_thread_state state thread state for this flavor */
|
||||
/* ... */
|
||||
};
|
||||
@ -1149,8 +1194,10 @@ struct rpath_command {
|
||||
struct linkedit_data_command {
|
||||
uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO,
|
||||
LC_FUNCTION_STARTS, LC_DATA_IN_CODE,
|
||||
LC_DYLIB_CODE_SIGN_DRS or
|
||||
LC_LINKER_OPTIMIZATION_HINT. */
|
||||
LC_DYLIB_CODE_SIGN_DRS,
|
||||
LC_LINKER_OPTIMIZATION_HINT,
|
||||
LC_DYLD_EXPORTS_TRIE, or
|
||||
LC_DYLD_CHAINED_FIXUPS. */
|
||||
uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */
|
||||
uint32_t dataoff; /* file offset of data in __LINKEDIT segment */
|
||||
uint32_t datasize; /* file size of data in __LINKEDIT segment */
|
||||
@ -1190,12 +1237,55 @@ struct encryption_info_command_64 {
|
||||
*/
|
||||
struct version_min_command {
|
||||
uint32_t cmd; /* LC_VERSION_MIN_MACOSX or
|
||||
LC_VERSION_MIN_IPHONEOS */
|
||||
LC_VERSION_MIN_IPHONEOS or
|
||||
LC_VERSION_MIN_WATCHOS or
|
||||
LC_VERSION_MIN_TVOS */
|
||||
uint32_t cmdsize; /* sizeof(struct min_version_command) */
|
||||
uint32_t version; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
|
||||
uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
|
||||
};
|
||||
|
||||
/*
|
||||
* The build_version_command contains the min OS version on which this
|
||||
* binary was built to run for its platform. The list of known platforms and
|
||||
* tool values following it.
|
||||
*/
|
||||
struct build_version_command {
|
||||
uint32_t cmd; /* LC_BUILD_VERSION */
|
||||
uint32_t cmdsize; /* sizeof(struct build_version_command) plus */
|
||||
/* ntools * sizeof(struct build_tool_version) */
|
||||
uint32_t platform; /* platform */
|
||||
uint32_t minos; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
|
||||
uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
|
||||
uint32_t ntools; /* number of tool entries following this */
|
||||
};
|
||||
|
||||
struct build_tool_version {
|
||||
uint32_t tool; /* enum for the tool */
|
||||
uint32_t version; /* version number of the tool */
|
||||
};
|
||||
|
||||
/* Known values for the platform field above. */
|
||||
#define PLATFORM_MACOS 1
|
||||
#define PLATFORM_IOS 2
|
||||
#define PLATFORM_TVOS 3
|
||||
#define PLATFORM_WATCHOS 4
|
||||
#define PLATFORM_BRIDGEOS 5
|
||||
#define PLATFORM_MACCATALYST 6
|
||||
#if (!defined(PLATFORM_MACCATALYST))
|
||||
#define PLATFORM_MACCATALYST 6
|
||||
#endif
|
||||
#define PLATFORM_IOSMAC 6
|
||||
#define PLATFORM_IOSSIMULATOR 7
|
||||
#define PLATFORM_TVOSSIMULATOR 8
|
||||
#define PLATFORM_WATCHOSSIMULATOR 9
|
||||
#define PLATFORM_DRIVERKIT 10
|
||||
|
||||
/* Known values for the tool field above. */
|
||||
#define TOOL_CLANG 1
|
||||
#define TOOL_SWIFT 2
|
||||
#define TOOL_LD 3
|
||||
|
||||
/*
|
||||
* The dyld_info_command contains the file offsets and sizes of
|
||||
* the new compressed form of the information dyld needs to
|
||||
@ -1337,6 +1427,7 @@ struct dyld_info_command {
|
||||
#define BIND_SPECIAL_DYLIB_SELF 0
|
||||
#define BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE -1
|
||||
#define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2
|
||||
#define BIND_SPECIAL_DYLIB_WEAK_LOOKUP -3
|
||||
|
||||
#define BIND_SYMBOL_FLAGS_WEAK_IMPORT 0x1
|
||||
#define BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION 0x8
|
||||
@ -1356,6 +1447,9 @@ struct dyld_info_command {
|
||||
#define BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB 0xA0
|
||||
#define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED 0xB0
|
||||
#define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xC0
|
||||
#define BIND_OPCODE_THREADED 0xD0
|
||||
#define BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB 0x00
|
||||
#define BIND_SUBOPCODE_THREADED_APPLY 0x01
|
||||
|
||||
|
||||
/*
|
||||
@ -1365,6 +1459,7 @@ struct dyld_info_command {
|
||||
#define EXPORT_SYMBOL_FLAGS_KIND_MASK 0x03
|
||||
#define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00
|
||||
#define EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL 0x01
|
||||
#define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
|
||||
#define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04
|
||||
#define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08
|
||||
#define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
|
||||
@ -1475,4 +1570,16 @@ struct tlv_descriptor
|
||||
unsigned long offset;
|
||||
};
|
||||
|
||||
/*
|
||||
* LC_NOTE commands describe a region of arbitrary data included in a Mach-O
|
||||
* file. Its initial use is to record extra data in MH_CORE files.
|
||||
*/
|
||||
struct note_command {
|
||||
uint32_t cmd; /* LC_NOTE */
|
||||
uint32_t cmdsize; /* sizeof(struct note_command) */
|
||||
char data_owner[16]; /* owner name for this LC_NOTE */
|
||||
uint64_t offset; /* file offset of this data */
|
||||
uint64_t size; /* length of data region */
|
||||
};
|
||||
|
||||
#endif /* _MACHO_LOADER_H_ */
|
||||
|
@ -1,4 +1,4 @@
|
||||
module MachO [system] {
|
||||
module MachO [system] [extern_c] {
|
||||
export *
|
||||
|
||||
module arch {
|
||||
|
@ -302,6 +302,12 @@ struct nlist_64 {
|
||||
*/
|
||||
#define N_ALT_ENTRY 0x0200
|
||||
|
||||
/*
|
||||
* The N_COLD_FUNC bit of the n_desc field indicates that the symbol is used
|
||||
* infrequently and the linker should order it towards the end of the section.
|
||||
*/
|
||||
#define N_COLD_FUNC 0x0400
|
||||
|
||||
#ifndef __STRICT_BSD__
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -90,13 +90,17 @@
|
||||
#define N_STSYM 0x26 /* static symbol: name,,n_sect,type,address */
|
||||
#define N_LCSYM 0x28 /* .lcomm symbol: name,,n_sect,type,address */
|
||||
#define N_BNSYM 0x2e /* begin nsect sym: 0,,n_sect,0,address */
|
||||
#define N_AST 0x32 /* AST file path: name,,NO_SECT,0,0 */
|
||||
#define N_OPT 0x3c /* emitted with gcc2_compiled and in gcc source */
|
||||
#define N_RSYM 0x40 /* register sym: name,,NO_SECT,type,register */
|
||||
#define N_SLINE 0x44 /* src line: 0,,n_sect,linenumber,address */
|
||||
#define N_ENSYM 0x4e /* end nsect sym: 0,,n_sect,0,address */
|
||||
#define N_SSYM 0x60 /* structure elt: name,,NO_SECT,type,struct_offset */
|
||||
#define N_SO 0x64 /* source file name: name,,n_sect,0,address */
|
||||
#define N_OSO 0x66 /* object file name: name,,0,0,st_mtime */
|
||||
#define N_OSO 0x66 /* object file name: name,,(see below),0,st_mtime */
|
||||
/* historically N_OSO set n_sect to 0. The N_OSO
|
||||
* n_sect may instead hold the low byte of the
|
||||
* cpusubtype value from the Mach-O header. */
|
||||
#define N_LSYM 0x80 /* local sym: name,,NO_SECT,type,offset */
|
||||
#define N_BINCL 0x82 /* include file beginning: name,,NO_SECT,0,sum */
|
||||
#define N_SOL 0x84 /* #included file name: name,,n_sect,0,address */
|
||||
|
@ -44,6 +44,11 @@ extern void swap_fat_arch(
|
||||
uint32_t nfat_arch,
|
||||
enum NXByteOrder target_byte_order);
|
||||
|
||||
extern void swap_fat_arch_64(
|
||||
struct fat_arch_64 *fat_archs64,
|
||||
uint32_t nfat_arch,
|
||||
enum NXByteOrder target_byte_order);
|
||||
|
||||
extern void swap_mach_header(
|
||||
struct mach_header *mh,
|
||||
enum NXByteOrder target_byte_order);
|
||||
@ -186,6 +191,19 @@ extern void swap_source_version_command(
|
||||
struct source_version_command *sv,
|
||||
enum NXByteOrder target_byte_sex);
|
||||
|
||||
extern void swap_note_command(
|
||||
struct note_command *nc,
|
||||
enum NXByteOrder target_byte_sex);
|
||||
|
||||
extern void swap_build_version_command(
|
||||
struct build_version_command *bv,
|
||||
enum NXByteOrder target_byte_sex);
|
||||
|
||||
extern void swap_build_tool_version(
|
||||
struct build_tool_version *bt,
|
||||
uint32_t ntools,
|
||||
enum NXByteOrder target_byte_sex);
|
||||
|
||||
extern void swap_prebind_cksum_command(
|
||||
struct prebind_cksum_command *cksum_cmd,
|
||||
enum NXByteOrder target_byte_sex);
|
||||
@ -214,6 +232,11 @@ extern void swap_ranlib(
|
||||
uint32_t nranlibs,
|
||||
enum NXByteOrder target_byte_order);
|
||||
|
||||
extern void swap_ranlib_64(
|
||||
struct ranlib_64 *ranlibs,
|
||||
uint64_t nranlibs,
|
||||
enum NXByteOrder target_byte_order);
|
||||
|
||||
extern void swap_relocation_info(
|
||||
struct relocation_info *relocs,
|
||||
uint32_t nrelocs,
|
||||
|
66
platform-include/mach/dyld_kernel.h
Normal file
66
platform-include/mach/dyld_kernel.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Apple Computer, 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@
|
||||
*/
|
||||
|
||||
#ifndef _MACH_DYLIB_INFO_H_
|
||||
#define _MACH_DYLIB_INFO_H_
|
||||
|
||||
#include <mach/boolean.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/_types/_fsid_t.h>
|
||||
#include <sys/_types/_u_int32_t.h>
|
||||
#include <sys/_types/_fsobj_id_t.h>
|
||||
#include <sys/_types/_uuid_t.h>
|
||||
|
||||
/* These definitions must be kept in sync with the ones in
|
||||
* osfmk/mach/mach_types.defs.
|
||||
*/
|
||||
|
||||
struct dyld_kernel_image_info {
|
||||
uuid_t uuid;
|
||||
fsobj_id_t fsobjid;
|
||||
fsid_t fsid;
|
||||
uint64_t load_addr;
|
||||
};
|
||||
|
||||
struct dyld_kernel_process_info {
|
||||
struct dyld_kernel_image_info cache_image_info;
|
||||
uint64_t timestamp; // mach_absolute_time of last time dyld change to image list
|
||||
uint32_t imageCount; // number of images currently loaded into process
|
||||
uint32_t initialImageCount; // number of images statically loaded into process (before any dlopen() calls)
|
||||
uint8_t dyldState; // one of dyld_process_state_* values
|
||||
boolean_t no_cache; // process is running without a dyld cache
|
||||
boolean_t private_cache; // process is using a private copy of its dyld cache
|
||||
};
|
||||
|
||||
/* typedefs so our MIG is sane */
|
||||
|
||||
typedef struct dyld_kernel_image_info dyld_kernel_image_info_t;
|
||||
typedef struct dyld_kernel_process_info dyld_kernel_process_info_t;
|
||||
typedef dyld_kernel_image_info_t *dyld_kernel_image_info_array_t;
|
||||
|
||||
#endif /* _MACH_DYLIB_INFO_H_ */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2010 Apple Computer, Inc. All rights reserved.
|
||||
* Copyright (c) 2000-2018 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
|
||||
*
|
||||
@ -89,6 +89,7 @@
|
||||
#include <mach/mach_voucher_types.h>
|
||||
#include <mach/processor_info.h>
|
||||
#include <mach/task_info.h>
|
||||
#include <mach/task_inspect.h>
|
||||
#include <mach/task_policy.h>
|
||||
#include <mach/task_special_ports.h>
|
||||
#include <mach/thread_info.h>
|
||||
@ -107,6 +108,7 @@
|
||||
#include <mach/vm_types.h>
|
||||
#include <mach/vm_region.h>
|
||||
#include <mach/kmod.h>
|
||||
#include <mach/dyld_kernel.h>
|
||||
|
||||
|
||||
/*
|
||||
@ -115,10 +117,13 @@
|
||||
*/
|
||||
typedef mach_port_t task_t;
|
||||
typedef mach_port_t task_name_t;
|
||||
typedef mach_port_t task_inspect_t;
|
||||
typedef mach_port_t task_suspension_token_t;
|
||||
typedef mach_port_t thread_t;
|
||||
typedef mach_port_t thread_act_t;
|
||||
typedef mach_port_t thread_inspect_t;
|
||||
typedef mach_port_t ipc_space_t;
|
||||
typedef mach_port_t ipc_space_inspect_t;
|
||||
typedef mach_port_t coalition_t;
|
||||
typedef mach_port_t host_t;
|
||||
typedef mach_port_t host_priv_t;
|
||||
@ -133,6 +138,7 @@ typedef mach_port_t alarm_t;
|
||||
typedef mach_port_t clock_serv_t;
|
||||
typedef mach_port_t clock_ctrl_t;
|
||||
|
||||
typedef mach_port_t arcade_register_t;
|
||||
|
||||
/*
|
||||
* These aren't really unique types. They are just called
|
||||
@ -198,18 +204,22 @@ typedef clock_serv_t clock_serv_port_t;
|
||||
typedef clock_ctrl_t clock_ctrl_port_t;
|
||||
typedef exception_handler_t exception_port_t;
|
||||
typedef exception_handler_array_t exception_port_arrary_t;
|
||||
|
||||
typedef char vfs_path_t[4096];
|
||||
typedef char nspace_path_t[1024]; /* 1024 == PATH_MAX */
|
||||
|
||||
#define TASK_NULL ((task_t) 0)
|
||||
#define TASK_NAME_NULL ((task_name_t) 0)
|
||||
#define TASK_INSPECT_NULL ((task_inspect_t) 0)
|
||||
#define THREAD_NULL ((thread_t) 0)
|
||||
#define THREAD_INSPECT_NULL ((thread_inspect_t) 0)
|
||||
#define TID_NULL ((uint64_t) 0)
|
||||
#define THR_ACT_NULL ((thread_act_t) 0)
|
||||
#define IPC_SPACE_NULL ((ipc_space_t) 0)
|
||||
#define IPC_SPACE_INSPECT_NULL ((ipc_space_inspect_t) 0)
|
||||
#define COALITION_NULL ((coalition_t) 0)
|
||||
#define HOST_NULL ((host_t) 0)
|
||||
#define HOST_PRIV_NULL ((host_priv_t)0)
|
||||
#define HOST_SECURITY_NULL ((host_security_t)0)
|
||||
#define HOST_PRIV_NULL ((host_priv_t) 0)
|
||||
#define HOST_SECURITY_NULL ((host_security_t) 0)
|
||||
#define PROCESSOR_SET_NULL ((processor_set_t) 0)
|
||||
#define PROCESSOR_NULL ((processor_t) 0)
|
||||
#define SEMAPHORE_NULL ((semaphore_t) 0)
|
||||
@ -218,6 +228,7 @@ typedef exception_handler_array_t exception_port_arrary_t;
|
||||
#define ALARM_NULL ((alarm_t) 0)
|
||||
#define CLOCK_NULL ((clock_t) 0)
|
||||
#define UND_SERVER_NULL ((UNDServerRef) 0)
|
||||
#define ARCADE_REG_NULL ((arcade_register_t) 0)
|
||||
|
||||
/* DEPRECATED */
|
||||
typedef natural_t ledger_item_t;
|
||||
|
54
platform-include/mach/task_inspect.h
Normal file
54
platform-include/mach/task_inspect.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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@
|
||||
*/
|
||||
|
||||
#ifndef MACH_TASK_INSPECT_H
|
||||
#define MACH_TASK_INSPECT_H
|
||||
|
||||
/*
|
||||
* XXX These interfaces are still in development -- they are subject to change
|
||||
* without notice.
|
||||
*/
|
||||
|
||||
typedef natural_t task_inspect_flavor_t;
|
||||
|
||||
enum task_inspect_flavor {
|
||||
TASK_INSPECT_BASIC_COUNTS = 1,
|
||||
};
|
||||
|
||||
struct task_inspect_basic_counts {
|
||||
uint64_t instructions;
|
||||
uint64_t cycles;
|
||||
};
|
||||
#define TASK_INSPECT_BASIC_COUNTS_COUNT \
|
||||
(sizeof(struct task_inspect_basic_counts) / sizeof(natural_t))
|
||||
typedef struct task_inspect_basic_counts task_inspect_basic_counts_data_t;
|
||||
typedef struct task_inspect_basic_counts *task_inspect_basic_counts_t;
|
||||
|
||||
typedef integer_t *task_inspect_info_t;
|
||||
|
||||
#endif /* !defined(MACH_TASK_INSPECT_H) */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2009 Apple Inc. All rights reserved.
|
||||
* Copyright (c) 2000-2019 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
|
||||
*
|
||||
@ -222,6 +222,8 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
|
||||
#define VM_PAGE_QUERY_PAGE_EXTERNAL 0x80
|
||||
#define VM_PAGE_QUERY_PAGE_CS_VALIDATED 0x100
|
||||
#define VM_PAGE_QUERY_PAGE_CS_TAINTED 0x200
|
||||
#define VM_PAGE_QUERY_PAGE_CS_NX 0x400
|
||||
#define VM_PAGE_QUERY_PAGE_REUSABLE 0x800
|
||||
|
||||
|
||||
/*
|
||||
@ -237,6 +239,9 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
|
||||
* VM_FLAGS_PURGABLE
|
||||
* Create a purgable VM object for that new VM region.
|
||||
*
|
||||
* VM_FLAGS_4GB_CHUNK
|
||||
* The new VM region will be chunked up into 4GB sized pieces.
|
||||
*
|
||||
* VM_FLAGS_NO_PMAP_CHECK
|
||||
* (for DEBUG kernel config only, ignored for other configs)
|
||||
* Do not check that there is no stale pmap mapping for the new VM region.
|
||||
@ -252,10 +257,15 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
|
||||
* queue instead of the active queue. In other words, they are not
|
||||
* cached so that they will be stolen first if memory runs low.
|
||||
*/
|
||||
|
||||
#define VM_FLAGS_FIXED 0x0000
|
||||
#define VM_FLAGS_ANYWHERE 0x0001
|
||||
#define VM_FLAGS_PURGABLE 0x0002
|
||||
#define VM_FLAGS_4GB_CHUNK 0x0004
|
||||
#define VM_FLAGS_RANDOM_ADDR 0x0008
|
||||
#define VM_FLAGS_NO_CACHE 0x0010
|
||||
#define VM_FLAGS_RESILIENT_CODESIGN 0x0020
|
||||
#define VM_FLAGS_RESILIENT_MEDIA 0x0040
|
||||
#define VM_FLAGS_OVERWRITE 0x4000 /* delete any existing mappings first */
|
||||
/*
|
||||
* VM_FLAGS_SUPERPAGE_MASK
|
||||
@ -264,6 +274,7 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
|
||||
*/
|
||||
#define VM_FLAGS_SUPERPAGE_MASK 0x70000 /* bits 0x10000, 0x20000, 0x40000 */
|
||||
#define VM_FLAGS_RETURN_DATA_ADDR 0x100000 /* Return address of target data, rather than base of page */
|
||||
#define VM_FLAGS_RETURN_4K_DATA_ADDR 0x800000 /* Return 4K aligned address of target data */
|
||||
#define VM_FLAGS_ALIAS_MASK 0xFF000000
|
||||
#define VM_GET_FLAGS_ALIAS(flags, alias) \
|
||||
(alias) = ((flags) & VM_FLAGS_ALIAS_MASK) >> 24
|
||||
@ -275,16 +286,22 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
|
||||
#define VM_FLAGS_USER_ALLOCATE (VM_FLAGS_FIXED | \
|
||||
VM_FLAGS_ANYWHERE | \
|
||||
VM_FLAGS_PURGABLE | \
|
||||
VM_FLAGS_4GB_CHUNK | \
|
||||
VM_FLAGS_RANDOM_ADDR | \
|
||||
VM_FLAGS_NO_CACHE | \
|
||||
VM_FLAGS_OVERWRITE | \
|
||||
VM_FLAGS_SUPERPAGE_MASK | \
|
||||
VM_FLAGS_ALIAS_MASK)
|
||||
#define VM_FLAGS_USER_MAP (VM_FLAGS_USER_ALLOCATE | \
|
||||
VM_FLAGS_RETURN_4K_DATA_ADDR | \
|
||||
VM_FLAGS_RETURN_DATA_ADDR)
|
||||
#define VM_FLAGS_USER_REMAP (VM_FLAGS_FIXED | \
|
||||
VM_FLAGS_ANYWHERE | \
|
||||
VM_FLAGS_RANDOM_ADDR | \
|
||||
VM_FLAGS_OVERWRITE| \
|
||||
VM_FLAGS_RETURN_DATA_ADDR)
|
||||
VM_FLAGS_RETURN_DATA_ADDR | \
|
||||
VM_FLAGS_RESILIENT_CODESIGN | \
|
||||
VM_FLAGS_RESILIENT_MEDIA)
|
||||
|
||||
#define VM_FLAGS_SUPERPAGE_SHIFT 16
|
||||
#define SUPERPAGE_NONE 0 /* no superpages, if all bits are 0 */
|
||||
@ -294,6 +311,33 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
|
||||
#define SUPERPAGE_SIZE_2MB 2
|
||||
#define VM_FLAGS_SUPERPAGE_SIZE_2MB (SUPERPAGE_SIZE_2MB<<VM_FLAGS_SUPERPAGE_SHIFT)
|
||||
|
||||
/*
|
||||
* EXC_GUARD definitions for virtual memory.
|
||||
*/
|
||||
#define GUARD_TYPE_VIRT_MEMORY 0x5
|
||||
|
||||
/* Reasons for exception for virtual memory */
|
||||
enum virtual_memory_guard_exception_codes {
|
||||
kGUARD_EXC_DEALLOC_GAP = 1u << 0
|
||||
};
|
||||
|
||||
|
||||
/* current accounting postmark */
|
||||
#define __VM_LEDGER_ACCOUNTING_POSTMARK 2019032600
|
||||
|
||||
/* discrete values: */
|
||||
#define VM_LEDGER_TAG_NONE 0x00000000
|
||||
#define VM_LEDGER_TAG_DEFAULT 0x00000001
|
||||
#define VM_LEDGER_TAG_NETWORK 0x00000002
|
||||
#define VM_LEDGER_TAG_MEDIA 0x00000003
|
||||
#define VM_LEDGER_TAG_GRAPHICS 0x00000004
|
||||
#define VM_LEDGER_TAG_NEURAL 0x00000005
|
||||
#define VM_LEDGER_TAG_MAX 0x00000005
|
||||
/* individual bits: */
|
||||
#define VM_LEDGER_FLAG_NO_FOOTPRINT 0x00000001
|
||||
#define VM_LEDGER_FLAGS (VM_LEDGER_FLAG_NO_FOOTPRINT)
|
||||
|
||||
|
||||
#define VM_MEMORY_MALLOC 1
|
||||
#define VM_MEMORY_MALLOC_SMALL 2
|
||||
#define VM_MEMORY_MALLOC_LARGE 3
|
||||
@ -307,6 +351,7 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
|
||||
#define VM_MEMORY_ANALYSIS_TOOL 10
|
||||
|
||||
#define VM_MEMORY_MALLOC_NANO 11
|
||||
#define VM_MEMORY_MALLOC_MEDIUM 12
|
||||
|
||||
#define VM_MEMORY_MACH_MSG 20
|
||||
#define VM_MEMORY_IOKIT 21
|
||||
@ -348,6 +393,9 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
|
||||
/* Window backing stores, custom shadow data, and compressed backing stores */
|
||||
#define VM_MEMORY_COREGRAPHICS_BACKINGSTORES 57
|
||||
|
||||
/* x-alloc'd memory */
|
||||
#define VM_MEMORY_COREGRAPHICS_XALLOC 58
|
||||
|
||||
/* catch-all for other uses, such as the read-only shared data page */
|
||||
#define VM_MEMORY_COREGRAPHICS_MISC VM_MEMORY_COREGRAPHICS
|
||||
|
||||
@ -361,6 +409,7 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
|
||||
|
||||
/* JavaScriptCore heaps */
|
||||
#define VM_MEMORY_JAVASCRIPT_CORE 63
|
||||
#define VM_MEMORY_WEBASSEMBLY VM_MEMORY_JAVASCRIPT_CORE
|
||||
/* memory allocated for the JIT */
|
||||
#define VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR 64
|
||||
#define VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE 65
|
||||
@ -404,10 +453,71 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
|
||||
/* Genealogy buffers */
|
||||
#define VM_MEMORY_GENEALOGY 78
|
||||
|
||||
/* RawCamera VM allocated memory */
|
||||
#define VM_MEMORY_RAWCAMERA 79
|
||||
|
||||
/* corpse info for dead process */
|
||||
#define VM_MEMORY_CORPSEINFO 80
|
||||
|
||||
/* Apple System Logger (ASL) messages */
|
||||
#define VM_MEMORY_ASL 81
|
||||
|
||||
/* Swift runtime */
|
||||
#define VM_MEMORY_SWIFT_RUNTIME 82
|
||||
|
||||
/* Swift metadata */
|
||||
#define VM_MEMORY_SWIFT_METADATA 83
|
||||
|
||||
/* DHMM data */
|
||||
#define VM_MEMORY_DHMM 84
|
||||
|
||||
|
||||
/* memory allocated by SceneKit.framework */
|
||||
#define VM_MEMORY_SCENEKIT 86
|
||||
|
||||
/* memory allocated by skywalk networking */
|
||||
#define VM_MEMORY_SKYWALK 87
|
||||
|
||||
#define VM_MEMORY_IOSURFACE 88
|
||||
|
||||
#define VM_MEMORY_LIBNETWORK 89
|
||||
|
||||
#define VM_MEMORY_AUDIO 90
|
||||
|
||||
#define VM_MEMORY_VIDEOBITSTREAM 91
|
||||
|
||||
/* memory allocated by CoreMedia */
|
||||
#define VM_MEMORY_CM_XPC 92
|
||||
|
||||
#define VM_MEMORY_CM_RPC 93
|
||||
|
||||
#define VM_MEMORY_CM_MEMORYPOOL 94
|
||||
|
||||
#define VM_MEMORY_CM_READCACHE 95
|
||||
|
||||
#define VM_MEMORY_CM_CRABS 96
|
||||
|
||||
/* memory allocated for QuickLookThumbnailing */
|
||||
#define VM_MEMORY_QUICKLOOK_THUMBNAILS 97
|
||||
|
||||
/* memory allocated by Accounts framework */
|
||||
#define VM_MEMORY_ACCOUNTS 98
|
||||
|
||||
/* memory allocated by Sanitizer runtime libraries */
|
||||
#define VM_MEMORY_SANITIZER 99
|
||||
|
||||
/* Differentiate memory needed by GPU drivers and frameworks from generic IOKit allocations */
|
||||
#define VM_MEMORY_IOACCELERATOR 100
|
||||
|
||||
/* memory allocated by CoreMedia for global image registration of frames */
|
||||
#define VM_MEMORY_CM_REGWARP 101
|
||||
|
||||
/* Reserve 240-255 for application */
|
||||
#define VM_MEMORY_APPLICATION_SPECIFIC_1 240
|
||||
#define VM_MEMORY_APPLICATION_SPECIFIC_16 255
|
||||
|
||||
#define VM_MAKE_TAG(tag) ((tag) << 24)
|
||||
|
||||
|
||||
|
||||
#endif /* _MACH_VM_STATISTICS_H_ */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2016 Apple Inc. All rights reserved.
|
||||
* Copyright (c) 2008-2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_APACHE_LICENSE_HEADER_START@
|
||||
*
|
||||
@ -21,15 +21,30 @@
|
||||
#ifndef __OS_AVAILABILITY__
|
||||
#define __OS_AVAILABILITY__
|
||||
|
||||
#include <AvailabilityInternal.h>
|
||||
|
||||
/*
|
||||
Macros for defining which versions/platform a given symbol can be used.
|
||||
|
||||
@see http://clang.llvm.org/docs/AttributeReference.html#availability
|
||||
* API_TO_BE_DEPRECATED is used as a version number in API that will be deprecated
|
||||
* in an upcoming release. This soft deprecation is an intermediate step before formal
|
||||
* deprecation to notify developers about the API before compiler warnings are generated.
|
||||
* You can find all places in your code that use soft deprecated API by redefining the
|
||||
* value of this macro to your current minimum deployment target, for example:
|
||||
* (macOS)
|
||||
* clang -DAPI_TO_BE_DEPRECATED=10.12 <other compiler flags>
|
||||
* (iOS)
|
||||
* clang -DAPI_TO_BE_DEPRECATED=11.0 <other compiler flags>
|
||||
*/
|
||||
|
||||
/*
|
||||
#ifndef API_TO_BE_DEPRECATED
|
||||
#define API_TO_BE_DEPRECATED 100000
|
||||
#endif
|
||||
|
||||
#include <AvailabilityInternal.h>
|
||||
|
||||
|
||||
|
||||
#if defined(__has_feature) && defined(__has_attribute)
|
||||
#if __has_attribute(availability)
|
||||
|
||||
/*
|
||||
* API Introductions
|
||||
*
|
||||
* Use to specify the release that a particular API became available.
|
||||
@ -43,14 +58,12 @@
|
||||
* API_AVAILABLE(macos(10.4), ios(8.0), watchos(2.0), tvos(10.0))
|
||||
*/
|
||||
|
||||
#define API_AVAILABLE(...) __API_AVAILABLE_GET_MACRO(__VA_ARGS__,__API_AVAILABLE4, __API_AVAILABLE3, __API_AVAILABLE2, __API_AVAILABLE1)(__VA_ARGS__)
|
||||
#define API_AVAILABLE(...) __API_AVAILABLE_GET_MACRO(__VA_ARGS__,__API_AVAILABLE7, __API_AVAILABLE6, __API_AVAILABLE5, __API_AVAILABLE4, __API_AVAILABLE3, __API_AVAILABLE2, __API_AVAILABLE1, 0)(__VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Stub for SPI_AVAILABLE
|
||||
*/
|
||||
#define SPI_AVAILABLE(...)
|
||||
#define API_AVAILABLE_BEGIN(...) _Pragma("clang attribute push") __API_AVAILABLE_BEGIN_GET_MACRO(__VA_ARGS__,__API_AVAILABLE_BEGIN7,__API_AVAILABLE_BEGIN6, __API_AVAILABLE_BEGIN5, __API_AVAILABLE_BEGIN4, __API_AVAILABLE_BEGIN3, __API_AVAILABLE_BEGIN2, __API_AVAILABLE_BEGIN1, 0)(__VA_ARGS__)
|
||||
#define API_AVAILABLE_END _Pragma("clang attribute pop")
|
||||
|
||||
/*
|
||||
/*
|
||||
* API Deprecations
|
||||
*
|
||||
* Use to specify the release that a particular API became unavailable.
|
||||
@ -67,12 +80,17 @@
|
||||
* API_DEPRECATED_WITH_REPLACEMENT("SomeClassName", macos(10.4, 10.6), watchos(2.0, 3.0))
|
||||
*/
|
||||
|
||||
#define API_DEPRECATED(...) __API_DEPRECATED_MSG_GET_MACRO(__VA_ARGS__,__API_DEPRECATED_MSG5,__API_DEPRECATED_MSG4,__API_DEPRECATED_MSG3,__API_DEPRECATED_MSG2,__API_DEPRECATED_MSG1)(__VA_ARGS__)
|
||||
#define API_DEPRECATED_WITH_REPLACEMENT(...) __API_DEPRECATED_REP_GET_MACRO(__VA_ARGS__,__API_DEPRECATED_REP5,__API_DEPRECATED_REP4,__API_DEPRECATED_REP3,__API_DEPRECATED_REP2,__API_DEPRECATED_REP1)(__VA_ARGS__)
|
||||
#define API_DEPRECATED(...) __API_DEPRECATED_MSG_GET_MACRO(__VA_ARGS__,__API_DEPRECATED_MSG8,__API_DEPRECATED_MSG7, __API_DEPRECATED_MSG6,__API_DEPRECATED_MSG5,__API_DEPRECATED_MSG4,__API_DEPRECATED_MSG3,__API_DEPRECATED_MSG2,__API_DEPRECATED_MSG1, 0)(__VA_ARGS__)
|
||||
#define API_DEPRECATED_WITH_REPLACEMENT(...) __API_DEPRECATED_REP_GET_MACRO(__VA_ARGS__,__API_DEPRECATED_REP8,__API_DEPRECATED_REP7, __API_DEPRECATED_REP6,__API_DEPRECATED_REP5,__API_DEPRECATED_REP4,__API_DEPRECATED_REP3,__API_DEPRECATED_REP2,__API_DEPRECATED_REP1, 0)(__VA_ARGS__)
|
||||
|
||||
#define API_DEPRECATED_BEGIN(...) _Pragma("clang attribute push") __API_DEPRECATED_BEGIN_MSG_GET_MACRO(__VA_ARGS__,__API_DEPRECATED_BEGIN_MSG8,__API_DEPRECATED_BEGIN_MSG7, __API_DEPRECATED_BEGIN_MSG6, __API_DEPRECATED_BEGIN_MSG5, __API_DEPRECATED_BEGIN_MSG4, __API_DEPRECATED_BEGIN_MSG3, __API_DEPRECATED_BEGIN_MSG2, __API_DEPRECATED_BEGIN_MSG1, 0)(__VA_ARGS__)
|
||||
#define API_DEPRECATED_END _Pragma("clang attribute pop")
|
||||
|
||||
#define API_DEPRECATED_WITH_REPLACEMENT_BEGIN(...) _Pragma("clang attribute push") __API_DEPRECATED_BEGIN_REP_GET_MACRO(__VA_ARGS__,__API_DEPRECATED_BEGIN_REP8,__API_DEPRECATED_BEGIN_REP7, __API_DEPRECATED_BEGIN_REP6, __API_DEPRECATED_BEGIN_REP5, __API_DEPRECATED_BEGIN_REP4, __API_DEPRECATED_BEGIN_REP3, __API_DEPRECATED_BEGIN_REP2, __API_DEPRECATED_BEGIN_REP1, 0)(__VA_ARGS__)
|
||||
#define API_DEPRECATED_WITH_REPLACEMENT_END _Pragma("clang attribute pop")
|
||||
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* API Unavailability
|
||||
* Use to specify that an API is unavailable for a particular platform.
|
||||
*
|
||||
@ -81,6 +99,67 @@
|
||||
* API_UNAVAILABLE(watchos, tvos)
|
||||
*/
|
||||
|
||||
#define API_UNAVAILABLE(...) __API_UNAVAILABLE_GET_MACRO(__VA_ARGS__,__API_UNAVAILABLE3,__API_UNAVAILABLE2,__API_UNAVAILABLE1)(__VA_ARGS__)
|
||||
#define API_UNAVAILABLE(...) __API_UNAVAILABLE_GET_MACRO(__VA_ARGS__,__API_UNAVAILABLE7,__API_UNAVAILABLE6, __API_UNAVAILABLE5, __API_UNAVAILABLE4,__API_UNAVAILABLE3,__API_UNAVAILABLE2,__API_UNAVAILABLE1, 0)(__VA_ARGS__)
|
||||
|
||||
#define API_UNAVAILABLE_BEGIN(...) _Pragma("clang attribute push") __API_UNAVAILABLE_BEGIN_GET_MACRO(__VA_ARGS__,__API_UNAVAILABLE_BEGIN7,__API_UNAVAILABLE_BEGIN6, __API_UNAVAILABLE_BEGIN5, __API_UNAVAILABLE_BEGIN4, __API_UNAVAILABLE_BEGIN3, __API_UNAVAILABLE_BEGIN2, __API_UNAVAILABLE_BEGIN1, 0)(__VA_ARGS__)
|
||||
#define API_UNAVAILABLE_END _Pragma("clang attribute pop")
|
||||
#else
|
||||
|
||||
/*
|
||||
* Evaluate to nothing for compilers that don't support availability.
|
||||
*/
|
||||
|
||||
#define API_AVAILABLE(...)
|
||||
#define API_AVAILABLE_BEGIN(...)
|
||||
#define API_AVAILABLE_END
|
||||
#define API_DEPRECATED(...)
|
||||
#define API_DEPRECATED_WITH_REPLACEMENT(...)
|
||||
#define API_DEPRECATED_BEGIN(...)
|
||||
#define API_DEPRECATED_END
|
||||
#define API_DEPRECATED_WITH_REPLACEMENT_BEGIN(...)
|
||||
#define API_DEPRECATED_WITH_REPLACEMENT_END
|
||||
#define API_UNAVAILABLE(...)
|
||||
#define API_UNAVAILABLE_BEGIN(...)
|
||||
#define API_UNAVAILABLE_END
|
||||
#endif /* __has_attribute(availability) */
|
||||
#else
|
||||
|
||||
/*
|
||||
* Evaluate to nothing for compilers that don't support clang language extensions.
|
||||
*/
|
||||
|
||||
#define API_AVAILABLE(...)
|
||||
#define API_AVAILABLE_BEGIN(...)
|
||||
#define API_AVAILABLE_END
|
||||
#define API_DEPRECATED(...)
|
||||
#define API_DEPRECATED_WITH_REPLACEMENT(...)
|
||||
#define API_DEPRECATED_BEGIN(...)
|
||||
#define API_DEPRECATED_END
|
||||
#define API_DEPRECATED_WITH_REPLACEMENT_BEGIN(...)
|
||||
#define API_DEPRECATED_WITH_REPLACEMENT_END
|
||||
#define API_UNAVAILABLE(...)
|
||||
#define API_UNAVAILABLE_BEGIN(...)
|
||||
#define API_UNAVAILABLE_END
|
||||
#endif /* #if defined(__has_feature) && defined(__has_attribute) */
|
||||
|
||||
#if __has_include(<AvailabilityProhibitedInternal.h>)
|
||||
#include <AvailabilityProhibitedInternal.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If SPI decorations have not been defined elsewhere, disable them.
|
||||
*/
|
||||
|
||||
#ifndef SPI_AVAILABLE
|
||||
#define SPI_AVAILABLE(...)
|
||||
#endif
|
||||
|
||||
#ifndef SPI_DEPRECATED
|
||||
#define SPI_DEPRECATED(...)
|
||||
#endif
|
||||
|
||||
#ifndef SPI_DEPRECATED_WITH_REPLACEMENT
|
||||
#define SPI_DEPRECATED_WITH_REPLACEMENT(...)
|
||||
#endif
|
||||
|
||||
#endif /* __OS_AVAILABILITY__ */
|
||||
|
31
platform-include/sys/_types/_u_int16_t.h
Normal file
31
platform-include/sys/_types/_u_int16_t.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2012 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@
|
||||
*/
|
||||
#ifndef _U_INT16_T
|
||||
#define _U_INT16_T
|
||||
typedef unsigned short u_int16_t;
|
||||
#endif /* _U_INT16_T */
|
31
platform-include/sys/_types/_u_int32_t.h
Normal file
31
platform-include/sys/_types/_u_int32_t.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2012 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@
|
||||
*/
|
||||
#ifndef _U_INT32_T
|
||||
#define _U_INT32_T
|
||||
typedef unsigned int u_int32_t;
|
||||
#endif /* _U_INT32_T */
|
31
platform-include/sys/_types/_u_int64_t.h
Normal file
31
platform-include/sys/_types/_u_int64_t.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2012 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@
|
||||
*/
|
||||
#ifndef _U_INT64_T
|
||||
#define _U_INT64_T
|
||||
typedef unsigned long long u_int64_t;
|
||||
#endif /* _U_INT64_T */
|
31
platform-include/sys/_types/_u_int8_t.h
Normal file
31
platform-include/sys/_types/_u_int8_t.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 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@
|
||||
*/
|
||||
#ifndef _U_INT8_T
|
||||
#define _U_INT8_T
|
||||
typedef unsigned char u_int8_t;
|
||||
#endif /* _U_INT8_T */
|
@ -363,6 +363,13 @@
|
||||
|
||||
#define F_ADDFILESIGS_RETURN 97 /* Add signature from same file, return end offset in structure on sucess */
|
||||
#define F_CHECK_LV 98 /* Check if Library Validation allows this Mach-O file to be mapped into the calling process */
|
||||
#define F_PUNCHHOLE 99 /* Deallocate a range of the file */
|
||||
|
||||
#define F_TRIM_ACTIVE_FILE 100 /* Trim an active file */
|
||||
|
||||
#define F_SPECULATIVE_READ 101 /* Synchronous advisory read fcntl for regular and compressed file */
|
||||
|
||||
#define F_GETPATH_NOFIRMLINK 102 /* return the full path without firmlinks of the fd */
|
||||
|
||||
|
||||
// FS-specific fcntl()'s numbers begin at 0x00010000 and go up
|
||||
@ -601,6 +608,28 @@ typedef struct fstore {
|
||||
off_t fst_bytesalloc; /* OUT: number of bytes allocated */
|
||||
} fstore_t;
|
||||
|
||||
/* fpunchhole_t used by F_PUNCHHOLE */
|
||||
typedef struct fpunchhole {
|
||||
unsigned int fp_flags; /* unused */
|
||||
unsigned int reserved; /* (to maintain 8-byte alignment) */
|
||||
off_t fp_offset; /* IN: start of the region */
|
||||
off_t fp_length; /* IN: size of the region */
|
||||
} fpunchhole_t;
|
||||
|
||||
/* factive_file_trim_t used by F_TRIM_ACTIVE_FILE */
|
||||
typedef struct ftrimactivefile {
|
||||
off_t fta_offset; /* IN: start of the region */
|
||||
off_t fta_length; /* IN: size of the region */
|
||||
} ftrimactivefile_t;
|
||||
|
||||
/* fspecread_t used by F_SPECULATIVE_READ */
|
||||
typedef struct fspecread {
|
||||
unsigned int fsr_flags; /* IN: flags word */
|
||||
unsigned int reserved; /* to maintain 8-byte alignment */
|
||||
off_t fsr_offset; /* IN: start of the region */
|
||||
off_t fsr_length; /* IN: size of the region */
|
||||
} fspecread_t;
|
||||
|
||||
/* fbootstraptransfer_t used by F_READBOOTSTRAP and F_WRITEBOOTSTRAP commands */
|
||||
|
||||
typedef struct fbootstraptransfer {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
|
||||
* Copyright (c) 2000-2019 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
|
||||
*
|
||||
@ -119,6 +119,36 @@
|
||||
#define MAP_HASSEMAPHORE 0x0200 /* region may contain semaphores */
|
||||
#define MAP_NOCACHE 0x0400 /* don't cache pages for this mapping */
|
||||
#define MAP_JIT 0x0800 /* Allocate a region that will be used for JIT purposes */
|
||||
|
||||
/*
|
||||
* Mapping type
|
||||
*/
|
||||
#define MAP_FILE 0x0000 /* map from file (default) */
|
||||
#define MAP_ANON 0x1000 /* allocated from memory, swap space */
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
|
||||
/*
|
||||
* The MAP_RESILIENT_* flags can be used when the caller wants to map some
|
||||
* possibly unreliable memory and be able to access it safely, possibly
|
||||
* getting the wrong contents rather than raising any exception.
|
||||
* For safety reasons, such mappings have to be read-only (PROT_READ access
|
||||
* only).
|
||||
*
|
||||
* MAP_RESILIENT_CODESIGN:
|
||||
* accessing this mapping will not generate code-signing violations,
|
||||
* even if the contents are tainted.
|
||||
* MAP_RESILIENT_MEDIA:
|
||||
* accessing this mapping will not generate an exception if the contents
|
||||
* are not available (unreachable removable or remote media, access beyond
|
||||
* end-of-file, ...). Missing contents will be replaced with zeroes.
|
||||
*/
|
||||
#define MAP_RESILIENT_CODESIGN 0x2000 /* no code-signing failures */
|
||||
#define MAP_RESILIENT_MEDIA 0x4000 /* no backing-store failures */
|
||||
|
||||
#if !defined(CONFIG_EMBEDDED)
|
||||
#define MAP_32BIT 0x8000 /* Return virtual addresses <4G only: Requires entitlement */
|
||||
#endif /* !defined(CONFIG_EMBEDDED) */
|
||||
|
||||
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
|
||||
|
||||
/*
|
||||
@ -143,11 +173,6 @@
|
||||
#define MS_KILLPAGES 0x0004 /* invalidate pages, leave mapped */
|
||||
#define MS_DEACTIVATE 0x0008 /* deactivate pages, leave mapped */
|
||||
|
||||
/*
|
||||
* Mapping type
|
||||
*/
|
||||
#define MAP_FILE 0x0000 /* map from file (default) */
|
||||
#define MAP_ANON 0x1000 /* allocated from memory, swap space */
|
||||
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
|
||||
|
||||
|
||||
@ -171,6 +196,7 @@
|
||||
#define MADV_FREE_REUSABLE 7 /* pages can be reused (by anyone) */
|
||||
#define MADV_FREE_REUSE 8 /* caller wants to reuse those pages */
|
||||
#define MADV_CAN_REUSE 9
|
||||
#define MADV_PAGEOUT 10 /* page out now (internal only) */
|
||||
|
||||
/*
|
||||
* Return bits from mincore
|
||||
@ -180,6 +206,9 @@
|
||||
#define MINCORE_MODIFIED 0x4 /* Page has been modified by us */
|
||||
#define MINCORE_REFERENCED_OTHER 0x8 /* Page has been referenced */
|
||||
#define MINCORE_MODIFIED_OTHER 0x10 /* Page has been modified */
|
||||
#define MINCORE_PAGED_OUT 0x20 /* Page has been paged out */
|
||||
#define MINCORE_COPIED 0x40 /* Page has been copied */
|
||||
#define MINCORE_ANONYMOUS 0x80 /* Page belongs to an anonymous object */
|
||||
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
|
||||
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
* System call switch table.
|
||||
*
|
||||
* DO NOT EDIT-- this file is automatically generated.
|
||||
* created from bsd/kern/syscalls.master
|
||||
* created from /BuildRoot/Library/Caches/com.apple.xbs/Sources/xnu/xnu-6153.41.3/bsd/kern/syscalls.master
|
||||
*/
|
||||
|
||||
#ifndef _SYS_SYSCALL_H_
|
||||
@ -254,7 +254,7 @@
|
||||
/* 214 */
|
||||
/* 215 */
|
||||
#define SYS_open_dprotected_np 216
|
||||
/* 217 old statv */
|
||||
#define SYS_fsgetpath_ext 217
|
||||
/* 218 old lstatv */
|
||||
/* 219 old fstatv */
|
||||
#define SYS_getattrlist 220
|
||||
@ -540,18 +540,18 @@
|
||||
#define SYS_getentropy 500
|
||||
#define SYS_necp_open 501
|
||||
#define SYS_necp_client_action 502
|
||||
/* 503 */
|
||||
/* 504 */
|
||||
/* 505 */
|
||||
/* 506 */
|
||||
/* 507 */
|
||||
/* 508 */
|
||||
/* 509 */
|
||||
/* 510 */
|
||||
/* 511 */
|
||||
/* 512 */
|
||||
/* 513 */
|
||||
/* 514 */
|
||||
#define SYS___nexus_open 503
|
||||
#define SYS___nexus_register 504
|
||||
#define SYS___nexus_deregister 505
|
||||
#define SYS___nexus_create 506
|
||||
#define SYS___nexus_destroy 507
|
||||
#define SYS___nexus_get_opt 508
|
||||
#define SYS___nexus_set_opt 509
|
||||
#define SYS___channel_open 510
|
||||
#define SYS___channel_get_info 511
|
||||
#define SYS___channel_sync 512
|
||||
#define SYS___channel_get_opt 513
|
||||
#define SYS___channel_set_opt 514
|
||||
#define SYS_ulock_wait 515
|
||||
#define SYS_ulock_wake 516
|
||||
#define SYS_fclonefileat 517
|
||||
@ -567,9 +567,12 @@
|
||||
#define SYS_ntp_adjtime 527
|
||||
#define SYS_ntp_gettime 528
|
||||
#define SYS_os_fault_with_payload 529
|
||||
/* 530 */
|
||||
/* 531 */
|
||||
#define SYS_MAXSYSCALL 532
|
||||
#define SYS_kqueue_workloop_ctl 530
|
||||
#define SYS___mach_bridge_remote_time 531
|
||||
#define SYS_coalition_ledger 532
|
||||
#define SYS_log_data 533
|
||||
#define SYS_memorystatus_available_memory 534
|
||||
#define SYS_MAXSYSCALL 535
|
||||
#define SYS_invalid 63
|
||||
|
||||
#endif /* __APPLE_API_PRIVATE */
|
||||
|
10
src/dyld/.gitignore
vendored
Normal file
10
src/dyld/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
build
|
||||
DerivedData
|
||||
dyld.xcodeproj/kledzik.mode1v3
|
||||
dyld.xcodeproj/kledzik.pbxuser
|
||||
dyld.xcodeproj/project.xcworkspace/
|
||||
dyld.xcodeproj/xcuserdata/
|
||||
dyld.xcodeproj/xcshareddata/
|
||||
.DS_Store
|
||||
.pyc
|
||||
|
@ -9,8 +9,9 @@ endif(COMMAND cmake_policy)
|
||||
include (darling_exe)
|
||||
|
||||
add_definitions(-nostdinc)
|
||||
add_definitions(-D_LIBCPP_NO_EXCEPTIONS=1)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -include ${CMAKE_SOURCE_DIR}/src/duct/include/CrashReporterClient.h")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wno-availability -include ${CMAKE_SOURCE_DIR}/src/duct/include/CrashReporterClient.h")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_SAVED "${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -nostdlib -Wl,-bind_at_load -Wl,-flat_namespace -Wl,-undefined,suppress")
|
||||
|
||||
@ -28,11 +29,18 @@ include_directories(${CMAKE_SOURCE_DIR}/src/kernel/emulation/linux/misc)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/sandbox)
|
||||
include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src/external/libcxx/include)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src/libc/include)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src/external/libclosure)
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/src/external/libclosure
|
||||
${CMAKE_SOURCE_DIR}/src/libutil
|
||||
)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/launch-cache)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/mach-o)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/mach-o
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/dyld3/shared-cache
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/dyld3
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
set(DYLIB_INSTALL_NAME "/usr/lib/system/libdyld.dylib")
|
||||
add_circular(system_dyld FAT
|
||||
@ -46,6 +54,26 @@ add_circular(system_dyld FAT
|
||||
src/dyld_process_info.cpp
|
||||
src/dyld_process_info_notify.cpp
|
||||
src/start_glue.S
|
||||
dyld3/AllImages.cpp
|
||||
dyld3/APIs.cpp
|
||||
dyld3/APIs_macOS.cpp
|
||||
dyld3/ClosureBuilder.cpp
|
||||
dyld3/Closure.cpp
|
||||
dyld3/ClosureFileSystemPhysical.cpp
|
||||
dyld3/ClosurePrinter.cpp
|
||||
dyld3/ClosureWriter.cpp
|
||||
dyld3/Diagnostics.cpp
|
||||
dyld3/shared-cache/DyldSharedCache.cpp
|
||||
#dyld3/JSONReader.mm
|
||||
dyld3/libdyldEntryVector.cpp
|
||||
dyld3/Loading.cpp
|
||||
dyld3/Logging.cpp
|
||||
dyld3/MachOAnalyzer.cpp
|
||||
dyld3/MachOFile.cpp
|
||||
dyld3/MachOLoaded.cpp
|
||||
dyld3/PathOverrides.cpp
|
||||
dyld3/Tracing.cpp
|
||||
|
||||
SIBLINGS
|
||||
system_c system_kernel compiler_rt platform
|
||||
DEPENDENCIES
|
||||
@ -54,7 +82,7 @@ add_circular(system_dyld FAT
|
||||
set_target_properties(system_dyld PROPERTIES
|
||||
OUTPUT_NAME "dyld")
|
||||
set_property(TARGET system_dyld_obj APPEND_STRING PROPERTY
|
||||
COMPILE_FLAGS " -fno-exceptions -fno-rtti")
|
||||
COMPILE_FLAGS " -fno-exceptions -fno-rtti -DBUILDING_LIBDYLD=1")
|
||||
set_property(TARGET system_dyld APPEND_STRING PROPERTY
|
||||
LINK_FLAGS " -Wl,-compatibility_version,1.0.0 -Wl,-current_version,421.1.0")
|
||||
#target_link_libraries(system_dyld PRIVATE platform_static32 platform_static64 system_c system_kernel compiler_rt launch)
|
||||
@ -62,13 +90,12 @@ set_property(TARGET system_dyld APPEND_STRING PROPERTY
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS_SAVED} -nostdlib")
|
||||
|
||||
add_executable(system_loader
|
||||
src/dyld2.cpp
|
||||
src/dyldAPIs.cpp
|
||||
src/dyld.cpp
|
||||
src/dyld_gdb.cpp
|
||||
src/dyld_debugger.cpp
|
||||
src/dyldInitialization.cpp
|
||||
src/dyldLock.cpp
|
||||
src/dyldNew.cpp
|
||||
#src/dyld_process_info.cpp
|
||||
#src/dyld_process_info_notify.cpp
|
||||
src/ImageLoader.cpp
|
||||
src/ImageLoaderMachOClassic.cpp
|
||||
src/ImageLoaderMachOCompressed.cpp
|
||||
@ -80,11 +107,33 @@ add_executable(system_loader
|
||||
src/stub_binding_helper.S
|
||||
src/start_glue.S
|
||||
hell.c
|
||||
dyld3/BootArgs.cpp
|
||||
dyld3/ClosureBuilder.cpp
|
||||
dyld3/Closure.cpp
|
||||
dyld3/ClosureFileSystemNull.cpp
|
||||
dyld3/ClosureFileSystemPhysical.cpp
|
||||
#dyld3/ClosurePrinter.cpp
|
||||
dyld3/ClosureWriter.cpp
|
||||
dyld3/Tracing.cpp
|
||||
dyld3/Loading.cpp
|
||||
dyld3/Diagnostics.cpp
|
||||
dyld3/SharedCacheRuntime.cpp
|
||||
dyld3/shared-cache/DyldSharedCache.cpp
|
||||
#dyld3/shared-cache/FileUtils.cpp
|
||||
dyld3/MachOAnalyzer.cpp
|
||||
dyld3/MachOFile.cpp
|
||||
dyld3/MachOLoaded.cpp
|
||||
dyld3/PathOverrides.cpp
|
||||
dyld3/SharedCacheRuntime.cpp
|
||||
sandbox-dummy.c
|
||||
version.c # Too make the .exp file work
|
||||
)
|
||||
|
||||
use_ld64(system_loader)
|
||||
set_target_properties(system_loader PROPERTIES OUTPUT_NAME "dyld")
|
||||
set_property(TARGET system_loader APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-dylinker -Wl,-dead_strip -nostdlib -Wl,-e,__dyld_start -Wl,-image_base,0x1fe00000")
|
||||
set_property(TARGET system_loader APPEND_STRING PROPERTY
|
||||
COMPILE_FLAGS " -DBUILDING_DYLD=1 -gfull -fno-pic")
|
||||
set_property(TARGET system_loader APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-dylinker -Wl,-dead_strip -Wl,-data_const -nostdlib -Wl,-e,__dyld_start -Wl,-fixup_chains -Wl,-image_base,0x1fe00000 -Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/src/dyld.exp")
|
||||
target_link_libraries(system_loader libc_static system_blocks_static
|
||||
cxx_static
|
||||
unwind_static system_kernel_static system_m_static cxxabi_static
|
||||
|
102
src/dyld/bin/expand.rb
Executable file
102
src/dyld/bin/expand.rb
Executable file
@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'yaml'
|
||||
|
||||
if ENV["DRIVERKITROOT"]
|
||||
$availCmd = ENV["SDKROOT"] + ENV["DRIVERKITROOT"] + "/usr/local/libexec/availability.pl";
|
||||
else
|
||||
$availCmd = ENV["SDKROOT"] + "/usr/local/libexec/availability.pl";
|
||||
end
|
||||
|
||||
def versionString(vers)
|
||||
uvers = ""
|
||||
if vers =~ /^(\d+)$/
|
||||
uvers = "#{$1}_0"
|
||||
elsif vers =~ /^(\d+).(\d+)$/
|
||||
uvers = "#{$1}_#{$2}"
|
||||
elsif vers =~ /^(\d+).(\d+).(\d+)$/
|
||||
if $3 == 0
|
||||
uvers = "#{$1}_#{$2}"
|
||||
else
|
||||
uvers = "#{$1}_#{$2}_#{$3}"
|
||||
end
|
||||
end
|
||||
uvers
|
||||
end
|
||||
|
||||
def versionHex(vers)
|
||||
major = 0;
|
||||
minor = 0;
|
||||
revision = 0;
|
||||
|
||||
if vers =~ /^(\d+)$/
|
||||
major = $1.to_i;
|
||||
elsif vers =~ /^(\d+).(\d+)$/
|
||||
major = $1.to_i;
|
||||
minor = $2.to_i;
|
||||
elsif vers =~ /^(\d+).(\d+).(\d+)$/
|
||||
major = $1.to_i;
|
||||
minor = $2.to_i;
|
||||
revision = $3.to_i;
|
||||
end
|
||||
"0x00#{major.to_s(16).rjust(2, '0')}#{minor.to_s(16).rjust(2, '0')}#{revision.to_s(16).rjust(2, '0')}"
|
||||
end
|
||||
|
||||
def expandVersions(prefix, arg)
|
||||
versionList = `#{$availCmd} #{arg}`.gsub(/\s+/m, ' ').strip.split(" ")
|
||||
versionList.each { |version|
|
||||
puts "#define #{prefix}#{versionString(version)}".ljust(48, ' ') + versionHex(version)
|
||||
}
|
||||
end
|
||||
|
||||
def expandPlatformVersions(prefix, platform, arg)
|
||||
versionList = `#{$availCmd} #{arg}`.gsub(/\s+/m, ' ').strip.split(" ")
|
||||
versionList.each { |version|
|
||||
puts "static dyld_build_version_t dyld_platform_version_#{prefix}_#{versionString(version)}".ljust(72, ' ') + "= { .platform = #{platform}, .version = #{versionHex(version)} };"
|
||||
}
|
||||
end
|
||||
|
||||
def versionSetsForOSes(versionSets, key, platform, target)
|
||||
puts "#if #{target}"
|
||||
versionSets.each { |k,v|
|
||||
puts "#define dyld_#{k}_os_versions dyld_platform_version_#{platform}_#{versionString(v[key].to_s)}"
|
||||
}
|
||||
puts "#endif /* #{target} */"
|
||||
end
|
||||
|
||||
def expandVersionSets()
|
||||
versionSets = YAML.load(`#{$availCmd} --sets`)
|
||||
versionSetsForOSes(versionSets, "macos", "macOS", "TARGET_OS_OSX")
|
||||
versionSetsForOSes(versionSets, "ios", "iOS", "TARGET_OS_IOS")
|
||||
versionSetsForOSes(versionSets, "tvos", "tvOS", "TARGET_OS_TV")
|
||||
versionSetsForOSes(versionSets, "watchos", "watchOS", "TARGET_OS_WATCH")
|
||||
versionSetsForOSes(versionSets, "bridgeos", "bridgeOS", "TARGET_OS_BRIDGE")
|
||||
end
|
||||
|
||||
ARGF.each do |line|
|
||||
if line =~ /^\/\/\@MAC_VERSION_DEFS\@$/
|
||||
expandVersions("DYLD_MACOSX_VERSION_", "--macosx")
|
||||
elsif line =~ /^\/\/\@IOS_VERSION_DEFS\@$/
|
||||
expandVersions("DYLD_IOS_VERSION_", "--ios")
|
||||
elsif line =~ /^\/\/\@WATCHOS_VERSION_DEFS\@$/
|
||||
expandVersions("DYLD_WATCHOS_VERSION_", "--watchos")
|
||||
elsif line =~ /^\/\/\@TVOS_VERSION_DEFS\@$/
|
||||
expandVersions("DYLD_TVOS_VERSION_", "--appletvos")
|
||||
elsif line =~ /^\/\/\@BRIDGEOS_VERSION_DEFS\@$/
|
||||
expandVersions("DYLD_BRIDGEOS_VERSION_", "--bridgeos")
|
||||
elsif line =~ /^\/\/\@MACOS_PLATFORM_VERSION_DEFS\@$/
|
||||
expandPlatformVersions("macOS", "PLATFORM_MACOS", "--macosx")
|
||||
elsif line =~ /^\/\/\@IOS_PLATFORM_VERSION_DEFS\@$/
|
||||
expandPlatformVersions("iOS", "PLATFORM_IOS", "--ios")
|
||||
elsif line =~ /^\/\/\@WATCHOS_PLATFORM_VERSION_DEFS\@$/
|
||||
expandPlatformVersions("watchOS", "PLATFORM_WATCHOS", "--watchos")
|
||||
elsif line =~ /^\/\/\@TVOS_PLATFORM_VERSION_DEFS\@$/
|
||||
expandPlatformVersions("tvOS", "PLATFORM_TVOS", "--appletvos")
|
||||
elsif line =~ /^\/\/\@BRIDGEOS_PLATFORM_VERSION_DEFS\@$/
|
||||
expandPlatformVersions("bridgeOS", "PLATFORM_BRIDGEOS", "--bridgeos")
|
||||
elsif line =~ /^\/\/\@VERSION_SET_DEFS\@$/
|
||||
expandVersionSets()
|
||||
else
|
||||
puts line
|
||||
end
|
||||
end
|
2
src/dyld/configs/closured.xcconfig
Normal file
2
src/dyld/configs/closured.xcconfig
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
CODE_SIGN_ENTITLEMENTS[sdk=embedded*] = dyld3/closured/closured_entitlements.plist
|
@ -4,6 +4,11 @@ ENTRY[sdk=*simulator*] = -Wl,-e,_start_sim
|
||||
ENTRY[sdk=iphoneos*] = -Wl,-e,__dyld_start
|
||||
ENTRY[sdk=macosx*] = -Wl,-e,__dyld_start
|
||||
|
||||
OTHER_CODE_SIGN_FLAGS[sdk=*simulator*] = --entitlements $(SRCROOT)/dyld_sim-entitlements.plist
|
||||
OTHER_CODE_SIGN_FLAGS[sdk=iphoneos*] =
|
||||
OTHER_CODE_SIGN_FLAGS[sdk=macosx*] =
|
||||
|
||||
|
||||
EXPORTED_SYMBOLS_FILE[sdk=*simulator*] = $(SRCROOT)/src/dyld_sim.exp
|
||||
EXPORTED_SYMBOLS_FILE[sdk=iphoneos*] = $(SRCROOT)/src/dyld.exp
|
||||
EXPORTED_SYMBOLS_FILE[sdk=macosx*] = $(SRCROOT)/src/dyld.exp
|
||||
@ -13,3 +18,9 @@ PRODUCT_NAME[sdk=iphoneos*] = dyld
|
||||
PRODUCT_NAME[sdk=macosx*] = dyld
|
||||
|
||||
INSTALL_PATH = /usr/lib
|
||||
|
||||
//:configuration = Debug
|
||||
GCC_PREPROCESSOR_DEFINITIONS = DYLD_VERSION=$(RC_ProjectSourceVersion) BUILDING_DYLD=1 DEBUG=1
|
||||
|
||||
//:configuration = Release
|
||||
GCC_PREPROCESSOR_DEFINITIONS = DYLD_VERSION=$(RC_ProjectSourceVersion) BUILDING_DYLD=1
|
||||
|
@ -1,8 +1,8 @@
|
||||
|
||||
LIBSYSTEM_LIBS[sdk=*simulator*] = -Wl,-upward-lsystem_sim_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_sim_pthread -Wl,-upward-lxpc -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_sim_kernel -Wl,-upward-lsystem_sandbox -Wl,-upward-ldispatch
|
||||
LIBSYSTEM_LIBS[sdk=iphoneos*] = -Wl,-upward-lsystem_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_pthread -Wl,-upward-lxpc -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_kernel -Wl,-upward-lsystem_sandbox -Wl,-upward-ldispatch
|
||||
LIBSYSTEM_LIBS[sdk=macosx*] = -Wl,-upward-lsystem_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_pthread -Wl,-upward-lxpc -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_kernel -Wl,-upward-lsystem_sandbox -Wl,-upward-ldispatch
|
||||
LIBSYSTEM_LIBS[sdk=*simulator*] = -Wl,-upward-lsystem_sim_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_sim_pthread -Wl,-upward-lxpc -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_sim_kernel -Wl,-upward-lsystem_sandbox -Wl,-upward-ldispatch -Wl,-upward-lcorecrypto -Wl,-upward-lcompiler_rt
|
||||
LIBSYSTEM_LIBS[sdk=embedded*] = -Wl,-upward-lsystem_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_pthread -Wl,-upward-lxpc -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_kernel -Wl,-upward-lsystem_sandbox -Wl,-upward-ldispatch -Wl,-upward-lcorecrypto -Wl,-upward-lcompiler_rt
|
||||
LIBSYSTEM_LIBS[sdk=macosx*] = -Wl,-upward-lsystem_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_pthread -Wl,-upward-lxpc -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_kernel -Wl,-upward-lsystem_sandbox -Wl,-upward-ldispatch -Wl,-upward-lcorecrypto -Wl,-upward-lcompiler_rt
|
||||
LIBSYSTEM_LIBS[sdk=driverkit*] = -Wl,-upward-lsystem_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_pthread -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_kernel -Wl,-upward-lcompiler_rt
|
||||
|
||||
INSTALL_PATH = /usr/lib/system
|
||||
|
||||
|
||||
|
@ -1,18 +1 @@
|
||||
|
||||
//:configuration = Release
|
||||
LOCAL_YES = local
|
||||
|
||||
//:configuration = Release
|
||||
LOCAL = $(LOCAL_$(RC_PURPLE))
|
||||
|
||||
//:configuration = Release
|
||||
INSTALL_PATH = $(INSTALL_LOCATION)/usr/$(LOCAL)/bin
|
||||
|
||||
// don't iOS tool
|
||||
MY_RELEASE_CODE_SIGN_IDENTITY_YES =
|
||||
MY_RELEASE_CODE_SIGN_IDENTITY_ = -
|
||||
CODE_SIGN_IDENTITY = $(MY_RELEASE_CODE_SIGN_IDENTITY_$(RC_PURPLE))
|
||||
|
||||
|
||||
CODE_SIGN_ENTITLEMENTS = launch-cache/update_dyld_shared_cache_entitlements.plist
|
||||
|
||||
|
9
src/dyld/configs/update_dyld_sim_shared_cache.xcconfig
Normal file
9
src/dyld/configs/update_dyld_sim_shared_cache.xcconfig
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
#include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/PlatformSupportHost.xcconfig"
|
||||
|
||||
|
||||
//:configuration = Debug
|
||||
GCC_PREPROCESSOR_DEFINITIONS = BUILDING_CACHE_BUILDER=1 DEBUG=1
|
||||
|
||||
//:configuration = Release
|
||||
GCC_PREPROCESSOR_DEFINITIONS = BUILDING_CACHE_BUILDER=1
|
10
src/dyld/doc/man/man1/closured.1
Normal file
10
src/dyld/doc/man/man1/closured.1
Normal file
@ -0,0 +1,10 @@
|
||||
.Dd 3/1/17
|
||||
.Dt closured 1
|
||||
.Os Darwin
|
||||
.Sh NAME
|
||||
.Nm closured
|
||||
.Nd Daemon for building dyld closures.
|
||||
.Sh SYNOPSIS
|
||||
.Nm closured is a launchd managed daemon.
|
||||
.Sh DESCRIPTION
|
||||
.Nm closured is a launchd managed daemon.
|
@ -1,6 +1,6 @@
|
||||
.TH DYLD 1 "December 14, 2009" "Apple Inc."
|
||||
.TH DYLD 1 "June 1, 2017" "Apple Inc."
|
||||
.SH NAME
|
||||
dyld \- the dynamic link editor
|
||||
dyld \- the dynamic linker
|
||||
.SH SYNOPSIS
|
||||
DYLD_FRAMEWORK_PATH
|
||||
.br
|
||||
@ -16,8 +16,6 @@ DYLD_VERSIONED_LIBRARY_PATH
|
||||
.br
|
||||
DYLD_PRINT_TO_FILE
|
||||
.br
|
||||
DYLD_ROOT_PATH
|
||||
.br
|
||||
DYLD_SHARED_REGION
|
||||
.br
|
||||
DYLD_INSERT_LIBRARIES
|
||||
@ -32,8 +30,6 @@ DYLD_PRINT_ENV
|
||||
.br
|
||||
DYLD_PRINT_LIBRARIES
|
||||
.br
|
||||
DYLD_PRINT_LIBRARIES_POST_LAUNCH
|
||||
.br
|
||||
DYLD_BIND_AT_LAUNCH
|
||||
.br
|
||||
DYLD_DISABLE_DOFS
|
||||
@ -58,8 +54,12 @@ DYLD_SHARED_CACHE_DIR
|
||||
.br
|
||||
DYLD_SHARED_CACHE_DONT_VALIDATE
|
||||
.SH DESCRIPTION
|
||||
The dynamic linker uses the following environment variables.
|
||||
They affect any program that uses the dynamic linker.
|
||||
The dynamic linker checks the following environment variables during the launch
|
||||
of each process.
|
||||
.br
|
||||
.br
|
||||
Note: If System Integrity Protection is enabled, these environment variables are ignored
|
||||
when executing binaries protected by System Integrity Protection.
|
||||
.TP
|
||||
.B DYLD_FRAMEWORK_PATH
|
||||
This is a colon separated list of directories that contain frameworks.
|
||||
@ -67,35 +67,29 @@ The dynamic linker searches these directories before it searches for the
|
||||
framework by its install name.
|
||||
It allows you to test new versions of existing
|
||||
frameworks. (A framework is a library install name that ends in the form
|
||||
XXX.framework/Versions/YYY/XXX or XXX.framework/XXX, where XXX and YYY are any
|
||||
XXX.framework/Versions/A/XXX or XXX.framework/XXX, where XXX and A are any
|
||||
name.)
|
||||
.IP
|
||||
For each framework that a program uses, the dynamic linker looks for the
|
||||
framework in each directory in
|
||||
.SM DYLD_FRAMEWORK_PATH
|
||||
in turn. If it looks in all the directories and can't find the framework, it
|
||||
searches the directories in
|
||||
.SM DYLD_LIBRARY_PATH
|
||||
in turn. If it still can't find the framework, it then searches
|
||||
.SM DYLD_FALLBACK_FRAMEWORK_PATH
|
||||
and
|
||||
.SM DYLD_FALLBACK_LIBRARY_PATH
|
||||
in turn.
|
||||
in turn. If it looks in all those directories and can't find the framework, it
|
||||
uses whatever it would have loaded if DYLD_FRAMEWORK_PATH had not been set.
|
||||
.IP
|
||||
Use the
|
||||
.B \-L
|
||||
option to
|
||||
.IR otool (1).
|
||||
.IR otool (1)
|
||||
to discover the frameworks and shared libraries that the executable
|
||||
is linked against.
|
||||
.TP
|
||||
.B DYLD_FALLBACK_FRAMEWORK_PATH
|
||||
This is a colon separated list of directories that contain frameworks.
|
||||
It is used as the default location for frameworks not found in their install
|
||||
path.
|
||||
If a framework is not found at its install path, dyld uses this
|
||||
as a list of directories to search for the framework.
|
||||
|
||||
By default, it is set to
|
||||
/Library/Frameworks:/Network/Library/Frameworks:/System/Library/Frameworks
|
||||
/Library/Frameworks:/System/Library/Frameworks
|
||||
.TP
|
||||
.B DYLD_VERSIONED_FRAMEWORK_PATH
|
||||
This is a colon separated list of directories that contain potential override frameworks.
|
||||
@ -104,7 +98,7 @@ each framework found dyld looks at its LC_ID_DYLIB and gets the current_version
|
||||
and install name. Dyld then looks for the framework at the install name path.
|
||||
Whichever has the larger current_version value will be used in the process whenever
|
||||
a framework with that install name is required. This is similar to DYLD_FRAMEWORK_PATH
|
||||
except instead of always overriding, it only overrides is the supplied framework is newer.
|
||||
except instead of always overriding, it only overrides if the supplied framework is newer.
|
||||
Note: dyld does not check the framework's Info.plist to find its version. Dyld only
|
||||
checks the -currrent_version number supplied when the framework was created.
|
||||
.TP
|
||||
@ -114,28 +108,23 @@ dynamic linker searches these directories before it searches the default
|
||||
locations for libraries. It allows you to test new versions of existing
|
||||
libraries.
|
||||
.IP
|
||||
For each library that a program uses, the dynamic linker looks for it in each
|
||||
directory in
|
||||
.SM DYLD_LIBRARY_PATH
|
||||
in turn. If it still can't find the library, it then searches
|
||||
.SM DYLD_FALLBACK_FRAMEWORK_PATH
|
||||
and
|
||||
.SM DYLD_FALLBACK_LIBRARY_PATH
|
||||
in turn.
|
||||
For each dylib that a program uses, the dynamic linker looks for its
|
||||
leaf name in each directory in
|
||||
.SM DYLD_LIBRARY_PATH.
|
||||
.IP
|
||||
Use the
|
||||
.B \-L
|
||||
option to
|
||||
.IR otool (1).
|
||||
.IR otool (1)
|
||||
to discover the frameworks and shared libraries that the executable
|
||||
is linked against.
|
||||
.TP
|
||||
.B DYLD_FALLBACK_LIBRARY_PATH
|
||||
This is a colon separated list of directories that contain libraries.
|
||||
It is used as the default location for libraries not found in their install
|
||||
path.
|
||||
If a dylib is not found at its install path,
|
||||
dyld uses this as a list of directories to search for the dylib.
|
||||
By default, it is set
|
||||
to $(HOME)/lib:/usr/local/lib:/lib:/usr/lib.
|
||||
to /usr/local/lib:/usr/lib.
|
||||
.TP
|
||||
.B DYLD_VERSIONED_LIBRARY_PATH
|
||||
This is a colon separated list of directories that contain potential override libraries.
|
||||
@ -152,10 +141,6 @@ logging output (triggered by DYLD_PRINT_* settings) to file descriptor 2
|
||||
(which is usually stderr). But this setting causes the dynamic linker to
|
||||
write logging output to the specified file.
|
||||
.TP
|
||||
.B DYLD_ROOT_PATH
|
||||
This is a colon separated list of directories. The dynamic linker will prepend each of
|
||||
this directory paths to every image access until a file is found.
|
||||
.TP
|
||||
.B DYLD_SHARED_REGION
|
||||
This can be "use" (the default), "avoid", or "private". Setting it to
|
||||
"avoid" tells dyld to not use the shared cache. All OS dylibs are loaded
|
||||
@ -203,14 +188,9 @@ This is useful to make sure that the use of
|
||||
.SM DYLD_LIBRARY_PATH
|
||||
is getting what you want.
|
||||
.TP
|
||||
.B DYLD_PRINT_LIBRARIES_POST_LAUNCH
|
||||
This does the same as
|
||||
.SM DYLD_PRINT_LIBRARIES
|
||||
but the printing starts after the program gets to its entry point.
|
||||
.TP
|
||||
.B DYLD_BIND_AT_LAUNCH
|
||||
When this is set, the dynamic linker binds all undefined symbols
|
||||
the program needs at launch time. This includes function symbols that can are normally
|
||||
the program needs at launch time. This includes function symbols that are normally
|
||||
lazily bound at the time of their first call.
|
||||
.TP
|
||||
.B DYLD_PRINT_STATISTICS
|
||||
@ -222,11 +202,11 @@ Right before the process's main() is called, dyld prints out detailed informatio
|
||||
dyld spent its time. Useful for analyzing launch performance.
|
||||
.TP
|
||||
.B DYLD_DISABLE_DOFS
|
||||
Causes dyld not register dtrace static probes with the kernel.
|
||||
Causes dyld to not register dtrace static probes with the kernel.
|
||||
.TP
|
||||
.B DYLD_PRINT_INITIALIZERS
|
||||
Causes dyld to print out a line when running each initializers in every image. Initializers
|
||||
run by dyld included constructors for C++ statically allocated objects, functions marked with
|
||||
Causes dyld to print out a line when running each initializer in every image. Initializers
|
||||
run by dyld include constructors for C++ statically allocated objects, functions marked with
|
||||
__attribute__((constructor)), and -init functions.
|
||||
.TP
|
||||
.B DYLD_PRINT_APIS
|
||||
@ -306,4 +286,4 @@ with -rpath @loader_path/zzz, where zzz is the path from the executable to the a
|
||||
At runtime dyld sets it run path to be the anchor point, then each dylib is found relative
|
||||
to the anchor point.
|
||||
.SH "SEE ALSO"
|
||||
libtool(1), ld(1), otool(1)
|
||||
dyldinfo(1), ld(1), otool(1)
|
||||
|
112
src/dyld/doc/man/man1/dyld_usage.1
Normal file
112
src/dyld/doc/man/man1/dyld_usage.1
Normal file
@ -0,0 +1,112 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "DYLD_USAGE" "1" "2018-07-28" "" "dyld"
|
||||
.SH NAME
|
||||
dyld_usage \- report dynamic linker activity in real-time
|
||||
.
|
||||
.nr rst2man-indent-level 0
|
||||
.
|
||||
.de1 rstReportMargin
|
||||
\\$1 \\n[an-margin]
|
||||
level \\n[rst2man-indent-level]
|
||||
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
-
|
||||
\\n[rst2man-indent0]
|
||||
\\n[rst2man-indent1]
|
||||
\\n[rst2man-indent2]
|
||||
..
|
||||
.de1 INDENT
|
||||
.\" .rstReportMargin pre:
|
||||
. RS \\$1
|
||||
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
|
||||
. nr rst2man-indent-level +1
|
||||
.\" .rstReportMargin post:
|
||||
..
|
||||
.de UNINDENT
|
||||
. RE
|
||||
.\" indent \\n[an-margin]
|
||||
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.nr rst2man-indent-level -1
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.SH SYNOPSIS
|
||||
.sp
|
||||
\fBdyld_usage\fP \fB[\-e] [\-f mode] [\-t seconds] [\-R rawfile [\-S start_time]
|
||||
[\-E end_time]] [pid | cmd [pid | cmd] ...]\fP
|
||||
.SH DESCRIPTION
|
||||
.sp
|
||||
The \fBdyld_usage\fP utility presents an ongoing display of information
|
||||
pertaining to dynamic linker activity within one or more processes. It requires
|
||||
root privileges due to the kernel tracing facility it uses to operate. By
|
||||
default \fBdyld_usage\fP monitors \fIdyld\fP activity in all processes except
|
||||
the running \fIdyld_usage\fP process, \fITerminal\fP, \fItelnetd\fP, \fIsshd\fP, \fIrlogind\fP,
|
||||
\fItcsh\fP, \fIcsh\fP, and \fIsh\fP\&. These defaults can be overridden such that output is
|
||||
limited to include or exclude a list of processes specified on the command line.
|
||||
Processes may be specified either by file name or by process id.
|
||||
.sp
|
||||
The output of \fBdyld_usage\fP is formatted according to the size of your
|
||||
window. A narrow window will display fewer columns of data. Use a wide window
|
||||
for maximum data display.
|
||||
.SH OPTIONS
|
||||
.sp
|
||||
\fBdyld_usage\fP supports the following options:
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-e
|
||||
Exclude the specified list of pids and commands from the sample, and exclude
|
||||
\fBdyld_usage\fP by default.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-R
|
||||
specifies a raw trace file to process.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-t
|
||||
specifies timeout in seconds (for use in automated tools).
|
||||
.UNINDENT
|
||||
.SH DISPLAY
|
||||
.sp
|
||||
The data columns displayed are as follows:
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B TIMESTAMP
|
||||
Time of day when call occurred.
|
||||
.TP
|
||||
.B OPERATION
|
||||
The \fIdyld\fP operation triggered by the process. Typically these operations
|
||||
are triggered by process launch or via a \fBdlopen\fP or \fBdlsym\fP system
|
||||
call. System call entries include both the parameters to the system call and
|
||||
the system call\(aqs return code (e.g., 0 on success).
|
||||
.TP
|
||||
.B TIME INTERVAL
|
||||
The elapsed time spent in the dynamic linker operation or system call.
|
||||
.TP
|
||||
.B PROCESS NAME
|
||||
The process that generated the dynamic linker activity. If space allows, the
|
||||
thread id will be appended to the process name (i.e., Mail.nnn).
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.SH SAMPLE USAGE
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
\fBsudo dyld_usage Mail\fP
|
||||
.sp
|
||||
\fBdyld_usage\fP will display dynamic link operations for all instances of
|
||||
processes named Mail.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.SH SEE ALSO
|
||||
.sp
|
||||
\fBdyld(1)\fP, \fBfs_usage(1)\fP
|
||||
.SH AUTHOR
|
||||
Apple, Inc.
|
||||
.SH COPYRIGHT
|
||||
2000-2018, Apple, Inc.
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
@ -1,4 +1,4 @@
|
||||
.Dd June 23, 2016
|
||||
.Dd June 1, 2017
|
||||
.Dt update_dyld_shared_cache 1
|
||||
.Os Darwin
|
||||
.Sh NAME
|
||||
@ -12,7 +12,6 @@
|
||||
.Op Fl force
|
||||
.Op Fl debug
|
||||
.Op Fl universal_boot
|
||||
.Op Fl verify
|
||||
.Sh DESCRIPTION
|
||||
.Nm update_dyld_shared_cache
|
||||
ensures that dyld's shared cache is up-to-date. This tool is normally
|
||||
@ -23,9 +22,6 @@ used another mechanism to alter an OS dylib, you should manually run
|
||||
.Pp
|
||||
Note that the new cache does not take effect until the OS is rebooted.
|
||||
.Pp
|
||||
If a safe-boot is
|
||||
done (booting with shift key held down) the cache is deleted.
|
||||
.Pp
|
||||
The dyld shared cache
|
||||
is mapped by dyld into a process at launch time. Later, when loading
|
||||
any mach-o image, dyld will first check if is in the share cache, and if
|
||||
@ -34,11 +30,8 @@ the original file. This results in significant performance improvements to
|
||||
launch time.
|
||||
.Pp
|
||||
.Nm update_dyld_shared_cache
|
||||
scans the directory /var/db/dyld/shared_region_roots for text files containing paths to
|
||||
mach-o executables. The full dependencies of all dylibs required by those executables is
|
||||
used to determine which libraries are commonly used and should be placed in the
|
||||
shared cache. If one of the text files contains a path to a dylib, that dylib and its
|
||||
dependents will be forced into the cache.
|
||||
scans the directory /System/Library/Receipts/ for .bom files which list all files
|
||||
installed. From that info it creates the set of OS dylibs to build into the dyld cache.
|
||||
.Pp
|
||||
.Nm update_dyld_shared_cache
|
||||
builds a separate cache file for each architecture. The cache files and a readable text
|
||||
@ -77,14 +70,6 @@ to regenerated the shared cache files even if they appear to be already up-to-da
|
||||
This option prints out additional information about the work being done.
|
||||
.It Fl universal_boot
|
||||
This option builds caches for all machines.
|
||||
.It Fl verify
|
||||
Will regenerate a shared cache in-memory that matches the randomization of the existing shared
|
||||
cache file. Then instead of writing the cache file, it compares the in-memory cache file to
|
||||
the on disk version and reports any differences.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Tp
|
||||
/var/db/dyld/shared_region_roots
|
||||
directory of text files with paths to mach-o images used to determine what should be in shared cache.
|
||||
.Sh SEE ALSO
|
||||
.Xr dyld 1
|
||||
|
@ -23,15 +23,15 @@ is the value returned by a previous call to dlopen.
|
||||
Prior to Mac OS X 10.5, only bundles could be unloaded. Starting in Mac OS X 10.5,
|
||||
dynamic libraries may also be unloaded. There are a couple of cases in which a
|
||||
dynamic library will never be unloaded: 1) the main executable links against it,
|
||||
2) An API that does not supoort unloading (e.g. NSAddImage()) was used to load
|
||||
it or some other dynnamic library that depends on it, 3) the dynamic library
|
||||
2) an API that does not support unloading (e.g. NSAddImage()) was used to load
|
||||
it or some other dynamic library that depends on it, 3) the dynamic library
|
||||
is in dyld's shared cache.
|
||||
.Sh RETURN VALUES
|
||||
If
|
||||
.Fn dlclose
|
||||
is successful, it returns a value of 0.
|
||||
Otherwise it returns -1, and sets an error string that can be
|
||||
retrived with
|
||||
retrieved with
|
||||
.Fn dlerror .
|
||||
.Pp
|
||||
.Sh SEE ALSO
|
||||
|
@ -84,7 +84,7 @@ The symbol name passed to
|
||||
is the name used in C source code. For example to find the address
|
||||
of function foo(), you would pass "foo" as the symbol name. This
|
||||
is unlike the older dyld APIs which required a leading underscore.
|
||||
If you looking up a C++ symbol, you need to use the mangled C++ symbol
|
||||
If you are looking up a C++ symbol, you need to use the mangled C++ symbol name.
|
||||
name.
|
||||
.Sh SEE ALSO
|
||||
.Xr dlopen 3
|
||||
|
@ -1,4 +1,4 @@
|
||||
.Dd November 29, 2010
|
||||
.Dd June 20, 2019
|
||||
.Dt dyld 3
|
||||
.Sh NAME
|
||||
.Nm _dyld_image_count,
|
||||
@ -85,7 +85,9 @@ is out of range NULL is returned.
|
||||
registers the specified function to be called when a new image is added
|
||||
(a bundle or a dynamic shared library) to the program. When this function is
|
||||
first registered it is called for once for each image that is currently part of
|
||||
the process.
|
||||
the process. The function is called with the dyld lock held. This blocks other
|
||||
threads from using dlopen(). Therefore, the function should do minimal work and
|
||||
return.
|
||||
.Pp
|
||||
.Fn _dyld_register_func_for_remove_image
|
||||
registers the specified function to be called when an image is removed
|
||||
@ -123,4 +125,4 @@ needed could be more than MAXPATHLEN.
|
||||
.Xr dlopen 3
|
||||
.Xr dladdr 3
|
||||
.Xr dyld 1
|
||||
http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachOTopics/index.html
|
||||
https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/MachOTopics/0-Introduction/introduction.html
|
||||
|
253
src/dyld/doc/rst/conf.py
Normal file
253
src/dyld/doc/rst/conf.py
Normal file
@ -0,0 +1,253 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# dyld documentation build configuration file.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
from datetime import date
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
# extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'dyld'
|
||||
copyright = u'2000-%d, Apple, Inc.' % date.today().year
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short version.
|
||||
# version = '7'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
# release = '7'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
today_fmt = '%Y-%m-%d'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
show_authors = True
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'friendly'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
html_theme_options = { "nosidebar": True }
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
html_theme_path = ["_themes"]
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
html_last_updated_fmt = '%Y-%m-%d'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
html_sidebars = {'index': 'indexsidebar.html'}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
# htmlhelp_basename = 'doc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'dyld.tex', u'dyld Documentation',
|
||||
u'dyld project', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = []
|
||||
|
||||
# Automatically derive the list of man pages from the contents of the command
|
||||
# guide subdirectory.
|
||||
basedir = os.path.dirname(__file__)
|
||||
man_page_authors = "Apple, Inc."
|
||||
command_guide_subpath = '.'
|
||||
command_guide_path = os.path.join(basedir, command_guide_subpath)
|
||||
for name in os.listdir(command_guide_path):
|
||||
# Ignore non-ReST files and the index page.
|
||||
if not name.endswith('.rst') or name in ('index.rst',):
|
||||
continue
|
||||
|
||||
# Otherwise, automatically extract the description.
|
||||
file_subpath = os.path.join(command_guide_subpath, name)
|
||||
with open(os.path.join(command_guide_path, name)) as f:
|
||||
title = f.readline().rstrip('\n')
|
||||
header = f.readline().rstrip('\n')
|
||||
|
||||
if len(header) != len(title):
|
||||
print >>sys.stderr, (
|
||||
"error: invalid header in %r (does not match title)" % (
|
||||
file_subpath,))
|
||||
if ' - ' not in title:
|
||||
print >>sys.stderr, (
|
||||
("error: invalid title in %r "
|
||||
"(expected '<name> - <description>')") % (
|
||||
file_subpath,))
|
||||
|
||||
# Split the name out of the title.
|
||||
name,description = title.split(' - ', 1)
|
||||
man_pages.append((file_subpath.replace('.rst',''), name,
|
||||
description, man_page_authors, 1))
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
# FIXME: Define intersphinx configuration.
|
||||
intersphinx_mapping = {}
|
76
src/dyld/doc/rst/dyld_usage.rst
Normal file
76
src/dyld/doc/rst/dyld_usage.rst
Normal file
@ -0,0 +1,76 @@
|
||||
dyld_usage - report dynamic linker activity in real-time
|
||||
==========================================================
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
|
||||
:program:`dyld_usage` **[-e] [-f mode] [-t seconds] [-R rawfile [-S start_time]
|
||||
[-E end_time]] [pid | cmd [pid | cmd] ...]**
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The :program:`dyld_usage` utility presents an ongoing display of information
|
||||
pertaining to dynamic linker activity within one or more processes. It requires
|
||||
root privileges due to the kernel tracing facility it uses to operate. By
|
||||
default :program:`dyld_usage` monitors `dyld` activity in all processes except
|
||||
the running `dyld_usage` process, `Terminal`, `telnetd`, `sshd`, `rlogind`,
|
||||
`tcsh`, `csh`, and `sh`. These defaults can be overridden such that output is
|
||||
limited to include or exclude a list of processes specified on the command line.
|
||||
Processes may be specified either by file name or by process id.
|
||||
|
||||
The output of :program:`dyld_usage` is formatted according to the size of your
|
||||
window. A narrow window will display fewer columns of data. Use a wide window
|
||||
for maximum data display.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
:program:`dyld_usage` supports the following options:
|
||||
|
||||
.. option:: -e
|
||||
|
||||
Exclude the specified list of pids and commands from the sample, and exclude
|
||||
:program:`dyld_usage` by default.
|
||||
|
||||
.. option:: -R
|
||||
|
||||
specifies a raw trace file to process.
|
||||
|
||||
.. option:: -t
|
||||
|
||||
specifies timeout in seconds (for use in automated tools).
|
||||
|
||||
DISPLAY
|
||||
-------
|
||||
|
||||
The data columns displayed are as follows:
|
||||
|
||||
TIMESTAMP
|
||||
Time of day when call occurred.
|
||||
|
||||
OPERATION
|
||||
The `dyld` operation triggered by the process. Typically these operations
|
||||
are triggered by process launch or via a ``dlopen`` or ``dlsym`` system
|
||||
call. System call entries include both the parameters to the system call and
|
||||
the system call's return code (e.g., 0 on success).
|
||||
|
||||
TIME INTERVAL
|
||||
The elapsed time spent in the dynamic linker operation or system call.
|
||||
|
||||
PROCESS NAME
|
||||
The process that generated the dynamic linker activity. If space allows, the
|
||||
thread id will be appended to the process name (i.e., Mail.nnn).
|
||||
|
||||
|
||||
SAMPLE USAGE
|
||||
------------
|
||||
|
||||
``sudo dyld_usage Mail``
|
||||
|
||||
:program:`dyld_usage` will display dynamic link operations for all instances of
|
||||
processes named Mail.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
:manpage:`dyld(1)`, :manpage:`fs_usage(1)`
|
||||
|
9
src/dyld/doc/rst/index.rst
Normal file
9
src/dyld/doc/rst/index.rst
Normal file
@ -0,0 +1,9 @@
|
||||
DYLD Command Guide
|
||||
------------------
|
||||
|
||||
The following documents are command descriptions for some of the DYLD tools.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
dyld_usage
|
22
src/dyld/doc/tracing/dyld.codes
Normal file
22
src/dyld/doc/tracing/dyld.codes
Normal file
@ -0,0 +1,22 @@
|
||||
0x1f070000 dyld.static_intializer
|
||||
0x1f070004 dyld.launch_executable
|
||||
0x1f070008 dyld.map_file
|
||||
0x1f07000c dyld.apply_fixups
|
||||
0x1f070010 dyld.attach_codesignature
|
||||
0x1f070014 dyld.build_closure
|
||||
0x1f070018 dyld.add_image_callback
|
||||
0x1f07001c dyld.remove_image_callback
|
||||
0x1f070020 dyld.objc_image_init
|
||||
0x1f070024 dyld.objc_images_map
|
||||
0x1f070028 dyld.apply_interposing
|
||||
0x1f07002c dyld.gdb_image_notifier
|
||||
0x1f070030 dyld.remote_image_notifier
|
||||
0x1f080000 dyld.dlopen
|
||||
0x1f080004 dyld.dlopen_preflight
|
||||
0x1f080008 dyld.dlclose
|
||||
0x1f08000c dyld.dlsym
|
||||
0x1f080010 dyld.dladdr
|
||||
0x1f090000 dyld.DEBUG.vm_remap
|
||||
0x1f090004 dyld.DEBUG.vm_dealloc
|
||||
0x1f090008 dyld.DEBUG.map_loop
|
||||
0x1f09000c dyld.DEBUG.marker
|
127
src/dyld/doc/tracing/dyld.plist
Normal file
127
src/dyld/doc/tracing/dyld.plist
Normal file
@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<array>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>dyld</string>
|
||||
<key>Children</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>dlopen</string>
|
||||
<key>Type</key>
|
||||
<string>Interval</string>
|
||||
<key>EventsMatchedBy</key>
|
||||
<string>Arg1</string>
|
||||
<key>KTraceCodeBegin</key>
|
||||
<string>0x1f070005</string>
|
||||
<key>KTraceCodeEnd</key>
|
||||
<string>0x1f070006</string>
|
||||
<key>ArgValueTypesBegin</key>
|
||||
<dict>
|
||||
<key>Arg2</key>
|
||||
<string>String</string>
|
||||
</dict>
|
||||
<key>ArgNamesBegin</key>
|
||||
<dict>
|
||||
<key>Arg2</key>
|
||||
<string>Path</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>dlopen_preflight</string>
|
||||
<key>Type</key>
|
||||
<string>Interval</string>
|
||||
<key>EventsMatchedBy</key>
|
||||
<string>Arg1</string>
|
||||
<key>KTraceCodeBegin</key>
|
||||
<string>0x1f070009</string>
|
||||
<key>KTraceCodeEnd</key>
|
||||
<string>0x1f07000a</string>
|
||||
<key>ArgValueTypesBegin</key>
|
||||
<dict>
|
||||
<key>Arg2</key>
|
||||
<string>String</string>
|
||||
</dict>
|
||||
<key>ArgNamesBegin</key>
|
||||
<dict>
|
||||
<key>Arg2</key>
|
||||
<string>Path</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>map_file</string>
|
||||
<key>Type</key>
|
||||
<string>Interval</string>
|
||||
<key>EventsMatchedBy</key>
|
||||
<string>Arg1</string>
|
||||
<key>KTraceCodeBegin</key>
|
||||
<string>0x1f070005</string>
|
||||
<key>KTraceCodeEnd</key>
|
||||
<string>0x1f070006</string>
|
||||
<key>ArgValueTypesBegin</key>
|
||||
<dict>
|
||||
<key>Arg2</key>
|
||||
<string>String</string>
|
||||
</dict>
|
||||
<key>ArgNamesBegin</key>
|
||||
<dict>
|
||||
<key>Arg2</key>
|
||||
<string>Path</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>dlsym</string>
|
||||
<key>Type</key>
|
||||
<string>Interval</string>
|
||||
<key>EventsMatchedBy</key>
|
||||
<string>Arg1</string>
|
||||
<key>KTraceCodeBegin</key>
|
||||
<string>0x1f07000d</string>
|
||||
<key>KTraceCodeEnd</key>
|
||||
<string>0x1f07000e</string>
|
||||
<key>ArgValueTypesBegin</key>
|
||||
<dict>
|
||||
<key>Arg2</key>
|
||||
<string>String</string>
|
||||
</dict>
|
||||
<key>ArgNamesBegin</key>
|
||||
<dict>
|
||||
<key>Arg2</key>
|
||||
<string>Path</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>Static Initializer</string>
|
||||
<key>Type</key>
|
||||
<string>Interval</string>
|
||||
<key>EventsMatchedBy</key>
|
||||
<string>Arg1</string>
|
||||
<key>KTraceCodeBegin</key>
|
||||
<string>0x1f070001</string>
|
||||
<key>KTraceCodeEnd</key>
|
||||
<string>0x1f070002</string>
|
||||
<key>ArgValueTypesBegin</key>
|
||||
<dict>
|
||||
<key>Arg2</key>
|
||||
<string>Hex</string>
|
||||
<key>Arg3</key>
|
||||
<string>Hex</string>
|
||||
</dict>
|
||||
<key>ArgNamesBegin</key>
|
||||
<dict>
|
||||
<key>Arg2</key>
|
||||
<string>Mach Header</string>
|
||||
<key>Arg3</key>
|
||||
<string>Initializer Address</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</plist>
|
File diff suppressed because it is too large
Load Diff
1447
src/dyld/dyld3/APIs.cpp
Normal file
1447
src/dyld/dyld3/APIs.cpp
Normal file
File diff suppressed because it is too large
Load Diff
241
src/dyld/dyld3/APIs.h
Normal file
241
src/dyld/dyld3/APIs.h
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef __DYLD_APIS_H__
|
||||
#define __DYLD_APIS_H__
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <mach-o/dyld_priv.h>
|
||||
|
||||
#include "dlfcn.h"
|
||||
|
||||
|
||||
#define TEMP_HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
//
|
||||
// The implementation of all dyld load/unload API's must hold a global lock
|
||||
// so that the next load/unload does start until the current is complete.
|
||||
// This lock is recursive so that initializers can call dlopen().
|
||||
// This is done using the macros DYLD_LOCK_THIS_BLOCK.
|
||||
// Example:
|
||||
//
|
||||
// void dyld_load_api() {
|
||||
// DYLD_LOAD_LOCK_THIS_BLOCK;
|
||||
// // free to do stuff here
|
||||
// // that accesses dyld internal data structures
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
#define DYLD_LOAD_LOCK_THIS_BLOCK RecursiveAutoLock _dyld_load_lock;
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
class __attribute__((visibility("hidden"))) RecursiveAutoLock
|
||||
{
|
||||
public:
|
||||
RecursiveAutoLock() {
|
||||
pthread_mutex_lock(&_sMutex);
|
||||
}
|
||||
~RecursiveAutoLock() {
|
||||
pthread_mutex_unlock(&_sMutex);
|
||||
}
|
||||
private:
|
||||
static pthread_mutex_t _sMutex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
uint32_t _dyld_image_count() TEMP_HIDDEN;
|
||||
|
||||
const mach_header* _dyld_get_image_header(uint32_t imageIndex) TEMP_HIDDEN;
|
||||
|
||||
intptr_t _dyld_get_image_slide(const mach_header* mh) TEMP_HIDDEN;
|
||||
|
||||
intptr_t _dyld_get_image_vmaddr_slide(uint32_t imageIndex) TEMP_HIDDEN;
|
||||
|
||||
const char* _dyld_get_image_name(uint32_t imageIndex) TEMP_HIDDEN;
|
||||
|
||||
int32_t NSVersionOfLinkTimeLibrary(const char* libraryName) TEMP_HIDDEN;
|
||||
|
||||
int32_t NSVersionOfRunTimeLibrary(const char* libraryName) TEMP_HIDDEN;
|
||||
|
||||
uint32_t dyld_get_program_sdk_watch_os_version() TEMP_HIDDEN;
|
||||
uint32_t dyld_get_program_min_watch_os_version() TEMP_HIDDEN;
|
||||
|
||||
uint32_t dyld_get_program_sdk_bridge_os_version() TEMP_HIDDEN;
|
||||
uint32_t dyld_get_program_min_bridge_os_version() TEMP_HIDDEN;
|
||||
|
||||
|
||||
uint32_t dyld_get_sdk_version(const mach_header* mh) TEMP_HIDDEN;
|
||||
|
||||
|
||||
uint32_t dyld_get_program_sdk_version() TEMP_HIDDEN;
|
||||
uint32_t dyld_get_min_os_version(const mach_header* mh) TEMP_HIDDEN;
|
||||
|
||||
uint32_t dyld_get_program_min_os_version() TEMP_HIDDEN;
|
||||
|
||||
dyld_platform_t dyld_get_active_platform(void) TEMP_HIDDEN;
|
||||
dyld_platform_t dyld_get_base_platform(dyld_platform_t platform) TEMP_HIDDEN;
|
||||
bool dyld_is_simulator_platform(dyld_platform_t platform) TEMP_HIDDEN;
|
||||
bool dyld_sdk_at_least(const struct mach_header* mh, dyld_build_version_t version) TEMP_HIDDEN;
|
||||
bool dyld_minos_at_least(const struct mach_header* mh, dyld_build_version_t version) TEMP_HIDDEN;
|
||||
bool dyld_program_sdk_at_least(dyld_build_version_t version) TEMP_HIDDEN;
|
||||
bool dyld_program_minos_at_least(dyld_build_version_t version) TEMP_HIDDEN;
|
||||
void dyld_get_image_versions(const struct mach_header* mh, void (^callback)(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version)) TEMP_HIDDEN;
|
||||
|
||||
bool _dyld_get_image_uuid(const mach_header* mh, uuid_t uuid) TEMP_HIDDEN;
|
||||
|
||||
int _NSGetExecutablePath(char* buf, uint32_t* bufsize) TEMP_HIDDEN;
|
||||
|
||||
void _dyld_register_func_for_add_image(void (*func)(const mach_header *mh, intptr_t vmaddr_slide)) TEMP_HIDDEN;
|
||||
|
||||
void _dyld_register_func_for_remove_image(void (*func)(const mach_header *mh, intptr_t vmaddr_slide)) TEMP_HIDDEN;
|
||||
|
||||
void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
|
||||
_dyld_objc_notify_init init,
|
||||
_dyld_objc_notify_unmapped unmapped) TEMP_HIDDEN;
|
||||
|
||||
const mach_header* dyld_image_header_containing_address(const void* addr) TEMP_HIDDEN;
|
||||
|
||||
const mach_header* _dyld_get_image_header_containing_address(const void* address) TEMP_HIDDEN;
|
||||
|
||||
bool _dyld_image_containing_address(const void* address) TEMP_HIDDEN;
|
||||
|
||||
const char* dyld_image_path_containing_address(const void* addr) TEMP_HIDDEN;
|
||||
|
||||
bool _dyld_is_memory_immutable(const void* addr, size_t length) TEMP_HIDDEN;
|
||||
|
||||
|
||||
int dladdr(const void* addr, Dl_info* info) TEMP_HIDDEN;
|
||||
|
||||
char* dlerror() TEMP_HIDDEN;
|
||||
|
||||
int dlclose(void* handle) TEMP_HIDDEN;
|
||||
|
||||
void* dlopen_internal(const char* path, int mode, void* callerAddress) TEMP_HIDDEN;
|
||||
|
||||
bool dlopen_preflight_internal(const char* path) TEMP_HIDDEN;
|
||||
|
||||
void* dlsym_internal(void* handle, const char* symbolName, void* callerAddress) TEMP_HIDDEN;
|
||||
|
||||
const struct dyld_all_image_infos* _dyld_get_all_image_infos() TEMP_HIDDEN;
|
||||
|
||||
bool dyld_shared_cache_some_image_overridden() TEMP_HIDDEN;
|
||||
|
||||
bool _dyld_get_shared_cache_uuid(uuid_t uuid) TEMP_HIDDEN;
|
||||
|
||||
const void* _dyld_get_shared_cache_range(size_t* length) TEMP_HIDDEN;
|
||||
|
||||
bool _dyld_shared_cache_optimized() TEMP_HIDDEN;
|
||||
|
||||
bool _dyld_shared_cache_is_locally_built() TEMP_HIDDEN;
|
||||
|
||||
bool dyld_need_closure(const char* execPath, const char* tempDir) TEMP_HIDDEN;
|
||||
|
||||
void _dyld_images_for_addresses(unsigned count, const void* addresses[], struct dyld_image_uuid_offset infos[]) TEMP_HIDDEN;
|
||||
|
||||
void _dyld_register_for_image_loads(void (*func)(const mach_header* mh, const char* path, bool unloadable)) TEMP_HIDDEN;
|
||||
|
||||
void _dyld_register_for_bulk_image_loads(void (*func)(unsigned imageCount, const struct mach_header* mhs[], const char* paths[])) TEMP_HIDDEN;
|
||||
|
||||
bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info) TEMP_HIDDEN;
|
||||
|
||||
bool dyld_process_is_restricted() TEMP_HIDDEN;
|
||||
|
||||
const char* dyld_shared_cache_file_path() TEMP_HIDDEN;
|
||||
|
||||
bool dyld_has_inserted_or_interposing_libraries() TEMP_HIDDEN;
|
||||
|
||||
void dyld_dynamic_interpose(const mach_header* mh, const dyld_interpose_tuple array[], size_t count) TEMP_HIDDEN;
|
||||
|
||||
int dyld_shared_cache_find_iterate_text(const uuid_t cacheUuid, const char* extraSearchDirs[], void (^callback)(const dyld_shared_cache_dylib_text_info* info)) TEMP_HIDDEN;
|
||||
|
||||
int dyld_shared_cache_iterate_text(const uuid_t cacheUuid, void (^callback)(const dyld_shared_cache_dylib_text_info* info)) TEMP_HIDDEN;
|
||||
|
||||
void _dyld_atfork_prepare() TEMP_HIDDEN;
|
||||
void _dyld_atfork_parent() TEMP_HIDDEN;
|
||||
void _dyld_fork_child() TEMP_HIDDEN;
|
||||
|
||||
void _dyld_missing_symbol_abort() TEMP_HIDDEN;
|
||||
|
||||
const char* _dyld_get_objc_selector(const char* selName) TEMP_HIDDEN;
|
||||
|
||||
void _dyld_for_each_objc_class(const char* className,
|
||||
void (^callback)(void* classPtr, bool isLoaded, bool* stop)) TEMP_HIDDEN;
|
||||
|
||||
void _dyld_for_each_objc_protocol(const char* protocolName,
|
||||
void (^callback)(void* protocolPtr, bool isLoaded, bool* stop)) TEMP_HIDDEN;
|
||||
|
||||
// only in macOS and deprecated
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName, NSObjectFileImage *objectFileImage) TEMP_HIDDEN;
|
||||
NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void *address, size_t size, NSObjectFileImage *objectFileImage) TEMP_HIDDEN;
|
||||
bool NSDestroyObjectFileImage(NSObjectFileImage objectFileImage) TEMP_HIDDEN;
|
||||
uint32_t NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage) TEMP_HIDDEN;
|
||||
const char* NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal) TEMP_HIDDEN;
|
||||
uint32_t NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage) TEMP_HIDDEN;
|
||||
const char* NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal, bool *tentative_definition) TEMP_HIDDEN;
|
||||
bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage objectFileImage, const char* symbolName) TEMP_HIDDEN;
|
||||
void* NSGetSectionDataInObjectFileImage(NSObjectFileImage objectFileImage, const char* segmentName, const char* sectionName, size_t *size) TEMP_HIDDEN;
|
||||
const char* NSNameOfModule(NSModule m) TEMP_HIDDEN;
|
||||
const char* NSLibraryNameForModule(NSModule m) TEMP_HIDDEN;
|
||||
NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName, uint32_t options) TEMP_HIDDEN;
|
||||
bool NSUnLinkModule(NSModule module, uint32_t options) TEMP_HIDDEN;
|
||||
bool NSIsSymbolNameDefined(const char* symbolName) TEMP_HIDDEN;
|
||||
bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint) TEMP_HIDDEN;
|
||||
bool NSIsSymbolNameDefinedInImage(const struct mach_header* image, const char* symbolName) TEMP_HIDDEN;
|
||||
NSSymbol NSLookupAndBindSymbol(const char* symbolName) TEMP_HIDDEN;
|
||||
NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint) TEMP_HIDDEN;
|
||||
NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName) TEMP_HIDDEN;
|
||||
NSSymbol NSLookupSymbolInImage(const struct mach_header* image, const char* symbolName, uint32_t options) TEMP_HIDDEN;
|
||||
const char* NSNameOfSymbol(NSSymbol symbol) TEMP_HIDDEN;
|
||||
void* NSAddressOfSymbol(NSSymbol symbol) TEMP_HIDDEN;
|
||||
NSModule NSModuleForSymbol(NSSymbol symbol) TEMP_HIDDEN;
|
||||
void NSLinkEditError(NSLinkEditErrors *c, int *errorNumber, const char** fileName, const char** errorString) TEMP_HIDDEN;
|
||||
bool NSAddLibrary(const char* pathName) TEMP_HIDDEN;
|
||||
bool NSAddLibraryWithSearching(const char* pathName) TEMP_HIDDEN;
|
||||
const struct mach_header* NSAddImage(const char* image_name, uint32_t options) TEMP_HIDDEN;
|
||||
void NSInstallLinkEditErrorHandlers(const NSLinkEditErrorHandlers *handlers) TEMP_HIDDEN;
|
||||
bool _dyld_present(void) TEMP_HIDDEN;
|
||||
bool _dyld_launched_prebound(void) TEMP_HIDDEN;
|
||||
bool _dyld_all_twolevel_modules_prebound(void) TEMP_HIDDEN;
|
||||
bool _dyld_bind_fully_image_containing_address(const void* address) TEMP_HIDDEN;
|
||||
bool _dyld_image_containing_address(const void* address) TEMP_HIDDEN;
|
||||
void _dyld_lookup_and_bind(const char* symbol_name, void **address, NSModule* module) TEMP_HIDDEN;
|
||||
void _dyld_lookup_and_bind_with_hint(const char* symbol_name, const char* library_name_hint, void** address, NSModule* module) TEMP_HIDDEN;
|
||||
void _dyld_lookup_and_bind_fully(const char* symbol_name, void** address, NSModule* module) TEMP_HIDDEN;
|
||||
const struct mach_header* _dyld_get_image_header_containing_address(const void* address) TEMP_HIDDEN;
|
||||
#endif
|
||||
|
||||
} // namespace dyld3
|
||||
|
||||
#endif // __DYLD_APIS_H__
|
||||
|
||||
|
605
src/dyld/dyld3/APIs_macOS.cpp
Normal file
605
src/dyld/dyld3/APIs_macOS.cpp
Normal file
@ -0,0 +1,605 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <_simple.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <TargetConditionals.h>
|
||||
#include <malloc/malloc.h>
|
||||
#include <mach-o/dyld_priv.h>
|
||||
#include <mach-o/dyld_images.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "dlfcn.h"
|
||||
|
||||
#include "AllImages.h"
|
||||
#include "Loading.h"
|
||||
#include "Logging.h"
|
||||
#include "Diagnostics.h"
|
||||
#include "DyldSharedCache.h"
|
||||
#include "APIs.h"
|
||||
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
// from APIs.cpp
|
||||
void parseDlHandle(void* h, const MachOLoaded** mh, bool* dontContinue);
|
||||
|
||||
|
||||
// only in macOS and deprecated
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
|
||||
// macOS needs to support an old API that only works with fileype==MH_BUNDLE.
|
||||
// In this deprecated API (unlike dlopen), loading and linking are separate steps.
|
||||
// NSCreateObjectFileImageFrom*() just maps in the bundle mach-o file.
|
||||
// NSLinkModule() does the load of dependent modules and rebasing/binding.
|
||||
// To unload one of these, you must call NSUnLinkModule() and NSDestroyObjectFileImage() in any order!
|
||||
//
|
||||
|
||||
NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* path, NSObjectFileImage* ofi)
|
||||
{
|
||||
log_apis("NSCreateObjectFileImageFromFile(\"%s\", %p)\n", path, ofi);
|
||||
|
||||
// verify path exists
|
||||
struct stat statbuf;
|
||||
if ( ::stat(path, &statbuf) == -1 )
|
||||
return NSObjectFileImageFailure;
|
||||
|
||||
// create ofi that just contains path. NSLinkModule does all the work
|
||||
OFIInfo result;
|
||||
result.path = strdup(path);
|
||||
result.memSource = nullptr;
|
||||
result.memLength = 0;
|
||||
result.loadAddress = nullptr;
|
||||
result.imageNum = 0;
|
||||
*ofi = gAllImages.addNSObjectFileImage(result);
|
||||
|
||||
log_apis("NSCreateObjectFileImageFromFile() => %p\n", *ofi);
|
||||
|
||||
return NSObjectFileImageSuccess;
|
||||
}
|
||||
|
||||
NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void* memImage, size_t memImageSize, NSObjectFileImage *ofi)
|
||||
{
|
||||
log_apis("NSCreateObjectFileImageFromMemory(%p, 0x%0lX, %p)\n", memImage, memImageSize, ofi);
|
||||
|
||||
// sanity check the buffer is a mach-o file
|
||||
__block Diagnostics diag;
|
||||
|
||||
// check if it is current arch mach-o or fat with slice for current arch
|
||||
bool usable = false;
|
||||
const MachOFile* mf = (MachOFile*)memImage;
|
||||
if ( mf->hasMachOMagic() && mf->isMachO(diag, memImageSize) ) {
|
||||
usable = (gAllImages.archs().grade(mf->cputype, mf->cpusubtype) != 0);
|
||||
}
|
||||
else if ( const FatFile* ff = FatFile::isFatFile(memImage) ) {
|
||||
uint64_t sliceOffset;
|
||||
uint64_t sliceLen;
|
||||
bool missingSlice;
|
||||
if ( ff->isFatFileWithSlice(diag, memImageSize, gAllImages.archs(), sliceOffset, sliceLen, missingSlice) ) {
|
||||
mf = (MachOFile*)((long)memImage+sliceOffset);
|
||||
if ( mf->isMachO(diag, sliceLen) ) {
|
||||
usable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( usable ) {
|
||||
if ( !mf->supportsPlatform(Platform::macOS) )
|
||||
usable = false;
|
||||
}
|
||||
if ( !usable ) {
|
||||
log_apis("NSCreateObjectFileImageFromMemory() not mach-o\n");
|
||||
return NSObjectFileImageFailure;
|
||||
}
|
||||
|
||||
// this API can only be used with bundles
|
||||
if ( !mf->isBundle() ) {
|
||||
log_apis("NSCreateObjectFileImageFromMemory() not a bundle\n");
|
||||
return NSObjectFileImageInappropriateFile;
|
||||
}
|
||||
|
||||
// allocate ofi that just lists the memory range
|
||||
OFIInfo result;
|
||||
result.path = nullptr;
|
||||
result.memSource = memImage;
|
||||
result.memLength = memImageSize;
|
||||
result.loadAddress = nullptr;
|
||||
result.imageNum = 0;
|
||||
*ofi = gAllImages.addNSObjectFileImage(result);
|
||||
|
||||
log_apis("NSCreateObjectFileImageFromMemory() => %p\n", *ofi);
|
||||
|
||||
return NSObjectFileImageSuccess;
|
||||
}
|
||||
|
||||
NSModule NSLinkModule(NSObjectFileImage ofi, const char* moduleName, uint32_t options)
|
||||
{
|
||||
DYLD_LOAD_LOCK_THIS_BLOCK
|
||||
log_apis("NSLinkModule(%p, \"%s\", 0x%08X)\n", ofi, moduleName, options);
|
||||
|
||||
__block const char* path = nullptr;
|
||||
bool foundImage = gAllImages.forNSObjectFileImage(ofi, ^(OFIInfo &image) {
|
||||
// if this is memory based image, write to temp file, then use file based loading
|
||||
if ( image.memSource != nullptr ) {
|
||||
// make temp file with content of memory buffer
|
||||
image.path = nullptr;
|
||||
char tempFileName[PATH_MAX];
|
||||
const char* tmpDir = getenv("TMPDIR");
|
||||
if ( (tmpDir != nullptr) && (strlen(tmpDir) > 2) ) {
|
||||
strlcpy(tempFileName, tmpDir, PATH_MAX);
|
||||
if ( tmpDir[strlen(tmpDir)-1] != '/' )
|
||||
strlcat(tempFileName, "/", PATH_MAX);
|
||||
}
|
||||
else
|
||||
strlcpy(tempFileName,"/tmp/", PATH_MAX);
|
||||
strlcat(tempFileName, "NSCreateObjectFileImageFromMemory-XXXXXXXX", PATH_MAX);
|
||||
int fd = ::mkstemp(tempFileName);
|
||||
if ( fd != -1 ) {
|
||||
ssize_t writtenSize = ::pwrite(fd, image.memSource, image.memLength, 0);
|
||||
if ( writtenSize == image.memLength ) {
|
||||
image.path = strdup(tempFileName);
|
||||
}
|
||||
else {
|
||||
log_apis("NSLinkModule() => NULL (could not save memory image to temp file)\n");
|
||||
}
|
||||
::close(fd);
|
||||
}
|
||||
}
|
||||
path = image.path;
|
||||
});
|
||||
|
||||
if (!foundImage) {
|
||||
// ofi is invalid if not in list
|
||||
log_apis("NSLinkModule() => NULL (invalid NSObjectFileImage)\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!path)
|
||||
return nullptr;
|
||||
|
||||
// dlopen the binary outside of the read lock as we don't want to risk deadlock
|
||||
Diagnostics diag;
|
||||
void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
|
||||
const MachOLoaded* loadAddress = gAllImages.dlopen(diag, path, false, false, false, false, true, callerAddress);
|
||||
if ( diag.hasError() ) {
|
||||
log_apis(" NSLinkModule: failed: %s\n", diag.errorMessage());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Now update the load address of this object
|
||||
gAllImages.forNSObjectFileImage(ofi, ^(OFIInfo &image) {
|
||||
image.loadAddress = loadAddress;
|
||||
|
||||
// if memory based load, delete temp file
|
||||
if ( image.memSource != nullptr ) {
|
||||
log_apis(" NSLinkModule: delete temp file: %s\n", image.path);
|
||||
::unlink(image.path);
|
||||
}
|
||||
});
|
||||
|
||||
log_apis("NSLinkModule() => %p\n", loadAddress);
|
||||
return (NSModule)loadAddress;
|
||||
}
|
||||
|
||||
// NSUnLinkModule unmaps the image, but does not release the NSObjectFileImage
|
||||
bool NSUnLinkModule(NSModule module, uint32_t options)
|
||||
{
|
||||
DYLD_LOAD_LOCK_THIS_BLOCK
|
||||
log_apis("NSUnLinkModule(%p, 0x%08X)\n", module, options);
|
||||
|
||||
__block const mach_header* mh = nullptr;
|
||||
gAllImages.infoForImageMappedAt(module, ^(const LoadedImage& foundImage, uint8_t permissions) {
|
||||
mh = foundImage.loadedAddress();
|
||||
});
|
||||
|
||||
if ( mh != nullptr )
|
||||
gAllImages.decRefCount(mh); // removes image if reference count went to zero
|
||||
|
||||
log_apis("NSUnLinkModule() => %d\n", mh != nullptr);
|
||||
|
||||
return mh != nullptr;
|
||||
}
|
||||
|
||||
// NSDestroyObjectFileImage releases the NSObjectFileImage, but the mapped image may remain in use
|
||||
bool NSDestroyObjectFileImage(NSObjectFileImage imageHandle)
|
||||
{
|
||||
log_apis("NSDestroyObjectFileImage(%p)\n", imageHandle);
|
||||
|
||||
__block const void* memSource = nullptr;
|
||||
__block size_t memLength = 0;
|
||||
__block const char* path = nullptr;
|
||||
bool foundImage = gAllImages.forNSObjectFileImage(imageHandle, ^(OFIInfo &image) {
|
||||
// keep copy of info
|
||||
memSource = image.memSource;
|
||||
memLength = image.memLength;
|
||||
path = image.path;
|
||||
});
|
||||
|
||||
if (!foundImage)
|
||||
return false;
|
||||
|
||||
// remove from list
|
||||
gAllImages.removeNSObjectFileImage(imageHandle);
|
||||
|
||||
// if object was created from a memory, release that memory
|
||||
// NOTE: this is the way dyld has always done this. NSCreateObjectFileImageFromMemory() hands ownership of the memory to dyld
|
||||
if ( memSource != nullptr ) {
|
||||
// we don't know if memory came from malloc or vm_allocate, so ask malloc
|
||||
if ( malloc_size(memSource) != 0 )
|
||||
free((void*)(memSource));
|
||||
else
|
||||
vm_deallocate(mach_task_self(), (vm_address_t)memSource, memLength);
|
||||
}
|
||||
free((void*)path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage)
|
||||
{
|
||||
halt("NSSymbolDefinitionCountInObjectFileImage() is obsolete");
|
||||
}
|
||||
|
||||
const char* NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal)
|
||||
{
|
||||
halt("NSSymbolDefinitionNameInObjectFileImage() is obsolete");
|
||||
}
|
||||
|
||||
uint32_t NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage)
|
||||
{
|
||||
halt("NSSymbolReferenceCountInObjectFileImage() is obsolete");
|
||||
}
|
||||
|
||||
const char* NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal, bool *tentative_definition)
|
||||
{
|
||||
halt("NSSymbolReferenceNameInObjectFileImage() is obsolete");
|
||||
}
|
||||
|
||||
bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage imageHandle, const char* symbolName)
|
||||
{
|
||||
log_apis("NSIsSymbolDefinedInObjectFileImage(%p, %s)\n", imageHandle, symbolName);
|
||||
|
||||
__block bool hasSymbol = false;
|
||||
bool foundImage = gAllImages.forNSObjectFileImage(imageHandle, ^(OFIInfo &image) {
|
||||
void* addr;
|
||||
bool resultPointsToInstructions = false;
|
||||
hasSymbol = image.loadAddress->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions);
|
||||
});
|
||||
|
||||
// ofi is invalid if not in list
|
||||
if (!foundImage)
|
||||
return false;
|
||||
|
||||
return hasSymbol;
|
||||
}
|
||||
|
||||
void* NSGetSectionDataInObjectFileImage(NSObjectFileImage imageHandle, const char* segmentName, const char* sectionName, size_t* size)
|
||||
{
|
||||
__block const void* result = nullptr;
|
||||
bool foundImage = gAllImages.forNSObjectFileImage(imageHandle, ^(OFIInfo &image) {
|
||||
uint64_t sz;
|
||||
result = image.loadAddress->findSectionContent(segmentName, sectionName, sz);
|
||||
*size = (size_t)sz;
|
||||
});
|
||||
|
||||
// ofi is invalid if not in list
|
||||
if (!foundImage)
|
||||
return nullptr;
|
||||
|
||||
return (void*)result;
|
||||
}
|
||||
|
||||
const char* NSNameOfModule(NSModule m)
|
||||
{
|
||||
log_apis("NSNameOfModule(%p)\n", m);
|
||||
|
||||
__block const char* result = nullptr;
|
||||
gAllImages.infoForImageMappedAt(m, ^(const LoadedImage& foundImage, uint8_t permissions) {
|
||||
result = gAllImages.imagePath(foundImage.image());
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const char* NSLibraryNameForModule(NSModule m)
|
||||
{
|
||||
log_apis("NSLibraryNameForModule(%p)\n", m);
|
||||
|
||||
__block const char* result = nullptr;
|
||||
gAllImages.infoForImageMappedAt(m, ^(const LoadedImage& foundImage, uint8_t permissions) {
|
||||
result = gAllImages.imagePath(foundImage.image());
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static bool flatFindSymbol(const char* symbolName, void** symbolAddress, const mach_header** foundInImageAtLoadAddress)
|
||||
{
|
||||
__block bool result = false;
|
||||
gAllImages.forEachImage(^(const LoadedImage& loadedImage, bool& stop) {
|
||||
bool resultPointsToInstructions = false;
|
||||
if ( loadedImage.loadedAddress()->hasExportedSymbol(symbolName, nullptr, symbolAddress, &resultPointsToInstructions) ) {
|
||||
*foundInImageAtLoadAddress = loadedImage.loadedAddress();
|
||||
stop = true;
|
||||
result = true;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NSIsSymbolNameDefined(const char* symbolName)
|
||||
{
|
||||
log_apis("NSIsSymbolNameDefined(%s)\n", symbolName);
|
||||
|
||||
const mach_header* foundInImageAtLoadAddress;
|
||||
void* address;
|
||||
return flatFindSymbol(symbolName, &address, &foundInImageAtLoadAddress);
|
||||
}
|
||||
|
||||
bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint)
|
||||
{
|
||||
log_apis("NSIsSymbolNameDefinedWithHint(%s, %s)\n", symbolName, libraryNameHint);
|
||||
|
||||
const mach_header* foundInImageAtLoadAddress;
|
||||
void* address;
|
||||
return flatFindSymbol(symbolName, &address, &foundInImageAtLoadAddress);
|
||||
}
|
||||
|
||||
bool NSIsSymbolNameDefinedInImage(const struct mach_header* mh, const char* symbolName)
|
||||
{
|
||||
log_apis("NSIsSymbolNameDefinedInImage(%p, %s)\n", mh, symbolName);
|
||||
|
||||
void* addr;
|
||||
bool resultPointsToInstructions = false;
|
||||
return ((MachOLoaded*)mh)->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions);
|
||||
}
|
||||
|
||||
NSSymbol NSLookupAndBindSymbol(const char* symbolName)
|
||||
{
|
||||
log_apis("NSLookupAndBindSymbol(%s)\n", symbolName);
|
||||
|
||||
const mach_header* foundInImageAtLoadAddress;
|
||||
void* symbolAddress;
|
||||
if ( flatFindSymbol(symbolName, &symbolAddress, &foundInImageAtLoadAddress) ) {
|
||||
return (NSSymbol)symbolAddress;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint)
|
||||
{
|
||||
log_apis("NSLookupAndBindSymbolWithHint(%s, %s)\n", symbolName, libraryNameHint);
|
||||
|
||||
const mach_header* foundInImageAtLoadAddress;
|
||||
void* symbolAddress;
|
||||
if ( flatFindSymbol(symbolName, &symbolAddress, &foundInImageAtLoadAddress) ) {
|
||||
return (NSSymbol)symbolAddress;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName)
|
||||
{
|
||||
log_apis("NSLookupSymbolInModule(%p. %s)\n", module, symbolName);
|
||||
|
||||
const MachOLoaded* mh = (const MachOLoaded*)module;
|
||||
void* addr;
|
||||
bool resultPointsToInstructions = false;
|
||||
if ( mh->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions) ) {
|
||||
return (NSSymbol)addr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NSSymbol NSLookupSymbolInImage(const mach_header* mh, const char* symbolName, uint32_t options)
|
||||
{
|
||||
log_apis("NSLookupSymbolInImage(%p, \"%s\", 0x%08X)\n", mh, symbolName, options);
|
||||
|
||||
void* addr;
|
||||
bool resultPointsToInstructions = false;
|
||||
if ( ((MachOLoaded*)mh)->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions) ) {
|
||||
log_apis(" NSLookupSymbolInImage() => %p\n", addr);
|
||||
return (NSSymbol)addr;
|
||||
}
|
||||
if ( options & NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR ) {
|
||||
log_apis(" NSLookupSymbolInImage() => NULL\n");
|
||||
return nullptr;
|
||||
}
|
||||
// FIXME: abort();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* NSNameOfSymbol(NSSymbol symbol)
|
||||
{
|
||||
halt("NSNameOfSymbol() is obsolete");
|
||||
}
|
||||
|
||||
void* NSAddressOfSymbol(NSSymbol symbol)
|
||||
{
|
||||
log_apis("NSAddressOfSymbol(%p)\n", symbol);
|
||||
|
||||
// in dyld 1.0, NSSymbol was a pointer to the nlist entry in the symbol table
|
||||
return (void*)symbol;
|
||||
}
|
||||
|
||||
NSModule NSModuleForSymbol(NSSymbol symbol)
|
||||
{
|
||||
log_apis("NSModuleForSymbol(%p)\n", symbol);
|
||||
|
||||
__block NSModule result = nullptr;
|
||||
gAllImages.infoForImageMappedAt(symbol, ^(const LoadedImage& foundImage, uint8_t permissions) {
|
||||
result = (NSModule)foundImage.loadedAddress();
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void NSLinkEditError(NSLinkEditErrors *c, int *errorNumber, const char** fileName, const char** errorString)
|
||||
{
|
||||
log_apis("NSLinkEditError(%p, %p, %p, %p)\n", c, errorNumber, fileName, errorString);
|
||||
*c = NSLinkEditOtherError;
|
||||
*errorNumber = 0;
|
||||
*fileName = NULL;
|
||||
*errorString = NULL;
|
||||
}
|
||||
|
||||
bool NSAddLibrary(const char* pathName)
|
||||
{
|
||||
log_apis("NSAddLibrary(%s)\n", pathName);
|
||||
|
||||
void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
|
||||
return ( dlopen_internal(pathName, 0, callerAddress) != nullptr);
|
||||
}
|
||||
|
||||
bool NSAddLibraryWithSearching(const char* pathName)
|
||||
{
|
||||
log_apis("NSAddLibraryWithSearching(%s)\n", pathName);
|
||||
|
||||
void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
|
||||
return ( dlopen_internal(pathName, 0, callerAddress) != nullptr);
|
||||
}
|
||||
|
||||
const mach_header* NSAddImage(const char* imageName, uint32_t options)
|
||||
{
|
||||
log_apis("NSAddImage(\"%s\", 0x%08X)\n", imageName, options);
|
||||
|
||||
// Note: this is a quick and dirty implementation that just uses dlopen() and ignores some option flags
|
||||
uint32_t dloptions = 0;
|
||||
if ( (options & NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED) != 0 )
|
||||
dloptions |= RTLD_NOLOAD;
|
||||
|
||||
void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
|
||||
void* h = dlopen_internal(imageName, dloptions, callerAddress);
|
||||
if ( h != nullptr ) {
|
||||
const MachOLoaded* mh;
|
||||
bool dontContinue;
|
||||
parseDlHandle(h, &mh, &dontContinue);
|
||||
return mh;
|
||||
}
|
||||
|
||||
if ( (options & (NSADDIMAGE_OPTION_RETURN_ON_ERROR|NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED)) == 0 ) {
|
||||
halt("NSAddImage() image not found");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NSInstallLinkEditErrorHandlers(const NSLinkEditErrorHandlers *handlers)
|
||||
{
|
||||
halt("NSInstallLinkEditErrorHandlers() is obsolete");
|
||||
}
|
||||
|
||||
bool _dyld_present(void)
|
||||
{
|
||||
log_apis("_dyld_present()\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _dyld_launched_prebound(void)
|
||||
{
|
||||
halt("_dyld_launched_prebound() is obsolete");
|
||||
}
|
||||
|
||||
bool _dyld_all_twolevel_modules_prebound(void)
|
||||
{
|
||||
halt("_dyld_all_twolevel_modules_prebound() is obsolete");
|
||||
}
|
||||
|
||||
bool _dyld_bind_fully_image_containing_address(const void* address)
|
||||
{
|
||||
log_apis("_dyld_bind_fully_image_containing_address(%p)\n", address);
|
||||
|
||||
// in dyld3, everything is always fully bound
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _dyld_image_containing_address(const void* address)
|
||||
{
|
||||
log_apis("_dyld_image_containing_address(%p)\n", address);
|
||||
|
||||
return (dyld_image_header_containing_address(address) != nullptr);
|
||||
}
|
||||
|
||||
void _dyld_lookup_and_bind(const char* symbolName, void **address, NSModule* module)
|
||||
{
|
||||
log_apis("_dyld_lookup_and_bind(%s, %p, %p)\n", symbolName, address, module);
|
||||
|
||||
const mach_header* foundInImageAtLoadAddress;
|
||||
if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
|
||||
*module = (NSModule)foundInImageAtLoadAddress;
|
||||
return;
|
||||
}
|
||||
|
||||
*address = 0;
|
||||
*module = 0;
|
||||
}
|
||||
|
||||
void _dyld_lookup_and_bind_with_hint(const char* symbolName, const char* libraryNameHint, void** address, NSModule* module)
|
||||
{
|
||||
log_apis("_dyld_lookup_and_bind_with_hint(%s, %s, %p, %p)\n", symbolName, libraryNameHint, address, module);
|
||||
|
||||
const mach_header* foundInImageAtLoadAddress;
|
||||
if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
|
||||
*module = (NSModule)foundInImageAtLoadAddress;
|
||||
return;
|
||||
}
|
||||
|
||||
*address = 0;
|
||||
*module = 0;
|
||||
}
|
||||
|
||||
|
||||
void _dyld_lookup_and_bind_fully(const char* symbolName, void** address, NSModule* module)
|
||||
{
|
||||
log_apis("_dyld_lookup_and_bind_fully(%s, %p, %p)\n", symbolName, address, module);
|
||||
|
||||
const mach_header* foundInImageAtLoadAddress;
|
||||
if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
|
||||
*module = (NSModule)foundInImageAtLoadAddress;
|
||||
return;
|
||||
}
|
||||
|
||||
*address = 0;
|
||||
*module = 0;
|
||||
}
|
||||
|
||||
const struct mach_header* _dyld_get_image_header_containing_address(const void* address)
|
||||
{
|
||||
log_apis("_dyld_get_image_header_containing_address(%p)\n", address);
|
||||
|
||||
return dyld_image_header_containing_address(address);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace dyld3
|
||||
|
1942
src/dyld/dyld3/AllImages.cpp
Normal file
1942
src/dyld/dyld3/AllImages.cpp
Normal file
File diff suppressed because it is too large
Load Diff
278
src/dyld/dyld3/AllImages.h
Normal file
278
src/dyld/dyld3/AllImages.h
Normal file
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __ALL_IMAGES_H__
|
||||
#define __ALL_IMAGES_H__
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <pthread.h>
|
||||
#include <os/lock_private.h>
|
||||
#include <mach-o/dyld_priv.h>
|
||||
|
||||
#include "Closure.h"
|
||||
#include "Loading.h"
|
||||
#include "MachOLoaded.h"
|
||||
#include "DyldSharedCache.h"
|
||||
|
||||
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
// only in macOS and deprecated
|
||||
struct VIS_HIDDEN OFIInfo
|
||||
{
|
||||
const char* path; // = nullptr;
|
||||
const void* memSource; // = nullptr;
|
||||
size_t memLength; // = 0;
|
||||
const dyld3::MachOLoaded* loadAddress; // = nullptr;
|
||||
uint64_t imageNum; // = 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
class VIS_HIDDEN AllImages
|
||||
{
|
||||
public:
|
||||
typedef void (*NotifyFunc)(const mach_header* mh, intptr_t slide);
|
||||
typedef void (*LoadNotifyFunc)(const mach_header* mh, const char* path, bool unloadable);
|
||||
typedef void (*BulkLoadNotifier)(unsigned count, const mach_header* mhs[], const char* paths[]);
|
||||
|
||||
void init(const closure::LaunchClosure* closure, const DyldSharedCache* dyldCacheLoadAddress, const char* dyldCachePath,
|
||||
const Array<LoadedImage>& initialImages);
|
||||
void setRestrictions(bool allowAtPaths, bool allowEnvPaths);
|
||||
void setHasCacheOverrides(bool someCacheImageOverriden);
|
||||
bool hasCacheOverrides() const;
|
||||
void setMainPath(const char* path);
|
||||
void applyInitialImages();
|
||||
|
||||
void addImages(const Array<LoadedImage>& newImages);
|
||||
void removeImages(const Array<LoadedImage>& unloadImages);
|
||||
void runImageNotifiers(const Array<LoadedImage>& newImages);
|
||||
void runImageCallbacks(const Array<LoadedImage>& newImages);
|
||||
void applyInterposingToDyldCache(const closure::Closure* closure);
|
||||
void runStartupInitialzers();
|
||||
void runInitialzersBottomUp(const closure::Image* topImage);
|
||||
void runLibSystemInitializer(LoadedImage& libSystem);
|
||||
|
||||
uint32_t count() const;
|
||||
|
||||
void forEachImage(void (^handler)(const LoadedImage& loadedImage, bool& stop)) const;
|
||||
const MachOLoaded* findDependent(const MachOLoaded* mh, uint32_t depIndex);
|
||||
void visitDependentsTopDown(const LoadedImage& start, void (^handler)(const LoadedImage& aLoadedImage, bool& stop)) const;
|
||||
void infoForImageMappedAt(const void* addr, void (^handler)(const LoadedImage& foundImage, uint8_t permissions)) const;
|
||||
bool infoForImageMappedAt(const void* addr, const MachOLoaded** ml, uint64_t* textSize, const char** path) const;
|
||||
void infoForNonCachedImageMappedAt(const void* addr, void (^handler)(const LoadedImage& foundImage, uint8_t permissions)) const;
|
||||
void infoForImageWithLoadAddress(const MachOLoaded*, void (^handler)(const LoadedImage& foundImage)) const;
|
||||
const char* pathForImageMappedAt(const void* addr) const;
|
||||
const char* imagePathByIndex(uint32_t index) const;
|
||||
const mach_header* imageLoadAddressByIndex(uint32_t index) const;
|
||||
bool immutableMemory(const void* addr, size_t length) const;
|
||||
void* interposeValue(void* value) const;
|
||||
|
||||
bool hasInsertedOrInterposingLibraries() const;
|
||||
bool isRestricted() const;
|
||||
const MachOLoaded* mainExecutable() const;
|
||||
const closure::Image* mainExecutableImage() const;
|
||||
const void* cacheLoadAddress() const { return _dyldCacheAddress; }
|
||||
const char* dyldCachePath() const { return _dyldCachePath; }
|
||||
bool dyldCacheHasPath(const char* path) const;
|
||||
const char* imagePath(const closure::Image*) const;
|
||||
dyld_platform_t platform() const;
|
||||
const GradedArchs& archs() const;
|
||||
|
||||
const Array<const closure::ImageArray*>& imagesArrays();
|
||||
|
||||
void incRefCount(const mach_header* loadAddress);
|
||||
void decRefCount(const mach_header* loadAddress);
|
||||
|
||||
void addLoadNotifier(NotifyFunc);
|
||||
void addUnloadNotifier(NotifyFunc);
|
||||
void setObjCNotifiers(_dyld_objc_notify_mapped, _dyld_objc_notify_init, _dyld_objc_notify_unmapped);
|
||||
void notifyObjCUnmap(const char* path, const struct mach_header* mh);
|
||||
void addLoadNotifier(LoadNotifyFunc);
|
||||
void addBulkLoadNotifier(BulkLoadNotifier);
|
||||
|
||||
|
||||
void setOldAllImageInfo(dyld_all_image_infos* old) { _oldAllImageInfos = old; }
|
||||
dyld_all_image_infos* oldAllImageInfo() const { return _oldAllImageInfos;}
|
||||
void notifyMonitorMain();
|
||||
void notifyMonitorLoads(const Array<LoadedImage>& newImages);
|
||||
void notifyMonitorUnloads(const Array<LoadedImage>& unloadingImages);
|
||||
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
NSObjectFileImage addNSObjectFileImage(const OFIInfo&);
|
||||
void removeNSObjectFileImage(NSObjectFileImage);
|
||||
bool forNSObjectFileImage(NSObjectFileImage imageHandle,
|
||||
void (^handler)(OFIInfo& image));
|
||||
#endif
|
||||
|
||||
const char* getObjCSelector(const char* selName) const;
|
||||
void forEachObjCClass(const char* className,
|
||||
void (^callback)(void* classPtr, bool isLoaded, bool* stop)) const;
|
||||
void forEachObjCProtocol(const char* protocolName,
|
||||
void (^callback)(void* protocolPtr, bool isLoaded, bool* stop)) const;
|
||||
|
||||
const MachOLoaded* dlopen(Diagnostics& diag, const char* path, bool rtldNoLoad, bool rtldLocal, bool rtldNoDelete, bool forceBindLazies, bool fromOFI, const void* callerAddress);
|
||||
|
||||
struct ProgramVars
|
||||
{
|
||||
const void* mh;
|
||||
int* NXArgcPtr;
|
||||
const char*** NXArgvPtr;
|
||||
const char*** environPtr;
|
||||
const char** __prognamePtr;
|
||||
};
|
||||
void setProgramVars(ProgramVars* vars);
|
||||
|
||||
// Note these are to be used exclusively by forking
|
||||
void takeLockBeforeFork();
|
||||
void releaseLockInForkParent();
|
||||
void resetLockInForkChild();
|
||||
|
||||
private:
|
||||
friend class Reaper;
|
||||
|
||||
struct DlopenCount {
|
||||
const mach_header* loadAddress;
|
||||
uintptr_t refCount;
|
||||
};
|
||||
|
||||
//
|
||||
// The ImmutableRanges structure is used to make dyld_is_memory_immutable()
|
||||
// fast and lock free. The table contains just ranges that are immutable,
|
||||
// which means they are non-writable and will never be unloaded.
|
||||
// This means the table is only every appended to. No entries are ever removed
|
||||
// or changed. This makes it easier to be lock-less. The array fields
|
||||
// all start as zero. Entries are only appended with the writer lock,
|
||||
// so we don't need to worry about multiple writers colliding. And when
|
||||
// appending, the end field is set before the start field. Readers
|
||||
// of this structure just walk down the array and quit at the first
|
||||
// start field that is zero.
|
||||
//
|
||||
struct ImmutableRanges {
|
||||
std::atomic<ImmutableRanges*> next;
|
||||
uintptr_t arraySize;
|
||||
struct {
|
||||
std::atomic<uintptr_t> start;
|
||||
std::atomic<uintptr_t> end;
|
||||
} array[2]; // programs with only main-exe and dyld cache fit in here
|
||||
};
|
||||
|
||||
const MachOLoaded* loadImage(Diagnostics& diag, closure::ImageNum topImageNum, const closure::DlopenClosure* newClosure,
|
||||
bool rtldLocal, bool rtldNoDelete, bool rtldNow, bool fromOFI);
|
||||
|
||||
|
||||
typedef void (*Initializer)(int argc, const char* argv[], char* envp[], const char* apple[], const ProgramVars* vars);
|
||||
typedef const Array<LoadedImage> StartImageArray;
|
||||
|
||||
void runInitialzersInImage(const mach_header* imageLoadAddress, const closure::Image* image);
|
||||
void mirrorToOldAllImageInfos();
|
||||
void garbageCollectImages();
|
||||
void breadthFirstRecurseDependents(Array<closure::ImageNum>& visited, const LoadedImage& nodeLi, bool& stop, void (^handler)(const LoadedImage& aLoadedImage, bool& stop)) const;
|
||||
void appendToImagesArray(const closure::ImageArray* newArray);
|
||||
void withReadLock(void (^work)()) const;
|
||||
void withWriteLock(void (^work)());
|
||||
void withNotifiersLock(void (^work)()) const;
|
||||
bool findImage(const mach_header* loadAddress, LoadedImage& foundImage) const;
|
||||
bool findImageNum(closure::ImageNum imageNum, LoadedImage& foundImage) const;
|
||||
LoadedImage findImageNum(closure::ImageNum num, uint32_t& indexHint);
|
||||
bool swapImageState(closure::ImageNum num, uint32_t& indexHint, LoadedImage::State expectedCurrentState, LoadedImage::State newState);
|
||||
void runAllInitializersInImage(const closure::Image* image, const MachOLoaded* ml);
|
||||
void recomputeBounds();
|
||||
void runAllStaticTerminators();
|
||||
uintptr_t resolveTarget(closure::Image::ResolvedSymbolTarget target) const;
|
||||
void addImmutableRange(uintptr_t start, uintptr_t end);
|
||||
|
||||
void constructMachPorts(int slot);
|
||||
void teardownMachPorts(int slot);
|
||||
void forEachPortSlot(void (^callback)(int slot));
|
||||
void sendMachMessage(int slot, mach_msg_id_t msg_id, mach_msg_header_t* msg_buffer, mach_msg_size_t msg_size);
|
||||
void notifyMonitoringDyld(bool unloading, const Array<LoadedImage>& images);
|
||||
|
||||
static void runAllStaticTerminatorsHelper(void*);
|
||||
|
||||
typedef closure::ImageArray ImageArray;
|
||||
|
||||
const closure::LaunchClosure* _mainClosure = nullptr;
|
||||
const DyldSharedCache* _dyldCacheAddress = nullptr;
|
||||
const char* _dyldCachePath = nullptr;
|
||||
uint64_t _dyldCacheSlide = 0;
|
||||
StartImageArray* _initialImages = nullptr;
|
||||
const char* _mainExeOverridePath = nullptr;
|
||||
_dyld_objc_notify_mapped _objcNotifyMapped = nullptr;
|
||||
_dyld_objc_notify_init _objcNotifyInit = nullptr;
|
||||
_dyld_objc_notify_unmapped _objcNotifyUnmapped = nullptr;
|
||||
ProgramVars* _programVars = nullptr;
|
||||
dyld_all_image_infos* _oldAllImageInfos = nullptr;
|
||||
dyld_image_info* _oldAllImageArray = nullptr;
|
||||
dyld_uuid_info* _oldUUIDArray = nullptr;
|
||||
const GradedArchs* _archs = nullptr;
|
||||
ImmutableRanges _immutableRanges = { nullptr, 2 };
|
||||
uint32_t _oldArrayAllocCount = 0;
|
||||
uint32_t _oldUUIDAllocCount = 0;
|
||||
closure::ImageNum _nextImageNum = 0;
|
||||
int32_t _gcCount = 0;
|
||||
bool _processDOFs = false;
|
||||
bool _allowAtPaths = false;
|
||||
bool _allowEnvPaths = false;
|
||||
bool _someImageOverridden = false;
|
||||
uintptr_t _lowestNonCached = 0;
|
||||
uintptr_t _highestNonCached = UINTPTR_MAX;
|
||||
#ifdef OS_UNFAIR_RECURSIVE_LOCK_INIT
|
||||
mutable os_unfair_recursive_lock _globalLock = OS_UNFAIR_RECURSIVE_LOCK_INIT;
|
||||
#else
|
||||
mutable pthread_mutex_t _globalLock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
GrowableArray<const ImageArray*, 4, 4> _imagesArrays;
|
||||
GrowableArray<NotifyFunc, 4, 4> _loadNotifiers;
|
||||
GrowableArray<NotifyFunc, 4, 4> _unloadNotifiers;
|
||||
GrowableArray<LoadNotifyFunc, 4, 4> _loadNotifiers2;
|
||||
GrowableArray<BulkLoadNotifier, 2, 2> _loadBulkNotifiers;
|
||||
GrowableArray<DlopenCount, 4, 4> _dlopenRefCounts;
|
||||
GrowableArray<LoadedImage, 16> _loadedImages;
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
uint64_t _nextObjectFileImageNum = 0;
|
||||
GrowableArray<OFIInfo, 4, 1> _objectFileImages;
|
||||
#endif
|
||||
|
||||
// ObjC selectors
|
||||
// This is an array of the base addresses of sections containing selector strings
|
||||
GrowableArray<uintptr_t, 4, 4> _objcSelectorHashTableImages;
|
||||
const closure::ObjCSelectorOpt* _objcSelectorHashTable = nullptr;
|
||||
|
||||
// ObjC classes
|
||||
// This is an array of the base addresses of (name vmaddr, data vmaddr) pairs of sections in each image
|
||||
GrowableArray<std::pair<uintptr_t, uintptr_t>, 4, 4> _objcClassHashTableImages;
|
||||
const closure::ObjCClassOpt* _objcClassHashTable = nullptr;
|
||||
const closure::ObjCClassDuplicatesOpt* _objcClassDuplicatesHashTable = nullptr;
|
||||
const closure::ObjCClassOpt* _objcProtocolHashTable = nullptr;
|
||||
const objc_opt::objc_opt_t* _dyldCacheObjCOpt = nullptr;
|
||||
};
|
||||
|
||||
extern AllImages gAllImages;
|
||||
|
||||
|
||||
} // dyld3
|
||||
|
||||
|
||||
#endif // __ALL_IMAGES_H__
|
322
src/dyld/dyld3/Array.h
Normal file
322
src/dyld/dyld3/Array.h
Normal file
@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#ifndef Array_h
|
||||
#define Array_h
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <mach/mach.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if !TARGET_OS_DRIVERKIT && (BUILDING_LIBDYLD || BUILDING_DYLD)
|
||||
#include <CrashReporterClient.h>
|
||||
#else
|
||||
#define CRSetCrashLogMessage(x)
|
||||
#define CRSetCrashLogMessage2(x)
|
||||
#endif
|
||||
|
||||
#define VIS_HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
|
||||
//
|
||||
// Similar to std::vector<> but storage is pre-allocated and cannot be re-allocated.
|
||||
// Storage is normally stack allocated.
|
||||
//
|
||||
// Use push_back() to add elements and range based for loops to iterate and [] to access by index.
|
||||
//
|
||||
template <typename T>
|
||||
class VIS_HIDDEN Array
|
||||
{
|
||||
public:
|
||||
Array() : _elements(nullptr), _allocCount(0), _usedCount(0) {}
|
||||
Array(T* storage, uintptr_t allocCount, uintptr_t usedCount=0) : _elements(storage), _allocCount(allocCount), _usedCount(usedCount) {}
|
||||
void setInitialStorage(T* storage, uintptr_t allocCount) { assert(_usedCount == 0); _elements=storage; _allocCount=allocCount; }
|
||||
|
||||
T& operator[](size_t idx) { assert(idx < _usedCount); return _elements[idx]; }
|
||||
const T& operator[](size_t idx) const { assert(idx < _usedCount); return _elements[idx]; }
|
||||
T& back() { assert(_usedCount > 0); return _elements[_usedCount-1]; }
|
||||
uintptr_t count() const { return _usedCount; }
|
||||
uintptr_t maxCount() const { return _allocCount; }
|
||||
uintptr_t freeCount() const { return _allocCount - _usedCount; }
|
||||
bool empty() const { return (_usedCount == 0); }
|
||||
uintptr_t index(const T& element) { return &element - _elements; }
|
||||
void push_back(const T& t) { assert(_usedCount < _allocCount); _elements[_usedCount++] = t; }
|
||||
void default_constuct_back() { assert(_usedCount < _allocCount); new (&_elements[_usedCount++])T(); }
|
||||
void pop_back() { assert(_usedCount > 0); _usedCount--; }
|
||||
T* begin() { return &_elements[0]; }
|
||||
T* end() { return &_elements[_usedCount]; }
|
||||
const T* begin() const { return &_elements[0]; }
|
||||
const T* end() const { return &_elements[_usedCount]; }
|
||||
const Array<T> subArray(uintptr_t start, uintptr_t size) const { assert(start+size <= _usedCount);
|
||||
return Array<T>(&_elements[start], size, size); }
|
||||
bool contains(const T& targ) const { for (const T& a : *this) { if ( a == targ ) return true; } return false; }
|
||||
void remove(size_t idx) { assert(idx < _usedCount); ::memmove(&_elements[idx], &_elements[idx+1], sizeof(T)*(_usedCount-idx-1)); }
|
||||
|
||||
protected:
|
||||
T* _elements;
|
||||
uintptr_t _allocCount;
|
||||
uintptr_t _usedCount;
|
||||
};
|
||||
|
||||
|
||||
// If an Array<>.setInitialStorage() is used, the array may out live the stack space of the storage.
|
||||
// To allow cleanup to be done to array elements when the stack goes away, you can make a local
|
||||
// variable of ArrayFinalizer<>.
|
||||
template <typename T>
|
||||
class VIS_HIDDEN ArrayFinalizer
|
||||
{
|
||||
public:
|
||||
typedef void (^CleanUp)(T& element);
|
||||
ArrayFinalizer(Array<T>& array, CleanUp handler) : _array(array), _handler(handler) { }
|
||||
~ArrayFinalizer() { for(T& element : _array) _handler(element); }
|
||||
private:
|
||||
Array<T>& _array;
|
||||
CleanUp _handler;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Similar to Array<> but if the array overflows, it is re-allocated using vm_allocate().
|
||||
// When the variable goes out of scope, any vm_allocate()ed storage is released.
|
||||
// if MAXCOUNT is specified, then only one one vm_allocate() to that size is done.
|
||||
//
|
||||
template <typename T, uintptr_t MAXCOUNT=0xFFFFFFFF>
|
||||
class VIS_HIDDEN OverflowSafeArray : public Array<T>
|
||||
{
|
||||
public:
|
||||
OverflowSafeArray() : Array<T>(nullptr, 0) {}
|
||||
OverflowSafeArray(T* stackStorage, uintptr_t stackAllocCount) : Array<T>(stackStorage, stackAllocCount) {}
|
||||
~OverflowSafeArray();
|
||||
|
||||
OverflowSafeArray(OverflowSafeArray&) = default;
|
||||
OverflowSafeArray& operator=(OverflowSafeArray&& other);
|
||||
|
||||
void push_back(const T& t) { verifySpace(1); this->_elements[this->_usedCount++] = t; }
|
||||
void default_constuct_back() { verifySpace(1); new (&this->_elements[this->_usedCount++])T(); }
|
||||
void clear() { this->_usedCount = 0; }
|
||||
void reserve(uintptr_t n) { if (this->_allocCount < n) growTo(n); }
|
||||
void resize(uintptr_t n) {
|
||||
if (n == this->_usedCount)
|
||||
return;
|
||||
if (n < this->_usedCount) {
|
||||
this->_usedCount = n;
|
||||
return;
|
||||
}
|
||||
reserve(n);
|
||||
this->_usedCount = n;
|
||||
}
|
||||
|
||||
protected:
|
||||
void growTo(uintptr_t n);
|
||||
void verifySpace(uintptr_t n) { if (this->_usedCount+n > this->_allocCount) growTo(this->_usedCount + n); }
|
||||
|
||||
private:
|
||||
vm_address_t _overflowBuffer = 0;
|
||||
vm_size_t _overflowBufferSize = 0;
|
||||
};
|
||||
|
||||
|
||||
template <typename T, uintptr_t MAXCOUNT>
|
||||
inline void OverflowSafeArray<T,MAXCOUNT>::growTo(uintptr_t n)
|
||||
{
|
||||
vm_address_t oldBuffer = _overflowBuffer;
|
||||
vm_size_t oldBufferSize = _overflowBufferSize;
|
||||
if ( MAXCOUNT != 0xFFFFFFFF ) {
|
||||
assert(oldBufferSize == 0); // only re-alloc once
|
||||
// MAXCOUNT is specified, so immediately jump to that size
|
||||
_overflowBufferSize = round_page(std::max(MAXCOUNT, n) * sizeof(T));
|
||||
}
|
||||
else {
|
||||
// MAXCOUNT is not specified, keep doubling size
|
||||
_overflowBufferSize = round_page(std::max(this->_allocCount * 2, n) * sizeof(T));
|
||||
}
|
||||
kern_return_t kr = ::vm_allocate(mach_task_self(), &_overflowBuffer, _overflowBufferSize, VM_FLAGS_ANYWHERE);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
#if BUILDING_LIBDYLD
|
||||
//FIXME We should figure out a way to do this in dyld
|
||||
char crashString[256];
|
||||
snprintf(crashString, 256, "OverflowSafeArray failed to allocate %lu bytes, vm_allocate returned: %d\n",
|
||||
_overflowBufferSize, kr);
|
||||
CRSetCrashLogMessage(crashString);
|
||||
#endif
|
||||
assert(0);
|
||||
}
|
||||
::memcpy((void*)_overflowBuffer, this->_elements, this->_usedCount*sizeof(T));
|
||||
this->_elements = (T*)_overflowBuffer;
|
||||
this->_allocCount = _overflowBufferSize / sizeof(T);
|
||||
|
||||
if ( oldBuffer != 0 )
|
||||
::vm_deallocate(mach_task_self(), oldBuffer, oldBufferSize);
|
||||
}
|
||||
|
||||
template <typename T, uintptr_t MAXCOUNT>
|
||||
inline OverflowSafeArray<T,MAXCOUNT>::~OverflowSafeArray()
|
||||
{
|
||||
if ( _overflowBuffer != 0 )
|
||||
::vm_deallocate(mach_task_self(), _overflowBuffer, _overflowBufferSize);
|
||||
}
|
||||
|
||||
template <typename T, uintptr_t MAXCOUNT>
|
||||
inline OverflowSafeArray<T,MAXCOUNT>& OverflowSafeArray<T,MAXCOUNT>::operator=(OverflowSafeArray<T,MAXCOUNT>&& other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
// Free our buffer if we have one
|
||||
if ( _overflowBuffer != 0 )
|
||||
::vm_deallocate(mach_task_self(), _overflowBuffer, _overflowBufferSize);
|
||||
|
||||
// Now take the buffer from the other array
|
||||
this->_elements = other._elements;
|
||||
this->_allocCount = other._allocCount;
|
||||
this->_usedCount = other._usedCount;
|
||||
_overflowBuffer = other._overflowBuffer;
|
||||
_overflowBufferSize = other._overflowBufferSize;
|
||||
|
||||
// Now reset the other object so that it doesn't try to deallocate the memory later.
|
||||
other._elements = nullptr;
|
||||
other._allocCount = 0;
|
||||
other._usedCount = 0;
|
||||
other._overflowBuffer = 0;
|
||||
other._overflowBufferSize = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if BUILDING_LIBDYLD
|
||||
//
|
||||
// Similar to std::vector<> but storage is initially allocated in the object. But if it needs to
|
||||
// grow beyond, it will use malloc. The QUANT template arg is the "quantum" size for allocations.
|
||||
// When the allocation needs to be grown, it is re-allocated at the required size rounded up to
|
||||
// the next quantum.
|
||||
//
|
||||
// Use push_back() to add elements and range based for loops to iterate and [] to access by index.
|
||||
//
|
||||
// Note: this should be a subclass of Array<T> but doing so disables the compiler from optimizing away static constructors
|
||||
//
|
||||
template <typename T, int QUANT=4, int INIT=1>
|
||||
class VIS_HIDDEN GrowableArray
|
||||
{
|
||||
public:
|
||||
|
||||
T& operator[](size_t idx) { assert(idx < _usedCount); return _elements[idx]; }
|
||||
const T& operator[](size_t idx) const { assert(idx < _usedCount); return _elements[idx]; }
|
||||
T& back() { assert(_usedCount > 0); return _elements[_usedCount-1]; }
|
||||
uintptr_t count() const { return _usedCount; }
|
||||
uintptr_t maxCount() const { return _allocCount; }
|
||||
bool empty() const { return (_usedCount == 0); }
|
||||
uintptr_t index(const T& element) { return &element - _elements; }
|
||||
void push_back(const T& t) { verifySpace(1); _elements[_usedCount++] = t; }
|
||||
void append(const Array<T>& a);
|
||||
void pop_back() { assert(_usedCount > 0); _usedCount--; }
|
||||
T* begin() { return &_elements[0]; }
|
||||
T* end() { return &_elements[_usedCount]; }
|
||||
const T* begin() const { return &_elements[0]; }
|
||||
const T* end() const { return &_elements[_usedCount]; }
|
||||
const Array<T> subArray(uintptr_t start, uintptr_t size) const { assert(start+size <= _usedCount);
|
||||
return Array<T>(&_elements[start], size, size); }
|
||||
const Array<T>& array() const { return *((Array<T>*)this); }
|
||||
bool contains(const T& targ) const { for (const T& a : *this) { if ( a == targ ) return true; } return false; }
|
||||
void erase(T& targ);
|
||||
|
||||
protected:
|
||||
void growTo(uintptr_t n);
|
||||
void verifySpace(uintptr_t n) { if (this->_usedCount+n > this->_allocCount) growTo(this->_usedCount + n); }
|
||||
|
||||
private:
|
||||
T* _elements = _initialAlloc;
|
||||
uintptr_t _allocCount = INIT;
|
||||
uintptr_t _usedCount = 0;
|
||||
T _initialAlloc[INIT] = { };
|
||||
};
|
||||
|
||||
|
||||
template <typename T, int QUANT, int INIT>
|
||||
inline void GrowableArray<T,QUANT,INIT>::growTo(uintptr_t n)
|
||||
{
|
||||
uintptr_t newCount = (n + QUANT - 1) & (-QUANT);
|
||||
T* newArray = (T*)::malloc(sizeof(T)*newCount);
|
||||
T* oldArray = this->_elements;
|
||||
if ( this->_usedCount != 0 )
|
||||
::memcpy(newArray, oldArray, sizeof(T)*this->_usedCount);
|
||||
this->_elements = newArray;
|
||||
this->_allocCount = newCount;
|
||||
if ( oldArray != this->_initialAlloc )
|
||||
::free(oldArray);
|
||||
}
|
||||
|
||||
template <typename T, int QUANT, int INIT>
|
||||
inline void GrowableArray<T,QUANT,INIT>::append(const Array<T>& a)
|
||||
{
|
||||
verifySpace(a.count());
|
||||
::memcpy(&_elements[_usedCount], a.begin(), a.count()*sizeof(T));
|
||||
_usedCount += a.count();
|
||||
}
|
||||
|
||||
template <typename T, int QUANT, int INIT>
|
||||
inline void GrowableArray<T,QUANT,INIT>::erase(T& targ)
|
||||
{
|
||||
intptr_t index = &targ - _elements;
|
||||
assert(index >= 0);
|
||||
assert(index < (intptr_t)_usedCount);
|
||||
intptr_t moveCount = _usedCount-index-1;
|
||||
if ( moveCount > 0 )
|
||||
::memcpy(&_elements[index], &_elements[index+1], moveCount*sizeof(T));
|
||||
_usedCount -= 1;
|
||||
}
|
||||
|
||||
#endif // BUILDING_LIBDYLD
|
||||
|
||||
|
||||
|
||||
// STACK_ALLOC_ARRAY(foo, myarray, 10);
|
||||
// myarray is of type Array<foo>
|
||||
#define STACK_ALLOC_ARRAY(_type, _name, _count) \
|
||||
uintptr_t __##_name##_array_alloc[1 + ((sizeof(_type)*(_count))/sizeof(uintptr_t))]; \
|
||||
__block dyld3::Array<_type> _name((_type*)__##_name##_array_alloc, _count);
|
||||
|
||||
|
||||
// STACK_ALLOC_OVERFLOW_SAFE_ARRAY(foo, myarray, 10);
|
||||
// myarray is of type OverflowSafeArray<foo>
|
||||
#define STACK_ALLOC_OVERFLOW_SAFE_ARRAY(_type, _name, _count) \
|
||||
uintptr_t __##_name##_array_alloc[1 + ((sizeof(_type)*(_count))/sizeof(uintptr_t))]; \
|
||||
__block dyld3::OverflowSafeArray<_type> _name((_type*)__##_name##_array_alloc, _count);
|
||||
|
||||
|
||||
// work around compiler bug where:
|
||||
// __block type name[count];
|
||||
// is not accessible in a block
|
||||
#define BLOCK_ACCCESSIBLE_ARRAY(_type, _name, _count) \
|
||||
_type __##_name##_array_alloc[_count]; \
|
||||
_type* _name = __##_name##_array_alloc;
|
||||
|
||||
|
||||
} // namespace dyld3
|
||||
|
||||
#endif /* Array_h */
|
82
src/dyld/dyld3/BootArgs.cpp
Normal file
82
src/dyld/dyld3/BootArgs.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
//
|
||||
// BootArgs.cpp
|
||||
// dyld
|
||||
//
|
||||
// Created by Louis Gerbarg on 11/14/18.
|
||||
//
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#include "Loading.h" // For internalInstall()
|
||||
#include "BootArgs.h"
|
||||
|
||||
namespace dyld3 {
|
||||
/*
|
||||
* Checks to see if there are any args that impact dyld. These args
|
||||
* can be set sevaral ways. These will only be honored on development
|
||||
* and Apple Internal builds.
|
||||
*/
|
||||
bool BootArgs::contains(const char* arg)
|
||||
{
|
||||
//FIXME: Use strnstr(). Unfortunately we are missing an imp in libc.a
|
||||
#if TARGET_OS_SIMULATOR
|
||||
return false;
|
||||
#else
|
||||
// don't check for boot-args on customer installs
|
||||
if ( !internalInstall() )
|
||||
return false;
|
||||
|
||||
// get length of full boot-args string
|
||||
size_t len;
|
||||
if ( sysctlbyname("kern.bootargs", NULL, &len, NULL, 0) != 0 )
|
||||
return false;
|
||||
|
||||
// get copy of boot-args string
|
||||
char bootArgsBuffer[len];
|
||||
if ( sysctlbyname("kern.bootargs", bootArgsBuffer, &len, NULL, 0) != 0 )
|
||||
return false;
|
||||
|
||||
// return true if 'arg' is a sub-string of boot-args
|
||||
return (strstr(bootArgsBuffer, arg) != nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t BootArgs::_flags = 0;
|
||||
|
||||
bool BootArgs::forceCustomerCache() {
|
||||
return (_flags & kForceCustomerCacheMask);
|
||||
}
|
||||
|
||||
bool BootArgs::forceDyld2() {
|
||||
// If both force dyld2 and dyld3 are set then use dyld3
|
||||
if (_flags & kForceDyld3CacheMask) { return false; }
|
||||
if (_flags & kForceDyld2CacheMask) { return true; }
|
||||
if (contains("force_dyld2=1")) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BootArgs::forceDyld3() {
|
||||
return ((_flags & kForceDyld3CacheMask) || contains("force_dyld3=1"));
|
||||
}
|
||||
|
||||
bool BootArgs::enableDyldTestMode() {
|
||||
return (_flags & kDyldTestModeMask);
|
||||
}
|
||||
|
||||
bool BootArgs::enableCompactImageInfo() {
|
||||
return (_flags & kEnableCompactImageInfoMask);
|
||||
}
|
||||
|
||||
void BootArgs::setFlags(uint64_t flags) {
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
return;
|
||||
#else
|
||||
// don't check for boot-args on customer installs
|
||||
if ( !internalInstall() )
|
||||
return;
|
||||
_flags = flags;
|
||||
#endif
|
||||
}
|
||||
};
|
38
src/dyld/dyld3/BootArgs.h
Normal file
38
src/dyld/dyld3/BootArgs.h
Normal file
@ -0,0 +1,38 @@
|
||||
//
|
||||
// BootArgs.hpp
|
||||
// dyld
|
||||
//
|
||||
// Created by Louis Gerbarg on 11/14/18.
|
||||
//
|
||||
|
||||
#ifndef __DYLD_BOOTARGS_H__
|
||||
#define __DYLD_BOOTARGS_H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define VIS_HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
namespace dyld3 {
|
||||
#if BUILDING_DYLD
|
||||
struct VIS_HIDDEN BootArgs {
|
||||
static bool contains(const char* arg);
|
||||
static bool forceCustomerCache();
|
||||
static bool forceDyld2();
|
||||
static bool forceDyld3();
|
||||
static bool enableDyldTestMode();
|
||||
static bool enableCompactImageInfo();
|
||||
static void setFlags(uint64_t flags);
|
||||
private:
|
||||
static const uint64_t kForceCustomerCacheMask = 1<<0;
|
||||
static const uint64_t kDyldTestModeMask = 1<<1;
|
||||
static const uint64_t kForceDyld2CacheMask = 1<<15;
|
||||
static const uint64_t kForceDyld3CacheMask = 1<<16;
|
||||
static const uint64_t kEnableCompactImageInfoMask = 1<<17;
|
||||
//FIXME: Move this into __DATA_CONST once it is enabled for dyld
|
||||
static uint64_t _flags;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace dyld3
|
||||
|
||||
#endif /* __DYLD_BOOTARGS_H__ */
|
1517
src/dyld/dyld3/Closure.cpp
Normal file
1517
src/dyld/dyld3/Closure.cpp
Normal file
File diff suppressed because it is too large
Load Diff
957
src/dyld/dyld3/Closure.h
Normal file
957
src/dyld/dyld3/Closure.h
Normal file
@ -0,0 +1,957 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef Closures_h
|
||||
#define Closures_h
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach-o/loader.h>
|
||||
|
||||
#include "Diagnostics.h"
|
||||
#include "Array.h"
|
||||
#include "MachOLoaded.h"
|
||||
#include "SupportedArchs.h"
|
||||
|
||||
namespace objc_opt {
|
||||
struct objc_opt_t;
|
||||
}
|
||||
|
||||
namespace dyld3 {
|
||||
namespace closure {
|
||||
|
||||
|
||||
|
||||
// bump this number each time binary format changes
|
||||
enum { kFormatVersion = 10 };
|
||||
|
||||
|
||||
typedef uint32_t ImageNum;
|
||||
|
||||
const ImageNum kFirstDyldCacheImageNum = 0x00000001;
|
||||
const ImageNum kLastDyldCacheImageNum = 0x00000FFF;
|
||||
const ImageNum kFirstOtherOSImageNum = 0x00001001;
|
||||
const ImageNum kLastOtherOSImageNum = 0x00001FFF;
|
||||
const ImageNum kFirstLaunchClosureImageNum = 0x00002000;
|
||||
const ImageNum kMissingWeakLinkedImage = 0x0FFFFFFF;
|
||||
|
||||
class ObjCSelectorOpt;
|
||||
class ObjCClassOpt;
|
||||
class ObjCClassDuplicatesOpt;
|
||||
|
||||
//
|
||||
// Generic typed range of bytes (similar to load commands)
|
||||
// Must be 4-byte aligned
|
||||
//
|
||||
struct VIS_HIDDEN TypedBytes
|
||||
{
|
||||
enum class Type : uint32_t {
|
||||
// containers which have an overall length and TypedBytes inside their content
|
||||
launchClosure = 1, // contains TypedBytes of closure attributes including imageArray
|
||||
imageArray = 2, // sizeof(ImageArray) + sizeof(uint32_t)*count + size of all images
|
||||
image = 3, // contains TypedBytes of image attributes
|
||||
dlopenClosure = 4, // contains TypedBytes of closure attributes including imageArray
|
||||
|
||||
// attributes for Images
|
||||
imageFlags = 7, // sizeof(Image::Flags)
|
||||
pathWithHash = 8, // len = uint32_t + length path + 1, use multiple entries for aliases
|
||||
fileInodeAndTime = 9, // sizeof(FileInfo)
|
||||
cdHash = 10, // 20, use multiple entries on watchOS for all hashes
|
||||
uuid = 11, // 16
|
||||
mappingInfo = 12, // sizeof(MappingInfo)
|
||||
diskSegment = 13, // sizeof(DiskSegment) * count
|
||||
cacheSegment = 14, // sizeof(DyldCacheSegment) * count
|
||||
dependents = 15, // sizeof(LinkedImage) * count
|
||||
initOffsets = 16, // sizeof(uint32_t) * count
|
||||
dofOffsets = 17, // sizeof(uint32_t) * count
|
||||
codeSignLoc = 18, // sizeof(CodeSignatureLocation)
|
||||
fairPlayLoc = 19, // sizeof(FairPlayRange)
|
||||
rebaseFixups = 20, // sizeof(RebasePattern) * count
|
||||
bindFixups = 21, // sizeof(BindPattern) * count
|
||||
cachePatchInfo = 22, // deprecated
|
||||
textFixups = 23, // sizeof(TextFixupPattern) * count
|
||||
imageOverride = 24, // sizeof(ImageNum)
|
||||
initBefores = 25, // sizeof(ImageNum) * count
|
||||
initsSection = 26, // sizeof(InitializerSectionRange)
|
||||
chainedFixupsTargets = 27, // sizeof(ResolvedSymbolTarget) * count
|
||||
termOffsets = 28, // sizeof(uint32_t) * count
|
||||
chainedStartsOffset = 29, // sizeof(uint64_t)
|
||||
objcFixups = 30, // sizeof(ResolvedSymbolTarget) + (sizeof(uint32_t) * 2) + (sizeof(ProtocolISAFixup) * count) + (sizeof(SelectorReferenceFixup) * count)
|
||||
|
||||
// attributes for Closures (launch or dlopen)
|
||||
closureFlags = 32, // sizeof(Closure::Flags)
|
||||
dyldCacheUUID = 33, // 16
|
||||
missingFiles = 34,
|
||||
envVar = 35, // "DYLD_BLAH=stuff"
|
||||
topImage = 36, // sizeof(ImageNum)
|
||||
libDyldEntry = 37, // sizeof(ResolvedSymbolTarget)
|
||||
libSystemNum = 38, // sizeof(ImageNum)
|
||||
bootUUID = 39, // c-string 40
|
||||
mainEntry = 40, // sizeof(ResolvedSymbolTarget)
|
||||
startEntry = 41, // sizeof(ResolvedSymbolTarget) // used by programs built with crt1.o
|
||||
cacheOverrides = 42, // sizeof(PatchEntry) * count // used if process uses interposing or roots (cached dylib overrides)
|
||||
interposeTuples = 43, // sizeof(InterposingTuple) * count
|
||||
existingFiles = 44, // uint64_t + (SkippedFiles * count)
|
||||
selectorTable = 45, // uint32_t + (sizeof(ObjCSelectorImage) * count) + hashTable size
|
||||
classTable = 46, // (3 * uint32_t) + (sizeof(ObjCClassImage) * count) + classHashTable size + protocolHashTable size
|
||||
warning = 47, // len = uint32_t + length path + 1, use one entry per warning
|
||||
duplicateClassesTable = 48, // duplicateClassesHashTable
|
||||
};
|
||||
|
||||
Type type : 8;
|
||||
uint32_t payloadLength : 24;
|
||||
|
||||
const void* payload() const;
|
||||
void* payload();
|
||||
};
|
||||
|
||||
static_assert(sizeof(TypedBytes) == 4, "Wrong size for TypedBytes");
|
||||
|
||||
|
||||
//
|
||||
// A TypedBytes which is a bag of other TypedBytes
|
||||
//
|
||||
struct VIS_HIDDEN ContainerTypedBytes : TypedBytes
|
||||
{
|
||||
void forEachAttribute(void (^callback)(const TypedBytes* typedBytes, bool& stop)) const;
|
||||
void forEachAttributePayload(Type requestedType, void (^handler)(const void* payload, uint32_t size, bool& stop)) const;
|
||||
const void* findAttributePayload(Type requestedType, uint32_t* payloadSize=nullptr) const;
|
||||
private:
|
||||
const TypedBytes* first() const;
|
||||
const TypedBytes* next(const TypedBytes*) const;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Information about a mach-o file
|
||||
//
|
||||
struct VIS_HIDDEN Image : ContainerTypedBytes
|
||||
{
|
||||
enum class LinkKind { regular=0, weak=1, upward=2, reExport=3 };
|
||||
|
||||
size_t size() const;
|
||||
ImageNum imageNum() const;
|
||||
bool representsImageNum(ImageNum num) const; // imageNum() or isOverrideOfDyldCacheImage()
|
||||
uint32_t maxLoadCount() const;
|
||||
const char* path() const;
|
||||
const char* leafName() const;
|
||||
bool getUuid(uuid_t) const;
|
||||
bool isInvalid() const;
|
||||
bool inDyldCache() const;
|
||||
bool hasObjC() const;
|
||||
bool hasInitializers() const;
|
||||
bool hasPrecomputedObjC() const;
|
||||
bool hasTerminators() const;
|
||||
bool hasReadOnlyData() const;
|
||||
bool hasChainedFixups() const;
|
||||
bool isBundle() const;
|
||||
bool isDylib() const;
|
||||
bool isExecutable() const;
|
||||
bool hasWeakDefs() const;
|
||||
bool mayHavePlusLoads() const;
|
||||
bool is64() const;
|
||||
bool neverUnload() const;
|
||||
bool cwdMustBeThisDir() const;
|
||||
bool isPlatformBinary() const;
|
||||
bool overridableDylib() const;
|
||||
bool hasFileModTimeAndInode(uint64_t& inode, uint64_t& mTime) const;
|
||||
void forEachCDHash(void (^handler)(const uint8_t cdHash[20], bool& stop)) const;
|
||||
void forEachAlias(void (^handler)(const char* aliasPath, bool& stop)) const;
|
||||
void forEachDependentImage(void (^handler)(uint32_t dependentIndex, LinkKind kind, ImageNum imageNum, bool& stop)) const;
|
||||
ImageNum dependentImageNum(uint32_t depIndex) const;
|
||||
bool containsAddress(const void* addr, const void* imageLoadAddress, uint8_t* permissions=nullptr) const;
|
||||
bool forEachInitializerSection(void (^handler)(uint32_t sectionOffset, uint32_t sectionSize)) const;
|
||||
void forEachInitializer(const void* imageLoadAddress, void (^handler)(const void* initializer)) const;
|
||||
void forEachTerminator(const void* imageLoadAddress, void (^handler)(const void* terminator)) const;
|
||||
void forEachImageToInitBefore(void (^handler)(ImageNum imageToInit, bool& stop)) const;
|
||||
void forEachDOF(const void* imageLoadAddress, void (^handler)(const void* initializer)) const;
|
||||
bool hasPathWithHash(const char* path, uint32_t hash) const;
|
||||
bool isOverrideOfDyldCacheImage(ImageNum& cacheImageNum) const;
|
||||
uint64_t textSize() const;
|
||||
|
||||
union ResolvedSymbolTarget
|
||||
{
|
||||
enum Kinds { kindRebase, kindSharedCache, kindImage, kindAbsolute };
|
||||
|
||||
struct Rebase {
|
||||
uint64_t kind : 2, // kindRebase
|
||||
unused : 62; // all zeros
|
||||
};
|
||||
struct SharedCache {
|
||||
uint64_t kind : 2; // kindSharedCache
|
||||
int64_t offset : 62;
|
||||
};
|
||||
struct Image {
|
||||
uint64_t kind : 2, // kindImage
|
||||
imageNum : 22; // ImageNum
|
||||
int64_t offset : 40;
|
||||
};
|
||||
struct Absolute {
|
||||
uint64_t kind : 2, // kindAbsolute
|
||||
value : 62; // sign extended
|
||||
};
|
||||
Rebase rebase;
|
||||
SharedCache sharedCache;
|
||||
Image image;
|
||||
Absolute absolute;
|
||||
uint64_t raw;
|
||||
|
||||
bool operator==(const ResolvedSymbolTarget& rhs) const {
|
||||
return (raw == rhs.raw);
|
||||
}
|
||||
bool operator!=(const ResolvedSymbolTarget& rhs) const {
|
||||
return (raw != rhs.raw);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(ResolvedSymbolTarget) == 8);
|
||||
|
||||
|
||||
// ObjC optimisations
|
||||
struct ObjCImageOffset {
|
||||
union {
|
||||
uint32_t raw = 0;
|
||||
struct {
|
||||
uint32_t imageIndex : 8;
|
||||
uint32_t imageOffset : 24;
|
||||
};
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
// The unused value so that we have a sentinel in our hash table
|
||||
sentinelValue = 0xFFFFFFFF,
|
||||
|
||||
// The maximum image index
|
||||
maximumImageIndex = (1U << 8) - 1,
|
||||
|
||||
// The maximum offset from the start of the strings section
|
||||
maximumOffset = (1U << 24) - 1
|
||||
};
|
||||
};
|
||||
|
||||
struct ObjCClassNameImageOffset {
|
||||
union {
|
||||
uint32_t raw = 0;
|
||||
struct {
|
||||
uint32_t classNameImageIndex : 8;
|
||||
uint32_t classNameImageOffset : 24;
|
||||
};
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
// The unused value so that we have a sentinel in our hash table
|
||||
sentinelValue = 0xFFFFFFFF,
|
||||
|
||||
// The maximum image index
|
||||
maximumImageIndex = (1U << 8) - 1,
|
||||
|
||||
// The maximum offset from the start of the strings section
|
||||
maximumOffset = (1U << 24) - 1
|
||||
};
|
||||
};
|
||||
|
||||
struct ObjCClassImageOffset {
|
||||
union {
|
||||
uint32_t raw = 0;
|
||||
struct {
|
||||
uint32_t imageIndex : 8;
|
||||
uint32_t imageOffset : 23;
|
||||
uint32_t isDuplicate : 1; // == 0
|
||||
} classData;
|
||||
struct {
|
||||
uint32_t count : 8;
|
||||
uint32_t index : 23;
|
||||
uint32_t isDuplicate : 1; // == 1
|
||||
} duplicateData;
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
// The unused value so that we have a sentinel in our hash table
|
||||
sentinelValue = 0xFFFFFFFF,
|
||||
|
||||
// The maximum image index
|
||||
maximumImageIndex = (1U << 8) - 1,
|
||||
|
||||
// The maximum offset from the start of the class data section
|
||||
maximumOffset = (1U << 23) - 1
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(ObjCClassImageOffset) == 4, "Invalid size");
|
||||
|
||||
static_assert(ObjCClassNameImageOffset::maximumImageIndex == ObjCClassImageOffset::maximumImageIndex , "Invalid indices");
|
||||
|
||||
struct ObjCDuplicateClass {
|
||||
union {
|
||||
uint32_t raw = 0;
|
||||
struct {
|
||||
uint32_t sharedCacheClassOptIndex : 20;
|
||||
uint32_t sharedCacheClassDuplicateIndex : 12;
|
||||
};
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
// The unused value so that we have a sentinel in our hash table
|
||||
sentinelValue = 0xFFFFFFFF
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(ObjCDuplicateClass) == 4, "Invalid size");
|
||||
|
||||
struct ObjCSelectorImage {
|
||||
ImageNum imageNum;
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
struct ObjCClassImage {
|
||||
ImageNum imageNum;
|
||||
uint32_t offsetOfClassNames;
|
||||
uint32_t offsetOfClasses;
|
||||
};
|
||||
|
||||
typedef MachOLoaded::ChainedFixupPointerOnDisk ChainedFixupPointerOnDisk;
|
||||
|
||||
// the following are only valid if inDyldCache() returns true
|
||||
uint32_t cacheOffset() const;
|
||||
uint32_t patchStartIndex() const;
|
||||
uint32_t patchCount() const;
|
||||
void forEachCacheSegment(void (^handler)(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const;
|
||||
|
||||
|
||||
// the following are only valid if inDyldCache() returns false
|
||||
uint64_t vmSizeToMap() const;
|
||||
uint64_t sliceOffsetInFile() const;
|
||||
bool hasCodeSignature(uint32_t& fileOffset, uint32_t& size) const;
|
||||
bool isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const;
|
||||
void forEachDiskSegment(void (^handler)(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize,
|
||||
uint8_t permissions, bool laterReadOnly, bool& stop)) const;
|
||||
void forEachFixup(void (^rebase)(uint64_t imageOffsetToRebase, bool& stop),
|
||||
void (^bind)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop),
|
||||
void (^chainedFixups)(uint64_t imageOffsetToStarts, const Array<ResolvedSymbolTarget>& targets, bool& stop),
|
||||
void (^fixupObjCImageInfo)(uint64_t imageOffsetToFixup),
|
||||
void (^fixupObjCProtocol)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop),
|
||||
void (^fixupObjCSelRef)(uint64_t imageOffsetToFixup, uint32_t selectorIndex, bool inSharedCache, bool& stop),
|
||||
void (^fixupObjCStableSwift)(uint64_t imageOffsetToFixup, bool& stop),
|
||||
void (^fixupObjCMethodList)(uint64_t imageOffsetToFixup, bool& stop)) const;
|
||||
void forEachTextReloc(void (^rebase)(uint32_t imageOffsetToRebase, bool& stop),
|
||||
void (^bind)(uint32_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop)) const;
|
||||
|
||||
static_assert(sizeof(ResolvedSymbolTarget) == 8, "Overflow in size of SymbolTargetLocation");
|
||||
|
||||
static uint32_t hashFunction(const char*);
|
||||
|
||||
private:
|
||||
friend struct Closure;
|
||||
friend class ImageWriter;
|
||||
friend class ClosureBuilder;
|
||||
friend class ClosureWriter;
|
||||
friend class LaunchClosureWriter;
|
||||
|
||||
uint32_t pageSize() const;
|
||||
|
||||
struct Flags
|
||||
{
|
||||
uint64_t imageNum : 16,
|
||||
maxLoadCount : 12,
|
||||
isInvalid : 1, // an error occurred creating the info for this image
|
||||
has16KBpages : 1,
|
||||
is64 : 1,
|
||||
hasObjC : 1,
|
||||
mayHavePlusLoads : 1,
|
||||
isEncrypted : 1, // image is DSMOS or FairPlay encrypted
|
||||
hasWeakDefs : 1,
|
||||
neverUnload : 1,
|
||||
cwdSameAsThis : 1, // dylibs use file system relative paths, cwd must be main's dir
|
||||
isPlatformBinary : 1, // part of OS - can be loaded into LV process
|
||||
isBundle : 1,
|
||||
isDylib : 1,
|
||||
isExecutable : 1,
|
||||
overridableDylib : 1, // only applicable to cached dylibs
|
||||
inDyldCache : 1,
|
||||
hasTerminators : 1,
|
||||
hasReadOnlyData : 1,
|
||||
hasChainedFixups : 1,
|
||||
hasPrecomputedObjC : 1,
|
||||
padding : 17;
|
||||
};
|
||||
|
||||
static_assert(sizeof(Flags) == sizeof(uint64_t), "Flags overflow");
|
||||
|
||||
const Flags& getFlags() const;
|
||||
|
||||
struct PathAndHash
|
||||
{
|
||||
uint32_t hash;
|
||||
char path[];
|
||||
};
|
||||
|
||||
// In disk based images, all segments are multiples of page size
|
||||
// This struct just tracks the size (disk and vm) of each segment.
|
||||
// This is compact for most every image which have contiguous segments.
|
||||
// If the image does not have contiguous segments (rare), an extra
|
||||
// DiskSegment is inserted with the paddingNotSeg bit set.
|
||||
struct DiskSegment
|
||||
{
|
||||
uint64_t filePageCount : 30,
|
||||
vmPageCount : 30,
|
||||
permissions : 3,
|
||||
paddingNotSeg : 1;
|
||||
|
||||
// We only have three bits for permissions, and need a way to
|
||||
// encode segments that are initially r/w then made read-only
|
||||
// after fixups are done. Previously, the only valid patterns
|
||||
// were: ---, r--, rw-, r-x. We now add -w- to mean r/w -> r/o.
|
||||
enum { kReadOnlyDataPermissions = VM_PROT_WRITE };
|
||||
};
|
||||
|
||||
|
||||
// In cache DATA_DIRTY is not page aligned or sized
|
||||
// This struct allows segments with any alignment and up to 256MB in size
|
||||
struct DyldCacheSegment
|
||||
{
|
||||
uint64_t cacheOffset : 32,
|
||||
size : 28,
|
||||
permissions : 4;
|
||||
};
|
||||
|
||||
struct CodeSignatureLocation
|
||||
{
|
||||
uint32_t fileOffset;
|
||||
uint32_t fileSize;
|
||||
};
|
||||
|
||||
struct FileInfo
|
||||
{
|
||||
uint64_t inode;
|
||||
uint64_t modTime;
|
||||
};
|
||||
|
||||
struct FairPlayRange
|
||||
{
|
||||
uint32_t rangeStart; // The byte offset of the start of the range.
|
||||
uint32_t rangeLength; // How long is the fairplay range in bytes
|
||||
};
|
||||
|
||||
struct MappingInfo
|
||||
{
|
||||
uint32_t totalVmPages;
|
||||
uint32_t sliceOffsetIn4K;
|
||||
};
|
||||
|
||||
struct InitializerSectionRange
|
||||
{
|
||||
uint32_t sectionOffset;
|
||||
uint32_t sectionSize;
|
||||
};
|
||||
|
||||
struct LinkedImage {
|
||||
|
||||
LinkedImage() : imgNum(0), linkKind(0) {
|
||||
}
|
||||
LinkedImage(LinkKind k, ImageNum num) : imgNum(num), linkKind((uint32_t)k) {
|
||||
assert((num & 0xC0000000) == 0);
|
||||
}
|
||||
|
||||
LinkKind kind() const { return (LinkKind)linkKind; }
|
||||
ImageNum imageNum() const { return imgNum; }
|
||||
void clearKind() { linkKind = 0; }
|
||||
|
||||
bool operator==(const LinkedImage& rhs) const {
|
||||
return (linkKind == rhs.linkKind) && (imgNum == rhs.imgNum);
|
||||
}
|
||||
bool operator!=(const LinkedImage& rhs) const {
|
||||
return (linkKind != rhs.linkKind) || (imgNum != rhs.imgNum);
|
||||
}
|
||||
private:
|
||||
uint32_t imgNum : 30,
|
||||
linkKind : 2; // LinkKind
|
||||
};
|
||||
|
||||
const Array<LinkedImage> dependentsArray() const;
|
||||
|
||||
struct RebasePattern
|
||||
{
|
||||
uint32_t repeatCount : 20,
|
||||
contigCount : 8, // how many contiguous pointers neeed rebasing
|
||||
skipCount : 4; // how many pointers to skip between contig groups
|
||||
// If contigCount == 0, then there are no rebases for this entry,
|
||||
// instead it advances the rebase location by repeatCount*skipCount.
|
||||
// If all fields are zero, then the rebase position is reset to the start.
|
||||
// This is to support old binaries with some non-monotonically-increasing rebases.
|
||||
};
|
||||
const Array<RebasePattern> rebaseFixups() const;
|
||||
|
||||
struct BindPattern
|
||||
{
|
||||
Image::ResolvedSymbolTarget target;
|
||||
uint64_t startVmOffset : 40, // max 1TB offset
|
||||
skipCount : 8,
|
||||
repeatCount : 16;
|
||||
};
|
||||
const Array<BindPattern> bindFixups() const;
|
||||
|
||||
// An optimzied selector reference bind will either point to the shared cache
|
||||
// or a binary optimized in our launch closure. We can use the index in to each
|
||||
// of their respective selector hash tables as the target or the bind.
|
||||
union SelectorReferenceFixup
|
||||
{
|
||||
uint32_t chainStartVMOffset;
|
||||
struct {
|
||||
uint32_t index : 24, // max 16m entries in the table
|
||||
next : 7, // (next * 4) -> offset to next fixup
|
||||
inSharedCache : 1; // 0 -> in the closure. 1 -> in the cache
|
||||
} chainEntry;
|
||||
};
|
||||
|
||||
struct ProtocolISAFixup
|
||||
{
|
||||
uint64_t startVmOffset : 40, // max 1TB offset
|
||||
skipCount : 8,
|
||||
repeatCount : 16;
|
||||
};
|
||||
|
||||
struct ClassStableSwiftFixup
|
||||
{
|
||||
uint64_t startVmOffset : 40, // max 1TB offset
|
||||
skipCount : 8,
|
||||
repeatCount : 16;
|
||||
};
|
||||
|
||||
struct MethodListFixup
|
||||
{
|
||||
uint64_t startVmOffset : 40, // max 1TB offset
|
||||
skipCount : 8,
|
||||
repeatCount : 16;
|
||||
};
|
||||
|
||||
void objcFixups(ResolvedSymbolTarget& objcProtocolClassTarget,
|
||||
uint64_t& objcImageInfoVMOffset,
|
||||
Array<ProtocolISAFixup>& protocolISAFixups,
|
||||
Array<SelectorReferenceFixup>& selRefFixups,
|
||||
Array<ClassStableSwiftFixup>& classStableSwiftFixups,
|
||||
Array<MethodListFixup>& methodListFixups) const;
|
||||
|
||||
struct TextFixupPattern
|
||||
{
|
||||
Image::ResolvedSymbolTarget target;
|
||||
uint32_t startVmOffset;
|
||||
uint16_t repeatCount;
|
||||
uint16_t skipCount;
|
||||
};
|
||||
const Array<TextFixupPattern> textFixups() const;
|
||||
|
||||
// for use with chained fixups
|
||||
uint64_t chainedStartsOffset() const;
|
||||
const Array<Image::ResolvedSymbolTarget> chainedTargets() const;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
Dyld cache patching notes:
|
||||
|
||||
The dyld cache needs to be patched to support interposing and dylib "roots".
|
||||
|
||||
For cached dylibs overrides:
|
||||
Closure build time:
|
||||
1) LoadedImages will contain the new dylib, so all symbol look ups
|
||||
will naturally find new impl. Only dyld cache needs special help.
|
||||
2) LoadedImages entry will have flag for images that override cache.
|
||||
3) When setting Closure attributes, if flag is set, builder will
|
||||
iterate PatchableExport entries in Image* from cache and create
|
||||
a PatchEntry for each.
|
||||
Runtime:
|
||||
1) [lib]dyld will iterate PatchEntry in closure and patch cache
|
||||
|
||||
For interposing:
|
||||
Closure build time:
|
||||
1) After Images built, if __interpose section(s) exist, builder will
|
||||
build InterposingTuple entries for closure
|
||||
2) For being-built closure and launch closure, apply any InterposingTuple
|
||||
to modify Image fixups before Image finalized.
|
||||
3) Builder will find PatchableExport entry that matchs stock Impl
|
||||
and add PatchEntry to closure for it.
|
||||
Runtime:
|
||||
1) When closure is loaded (launch or dlopen) PatchEntries are
|
||||
applied (exactly once) to whole cache.
|
||||
2) For each DlopenClosure loaded, any InterposeTuples in *launch* closure
|
||||
are applied to all new images in new DlopenClosure.
|
||||
|
||||
For weak-def coalesing:
|
||||
Closure build time:
|
||||
1) weak_bind entries are turned into -3 ordinal lookup which search through images
|
||||
in load order for first def (like flat). This fixups up all images not in cache.
|
||||
2) When processing -3 ordinals, it continues past first found and if any images
|
||||
past it are in dyld cache and export that same symbol, a PatchEntry is added to
|
||||
closure to fix up all cached uses of that symbol.
|
||||
3) If a weak_bind has strong bit set (no fixup, just def), all images from the dyld
|
||||
cache are checked to see if the export that symbol, if so, a PatchEntry is added
|
||||
to the closure.
|
||||
Runtime:
|
||||
1) When closure is loaded (launch or dlopen) PatchEntries are
|
||||
applied (exactly once) to whole cache.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// An array (accessible by index) list of Images
|
||||
//
|
||||
struct VIS_HIDDEN ImageArray : public TypedBytes
|
||||
{
|
||||
size_t size() const;
|
||||
size_t startImageNum() const;
|
||||
uint32_t imageCount() const;
|
||||
void forEachImage(void (^callback)(const Image* image, bool& stop)) const;
|
||||
bool hasPath(const char* path, ImageNum& num) const;
|
||||
const Image* imageForNum(ImageNum) const;
|
||||
void deallocate() const;
|
||||
|
||||
static const Image* findImage(const Array<const ImageArray*> imagesArrays, ImageNum imageNum);
|
||||
|
||||
private:
|
||||
friend class ImageArrayWriter;
|
||||
|
||||
uint32_t firstImageNum;
|
||||
uint32_t count : 31;
|
||||
uint32_t hasRoots : 1; // True if this ImageArray contains roots with imageNum's below firstImageNum
|
||||
uint32_t offsets[];
|
||||
// Image data
|
||||
};
|
||||
|
||||
|
||||
struct InterposingTuple
|
||||
{
|
||||
Image::ResolvedSymbolTarget stockImplementation;
|
||||
Image::ResolvedSymbolTarget newImplementation;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Describes how dyld should load a set of mach-o files
|
||||
//
|
||||
struct VIS_HIDDEN Closure : public ContainerTypedBytes
|
||||
{
|
||||
size_t size() const;
|
||||
const ImageArray* images() const;
|
||||
ImageNum topImage() const;
|
||||
void deallocate() const;
|
||||
|
||||
friend class ClosureWriter;
|
||||
|
||||
struct PatchEntry
|
||||
{
|
||||
ImageNum overriddenDylibInCache;
|
||||
uint32_t exportCacheOffset;
|
||||
Image::ResolvedSymbolTarget replacement;
|
||||
};
|
||||
|
||||
struct Warning
|
||||
{
|
||||
enum Type : uint32_t {
|
||||
duplicateObjCClass = 0
|
||||
};
|
||||
|
||||
Type type;
|
||||
char message[];
|
||||
};
|
||||
|
||||
void forEachPatchEntry(void (^handler)(const PatchEntry& entry)) const;
|
||||
void forEachWarning(Warning::Type type, void (^handler)(const char* warning, bool& stop)) const;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Describes how dyld should launch a main executable
|
||||
//
|
||||
struct VIS_HIDDEN LaunchClosure : public Closure
|
||||
{
|
||||
// Represents a file on disk we tried to load but skipped as it wasn't valid for our use
|
||||
struct SkippedFile
|
||||
{
|
||||
const char* path;
|
||||
uint64_t inode;
|
||||
uint64_t mtime;
|
||||
};
|
||||
|
||||
bool builtAgainstDyldCache(uuid_t cacheUUID) const;
|
||||
const char* bootUUID() const;
|
||||
void forEachMustBeMissingFile(void (^handler)(const char* path, bool& stop)) const;
|
||||
void forEachSkipIfExistsFile(void (^handler)(const SkippedFile& file, bool& stop)) const;
|
||||
void forEachEnvVar(void (^handler)(const char* keyEqualValue, bool& stop)) const;
|
||||
ImageNum libSystemImageNum() const;
|
||||
void libDyldEntry(Image::ResolvedSymbolTarget& loc) const;
|
||||
bool mainEntry(Image::ResolvedSymbolTarget& mainLoc) const;
|
||||
bool startEntry(Image::ResolvedSymbolTarget& startLoc) const;
|
||||
uint32_t initialLoadCount() const;
|
||||
void forEachInterposingTuple(void (^handler)(const InterposingTuple& tuple, bool& stop)) const;
|
||||
bool usedAtPaths() const;
|
||||
bool usedFallbackPaths() const;
|
||||
bool selectorHashTable(Array<Image::ObjCSelectorImage>& imageNums,
|
||||
const ObjCSelectorOpt*& hashTable) const;
|
||||
bool classAndProtocolHashTables(Array<Image::ObjCClassImage>& imageNums,
|
||||
const ObjCClassOpt*& classHashTable,
|
||||
const ObjCClassOpt*& protocolHashTable) const;
|
||||
void duplicateClassesHashTable(const ObjCClassDuplicatesOpt*& duplicateClassesHashTable) const;
|
||||
bool hasInsertedLibraries() const;
|
||||
bool hasInterposings() const;
|
||||
|
||||
static bool buildClosureCachePath(const char* mainExecutablePath, char closurePath[], const char* tempDir,
|
||||
bool makeDirsIfMissing);
|
||||
|
||||
private:
|
||||
friend class LaunchClosureWriter;
|
||||
|
||||
struct Flags
|
||||
{
|
||||
uint32_t usedAtPaths : 1,
|
||||
usedFallbackPaths : 1,
|
||||
initImageCount : 16,
|
||||
hasInsertedLibraries : 1,
|
||||
padding : 13;
|
||||
};
|
||||
const Flags& getFlags() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Describes how dyld should dlopen() a mach-o file
|
||||
//
|
||||
struct VIS_HIDDEN DlopenClosure : public Closure
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Precomputed perfect hash table of strings.
|
||||
// Base class for closure precomputed selector table and class table.
|
||||
class VIS_HIDDEN ObjCStringTable {
|
||||
public:
|
||||
typedef uint32_t StringTarget;
|
||||
|
||||
private:
|
||||
typedef uint8_t StringHashCheckByte;
|
||||
|
||||
protected:
|
||||
|
||||
uint32_t capacity;
|
||||
uint32_t occupied;
|
||||
uint32_t shift;
|
||||
uint32_t mask;
|
||||
StringTarget sentinelTarget;
|
||||
uint32_t roundedTabSize;
|
||||
uint64_t salt;
|
||||
|
||||
uint32_t scramble[256];
|
||||
uint8_t tab[0]; /* tab[mask+1] (always power-of-2). Rounded up to roundedTabSize */
|
||||
// uint8_t checkbytes[capacity]; /* check byte for each string */
|
||||
// int32_t offsets[capacity]; /* offsets from &capacity to cstrings */
|
||||
|
||||
StringHashCheckByte* checkBytesOffset() {
|
||||
return &tab[roundedTabSize];
|
||||
}
|
||||
|
||||
const StringHashCheckByte* checkBytesOffset() const {
|
||||
return &tab[roundedTabSize];
|
||||
}
|
||||
|
||||
StringTarget* targetsOffset() {
|
||||
return (StringTarget*)(checkBytesOffset() + capacity);
|
||||
}
|
||||
|
||||
const StringTarget* targetsOffset() const {
|
||||
return (StringTarget*)(checkBytesOffset() + capacity);
|
||||
}
|
||||
|
||||
dyld3::Array<StringHashCheckByte> checkBytes() {
|
||||
return dyld3::Array<StringHashCheckByte>((StringHashCheckByte *)checkBytesOffset(), capacity, capacity);
|
||||
}
|
||||
const dyld3::Array<StringHashCheckByte> checkBytes() const {
|
||||
return dyld3::Array<StringHashCheckByte>((StringHashCheckByte *)checkBytesOffset(), capacity, capacity);
|
||||
}
|
||||
|
||||
dyld3::Array<StringTarget> targets() {
|
||||
return dyld3::Array<StringTarget>((StringTarget *)targetsOffset(), capacity, capacity);
|
||||
}
|
||||
const dyld3::Array<StringTarget> targets() const {
|
||||
return dyld3::Array<StringTarget>((StringTarget *)targetsOffset(), capacity, capacity);
|
||||
}
|
||||
|
||||
uint32_t hash(const char *key, size_t keylen) const;
|
||||
|
||||
uint32_t hash(const char *key) const
|
||||
{
|
||||
return hash(key, strlen(key));
|
||||
}
|
||||
|
||||
// The check bytes areused to reject strings that aren't in the table
|
||||
// without paging in the table's cstring data. This checkbyte calculation
|
||||
// catches 4785/4815 rejects when launching Safari; a perfect checkbyte
|
||||
// would catch 4796/4815.
|
||||
StringHashCheckByte checkbyte(const char *key, size_t keylen) const
|
||||
{
|
||||
return ((key[0] & 0x7) << 5) | ((uint8_t)keylen & 0x1f);
|
||||
}
|
||||
|
||||
StringHashCheckByte checkbyte(const char *key) const
|
||||
{
|
||||
return checkbyte(key, strlen(key));
|
||||
}
|
||||
|
||||
StringTarget getPotentialTarget(const char *key) const
|
||||
{
|
||||
uint32_t index = getIndex(key);
|
||||
if (index == indexNotFound)
|
||||
return sentinelTarget;
|
||||
return targets()[index];
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
enum : uint32_t {
|
||||
indexNotFound = ~0U
|
||||
};
|
||||
|
||||
uint32_t getIndex(const char *key) const
|
||||
{
|
||||
size_t keylen = strlen(key);
|
||||
uint32_t h = hash(key, keylen);
|
||||
|
||||
// Use check byte to reject without paging in the table's cstrings
|
||||
StringHashCheckByte h_check = checkBytes()[h];
|
||||
StringHashCheckByte key_check = checkbyte(key, keylen);
|
||||
if (h_check != key_check)
|
||||
return indexNotFound;
|
||||
return h;
|
||||
}
|
||||
|
||||
template<typename PerfectHashT>
|
||||
static size_t size(const PerfectHashT& phash) {
|
||||
// Round tab[] to at least 4 in length to ensure the uint32_t's after are aligned
|
||||
uint32_t roundedTabSize = std::max(phash.mask+1, 4U);
|
||||
size_t tableSize = 0;
|
||||
tableSize += sizeof(ObjCStringTable);
|
||||
tableSize += roundedTabSize;
|
||||
tableSize += phash.capacity * sizeof(StringHashCheckByte);
|
||||
tableSize += phash.capacity * sizeof(StringTarget);
|
||||
return tableSize;
|
||||
}
|
||||
|
||||
// Get a string if it has an entry in the table
|
||||
const char* getString(const char* selName, const Array<uintptr_t>& baseAddresses) const;
|
||||
|
||||
void forEachString(const Array<Image::ObjCSelectorImage>& selectorImages,
|
||||
void (^callback)(uint64_t selVMOffset, ImageNum imageNum)) const;
|
||||
|
||||
template<typename PerfectHashT, typename ImageOffsetT>
|
||||
void write(const PerfectHashT& phash, const Array<std::pair<const char*, ImageOffsetT>>& strings);
|
||||
};
|
||||
|
||||
class VIS_HIDDEN ObjCSelectorOpt : public ObjCStringTable {
|
||||
public:
|
||||
// Get a string if it has an entry in the table
|
||||
// Returns true if an entry is found and sets the imageNum and vmOffset.
|
||||
bool getStringLocation(uint32_t index, const Array<closure::Image::ObjCSelectorImage>& selImages,
|
||||
ImageNum& imageNum, uint64_t& vmOffset) const;
|
||||
|
||||
void forEachString(const Array<Image::ObjCSelectorImage>& selectorImages,
|
||||
void (^callback)(uint64_t selVMOffset, ImageNum imageNum)) const;
|
||||
};
|
||||
|
||||
class VIS_HIDDEN ObjCClassOpt : public ObjCStringTable {
|
||||
private:
|
||||
// ...ObjCStringTable fields...
|
||||
// ClassTarget classOffsets[capacity]; /* offsets from &capacity to class_t and header_info */
|
||||
// DuplicateCount duplicateCount;
|
||||
// ClassTarget duplicateOffsets[duplicatedClasses];
|
||||
|
||||
typedef uint32_t DuplicateCount;
|
||||
typedef Image::ObjCClassImageOffset ClassTarget;
|
||||
|
||||
ClassTarget *classOffsetsStart() { return (ClassTarget *)&targetsOffset()[capacity]; }
|
||||
const ClassTarget *classOffsetsStart() const { return (const ClassTarget *)&targetsOffset()[capacity]; }
|
||||
|
||||
dyld3::Array<ClassTarget> classOffsets() {
|
||||
return dyld3::Array<ClassTarget>((ClassTarget *)classOffsetsStart(), capacity, capacity);
|
||||
}
|
||||
const dyld3::Array<ClassTarget> classOffsets() const {
|
||||
return dyld3::Array<ClassTarget>((ClassTarget *)classOffsetsStart(), capacity, capacity);
|
||||
}
|
||||
|
||||
DuplicateCount& duplicateCount() { return *(DuplicateCount *)&classOffsetsStart()[capacity]; }
|
||||
const DuplicateCount& duplicateCount() const { return *(const DuplicateCount *)&classOffsetsStart()[capacity]; }
|
||||
|
||||
ClassTarget *duplicateOffsetsStart() { return (ClassTarget *)(&duplicateCount()+1); }
|
||||
const ClassTarget *duplicateOffsetsStart() const { return (const ClassTarget *)(&duplicateCount()+1); }
|
||||
|
||||
dyld3::Array<ClassTarget> duplicateOffsets(uint32_t preCalculatedDuplicateCount) {
|
||||
return dyld3::Array<ClassTarget>((ClassTarget *)duplicateOffsetsStart(), preCalculatedDuplicateCount, duplicateCount());
|
||||
}
|
||||
const dyld3::Array<ClassTarget> duplicateOffsets(uint32_t preCalculatedDuplicateCount) const {
|
||||
return dyld3::Array<ClassTarget>((ClassTarget *)duplicateOffsetsStart(), preCalculatedDuplicateCount, duplicateCount());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<typename PerfectHashT>
|
||||
static size_t size(PerfectHashT& phash, uint32_t duplicateCount)
|
||||
{
|
||||
size_t tableSize = 0;
|
||||
tableSize += ObjCStringTable::size(phash);
|
||||
tableSize += phash.capacity * sizeof(ClassTarget);
|
||||
tableSize += sizeof(DuplicateCount);
|
||||
tableSize += duplicateCount * sizeof(ClassTarget);
|
||||
return tableSize;
|
||||
}
|
||||
|
||||
void forEachClass(const char* className,
|
||||
const Array<std::pair<uintptr_t, uintptr_t>>& nameAndDataBaseAddresses,
|
||||
void (^callback)(void* classPtr, bool isLoaded, bool* stop)) const;
|
||||
|
||||
void forEachClass(const Array<Image::ObjCClassImage>& classImages,
|
||||
void (^nameCallback)(uint64_t classNameVMOffset, ImageNum imageNum),
|
||||
void (^implCallback)(uint64_t classVMOffset, ImageNum imageNum)) const;
|
||||
|
||||
template<typename PerfectHashT, typename ImageOffsetT, typename ClassesMapT>
|
||||
void write(const PerfectHashT& phash, const Array<std::pair<const char*, ImageOffsetT>>& strings,
|
||||
const ClassesMapT& classes, uint32_t preCalculatedDuplicateCount);
|
||||
};
|
||||
|
||||
class VIS_HIDDEN ObjCClassDuplicatesOpt : public ObjCStringTable {
|
||||
public:
|
||||
// Get a class if it has an entry in the table
|
||||
bool getClassLocation(const char* className, const objc_opt::objc_opt_t* objCOpt, void*& classImpl) const;
|
||||
|
||||
void forEachClass(void (^callback)(Image::ObjCDuplicateClass duplicateClass)) const;
|
||||
};
|
||||
|
||||
} // namespace closure
|
||||
} // namespace dyld3
|
||||
|
||||
|
||||
#endif // Closures_h
|
||||
|
||||
|
3791
src/dyld/dyld3/ClosureBuilder.cpp
Normal file
3791
src/dyld/dyld3/ClosureBuilder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
365
src/dyld/dyld3/ClosureBuilder.h
Normal file
365
src/dyld/dyld3/ClosureBuilder.h
Normal file
@ -0,0 +1,365 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ClosureBuilder_h
|
||||
#define ClosureBuilder_h
|
||||
|
||||
|
||||
#include "Closure.h"
|
||||
#include "ClosureFileSystem.h"
|
||||
#include "ClosureWriter.h"
|
||||
#include "PathOverrides.h"
|
||||
#include "DyldSharedCache.h"
|
||||
#include "MachOAnalyzer.h"
|
||||
#include "Map.h"
|
||||
#include "Loading.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace objc_opt {
|
||||
struct objc_clsopt_t;
|
||||
struct objc_selopt_t;
|
||||
struct objc_protocolopt2_t;
|
||||
}
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
|
||||
namespace closure {
|
||||
|
||||
|
||||
|
||||
class VIS_HIDDEN ClosureBuilder
|
||||
{
|
||||
public:
|
||||
|
||||
struct LaunchErrorInfo
|
||||
{
|
||||
uintptr_t kind;
|
||||
const char* clientOfDylibPath;
|
||||
const char* targetDylibPath;
|
||||
const char* symbol;
|
||||
};
|
||||
|
||||
struct ResolvedTargetInfo
|
||||
{
|
||||
const MachOLoaded* foundInDylib;
|
||||
const char* requestedSymbolName;
|
||||
const char* foundSymbolName;
|
||||
uint64_t addend;
|
||||
bool weakBindCoalese;
|
||||
bool weakBindSameImage;
|
||||
bool isWeakDef;
|
||||
bool skippableWeakDef;
|
||||
int libOrdinal;
|
||||
};
|
||||
|
||||
struct CacheDylibsBindingHandlers
|
||||
{
|
||||
void (^rebase)(ImageNum, const MachOLoaded* imageToFix, uint32_t runtimeOffset);
|
||||
void (^bind)(ImageNum, const MachOLoaded* imageToFix, uint32_t runtimeOffset, Image::ResolvedSymbolTarget target, const ResolvedTargetInfo& targetInfo);
|
||||
void (^chainedBind)(ImageNum, const MachOLoaded*, const dyld_chained_starts_in_image* starts, const Array<Image::ResolvedSymbolTarget>& targets, const Array<ResolvedTargetInfo>& targetInfos);
|
||||
};
|
||||
|
||||
enum class AtPath { none, all, onlyInRPaths };
|
||||
|
||||
ClosureBuilder(uint32_t startImageNum, const FileSystem& fileSystem, const DyldSharedCache* dyldCache, bool dyldCacheIsLive,
|
||||
const GradedArchs& archs, const PathOverrides& pathOverrides,
|
||||
AtPath atPathHandling=AtPath::all, bool allowRelativePaths=true, LaunchErrorInfo* errorInfo=nullptr,
|
||||
Platform platform=MachOFile::currentPlatform(), const CacheDylibsBindingHandlers* handlers=nullptr);
|
||||
~ClosureBuilder();
|
||||
Diagnostics& diagnostics() { return _diag; }
|
||||
|
||||
const LaunchClosure* makeLaunchClosure(const LoadedFileInfo& fileInfo, bool allowInsertFailures);
|
||||
|
||||
const LaunchClosure* makeLaunchClosure(const char* mainPath,bool allowInsertFailures);
|
||||
|
||||
|
||||
static const DlopenClosure* sRetryDlopenClosure;
|
||||
const DlopenClosure* makeDlopenClosure(const char* dylibPath, const LaunchClosure* mainClosure, const Array<LoadedImage>& loadedList,
|
||||
closure::ImageNum callerImageNum, bool noLoad, bool forceBindLazies, bool canUseSharedCacheClosure,
|
||||
closure::ImageNum* topImageNum);
|
||||
|
||||
ImageNum nextFreeImageNum() const { return _startImageNum + _nextIndex; }
|
||||
|
||||
void setDyldCacheInvalidFormatVersion();
|
||||
|
||||
|
||||
struct PatchableExport
|
||||
{
|
||||
uint32_t cacheOffsetOfImpl;
|
||||
uint32_t cacheOffsetOfName;
|
||||
uint32_t patchLocationsCount;
|
||||
const dyld_cache_patchable_location* patchLocations;
|
||||
};
|
||||
|
||||
struct CachedDylibInfo
|
||||
{
|
||||
LoadedFileInfo fileInfo;
|
||||
};
|
||||
|
||||
struct CachedDylibAlias
|
||||
{
|
||||
const char* realPath;
|
||||
const char* aliasPath;
|
||||
};
|
||||
|
||||
const ImageArray* makeDyldCacheImageArray(bool customerCache, const Array<CachedDylibInfo>& dylibs, const Array<CachedDylibAlias>& aliases);
|
||||
|
||||
const ImageArray* makeOtherDylibsImageArray(const Array<LoadedFileInfo>& otherDylibs, uint32_t cachedDylibsCount);
|
||||
|
||||
static void buildLoadOrder(Array<LoadedImage>& loadedList, const Array<const ImageArray*>& imagesArrays, const Closure* toAdd);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
struct InitInfo
|
||||
{
|
||||
uint32_t initOrder;
|
||||
bool danglingUpward;
|
||||
bool visited;
|
||||
};
|
||||
|
||||
struct BuilderLoadedImage
|
||||
{
|
||||
Array<Image::LinkedImage> dependents;
|
||||
ImageNum imageNum;
|
||||
uint32_t unmapWhenDone : 1,
|
||||
contentRebased : 1,
|
||||
hasInits : 1,
|
||||
markNeverUnload : 1,
|
||||
rtldLocal : 1,
|
||||
isBadImage : 1,
|
||||
mustBuildClosure : 1,
|
||||
hasMissingWeakImports : 1,
|
||||
padding : 12,
|
||||
overrideImageNum : 12;
|
||||
LoadedFileInfo loadedFileInfo;
|
||||
|
||||
// Convenience method to get the information from the loadedFileInfo
|
||||
const MachOAnalyzer* loadAddress() const { return (const MachOAnalyzer*)loadedFileInfo.fileContent; }
|
||||
const char* path() const { return loadedFileInfo.path; }
|
||||
};
|
||||
|
||||
struct LoadedImageChain
|
||||
{
|
||||
LoadedImageChain* previous;
|
||||
BuilderLoadedImage& image;
|
||||
};
|
||||
|
||||
// Represents how the current image is linked
|
||||
enum class LinkageType {
|
||||
kStatic, // Linked via LC_LOAD_* by main executable or other dylib
|
||||
kDynamic, // Only used for the image we dlopen'ed, not anything it links
|
||||
kInserted // This is an inserted library
|
||||
};
|
||||
|
||||
typedef LaunchClosure::SkippedFile SkippedFile;
|
||||
|
||||
|
||||
void recursiveLoadDependents(LoadedImageChain& forImageChain, bool canUseSharedCacheClosure = true);
|
||||
void loadDanglingUpwardLinks(bool canUseSharedCacheClosure = true);
|
||||
void forEachResolvedPathVar(const char* loadPath, const LoadedImageChain& forImageChain, bool implictRPath, LinkageType linkageType,
|
||||
void (^handler)(const char* possiblePath, bool& stop));
|
||||
bool findImage(const char* loadPath, const LoadedImageChain& forImageChain, BuilderLoadedImage*& foundImage, LinkageType linkageType,
|
||||
uint32_t compatVersion, bool canUseSharedCacheClosure);
|
||||
void buildImage(ImageWriter& writer, BuilderLoadedImage& forImage);
|
||||
void addSegments(ImageWriter& writer, const MachOAnalyzer* mh);
|
||||
void addRebaseInfo(ImageWriter& writer, const MachOAnalyzer* mh);
|
||||
void addSynthesizedRebaseInfo(ImageWriter& writer, const MachOAnalyzer* mh);
|
||||
void addSynthesizedBindInfo(ImageWriter& writer, const MachOAnalyzer* mh);
|
||||
void addBindInfo(ImageWriter& writer, BuilderLoadedImage& forImage);
|
||||
void reportRebasesAndBinds(ImageWriter& writer, BuilderLoadedImage& forImage);
|
||||
void addChainedFixupInfo(ImageWriter& writer, BuilderLoadedImage& forImage);
|
||||
void addInterposingTuples(LaunchClosureWriter& writer, const Image* image, const MachOAnalyzer* mh);
|
||||
void computeInitOrder(ImageWriter& writer, uint32_t loadIndex);
|
||||
void addClosureInfo(LaunchClosureWriter& closureWriter);
|
||||
void depthFirstRecurseSetInitInfo(uint32_t loadIndex, InitInfo initInfos[], uint32_t& initOrder, bool& hasError);
|
||||
bool findSymbol(BuilderLoadedImage& fromImage, int libraryOrdinal, const char* symbolName, bool weakImport, bool lazyBind, uint64_t addend,
|
||||
Image::ResolvedSymbolTarget& target, ResolvedTargetInfo& targetInfo);
|
||||
bool findSymbolInImage(const MachOAnalyzer* macho, const char* symbolName, uint64_t addend, bool followReExports,
|
||||
bool weakImport, Image::ResolvedSymbolTarget& target, ResolvedTargetInfo& targetInfo);
|
||||
const MachOAnalyzer* machOForImageNum(ImageNum imageNum);
|
||||
ImageNum imageNumForMachO(const MachOAnalyzer* mh);
|
||||
const MachOAnalyzer* findDependent(const MachOLoaded* mh, uint32_t depIndex);
|
||||
BuilderLoadedImage& findLoadedImage(ImageNum imageNum);
|
||||
BuilderLoadedImage& findLoadedImage(const MachOAnalyzer* mh);
|
||||
uint32_t index(const BuilderLoadedImage&);
|
||||
bool expandAtLoaderPath(const char* loadPath, bool fromLCRPATH, const BuilderLoadedImage& loadedImage, char fixedPath[]);
|
||||
bool expandAtExecutablePath(const char* loadPath, bool fromLCRPATH, char fixedPath[]);
|
||||
void addMustBeMissingPath(const char* path);
|
||||
void addSkippedFile(const char* path, uint64_t inode, uint64_t mtime);
|
||||
const char* strdup_temp(const char* path);
|
||||
bool overridableDylib(const BuilderLoadedImage& forImage);
|
||||
void forEachBind(BuilderLoadedImage& forImage, void (^handler)(uint64_t runtimeOffset, Image::ResolvedSymbolTarget target, const ResolvedTargetInfo& targetInfo, bool& stop),
|
||||
void (^strongHandler)(const char* strongSymbolName),
|
||||
void (^missingLazyBindHandler)());
|
||||
bool findMissingSymbolHandler(Image::ResolvedSymbolTarget& target, ResolvedTargetInfo& targetInfo);
|
||||
|
||||
struct HashCString {
|
||||
static size_t hash(const char* v);
|
||||
};
|
||||
|
||||
struct EqualCString {
|
||||
static bool equal(const char* s1, const char* s2);
|
||||
};
|
||||
|
||||
struct HashPointer {
|
||||
template<typename T>
|
||||
static size_t hash(const T* v) {
|
||||
return std::hash<const T*>{}(v);
|
||||
}
|
||||
};
|
||||
|
||||
struct EqualPointer {
|
||||
template<typename T>
|
||||
static bool equal(const T* s1, const T* s2) {
|
||||
return s1 == s2;
|
||||
}
|
||||
};
|
||||
|
||||
struct ObjCOptimizerImage {
|
||||
|
||||
ObjCOptimizerImage() {
|
||||
}
|
||||
|
||||
~ObjCOptimizerImage() {
|
||||
}
|
||||
|
||||
typedef std::pair<closure::Image::ObjCClassNameImageOffset, closure::Image::ObjCClassImageOffset> SeenClass;
|
||||
|
||||
struct SelectorFixup {
|
||||
uint32_t fixupVMOffset;
|
||||
bool isSharedCache;
|
||||
union {
|
||||
struct {
|
||||
uint32_t selectorTableIndex;
|
||||
} sharedCache;
|
||||
struct {
|
||||
const char* selectorString;
|
||||
} image;
|
||||
};
|
||||
};
|
||||
|
||||
BuilderLoadedImage* loadedImage = nullptr;
|
||||
ImageWriter* writer = nullptr;
|
||||
uint64_t fairplayFileOffsetStart = 0;
|
||||
uint64_t fairplayFileOffsetEnd = 0;
|
||||
Diagnostics diag;
|
||||
|
||||
// Image info optimisation
|
||||
uint64_t objcImageInfoVMOffset;
|
||||
|
||||
// Class and protocol optimisation data structures
|
||||
OverflowSafeArray<std::pair<uint64_t, uint64_t>> classesNameAndDataVMOffsets;
|
||||
OverflowSafeArray<SeenClass> seenClasses;
|
||||
OverflowSafeArray<uint64_t> classStableSwiftFixups;
|
||||
Map<const char*, dyld3::closure::Image::ObjCDuplicateClass, HashCString, EqualCString> classSharedCacheDuplicates;
|
||||
OverflowSafeArray<SeenClass> seenProtocols;
|
||||
OverflowSafeArray<uint64_t> protocolISAFixups;
|
||||
|
||||
// Selector optimsation data structures
|
||||
OverflowSafeArray<SelectorFixup> selectorFixups;
|
||||
Map<const char*, dyld3::closure::Image::ObjCImageOffset, HashCString, EqualCString> selectorMap;
|
||||
std::optional<uint64_t> methodNameVMOffset;
|
||||
};
|
||||
|
||||
bool optimizeObjC(Array<ImageWriter>& writers);
|
||||
void optimizeObjCSelectors(const objc_opt::objc_selopt_t* objcSelOpt,
|
||||
const Map<const char*, dyld3::closure::Image::ObjCImageOffset, HashCString, EqualCString>& closureSelectorMap,
|
||||
ObjCOptimizerImage& image);
|
||||
void optimizeObjCClasses(const objc_opt::objc_clsopt_t* objcClassOpt,
|
||||
const Map<const dyld3::MachOAnalyzer*, bool, HashPointer, EqualPointer>& sharedCacheImagesMap,
|
||||
const Map<const char*, dyld3::closure::Image::ObjCDuplicateClass, HashCString, EqualCString>& duplicateSharedCacheClasses,
|
||||
ObjCOptimizerImage& image);
|
||||
void optimizeObjCProtocols(const objc_opt::objc_protocolopt2_t* objcProtocolOpt,
|
||||
const Map<const dyld3::MachOAnalyzer*, bool, HashPointer, EqualPointer>& sharedCacheImagesMap,
|
||||
ObjCOptimizerImage& image);
|
||||
void writeClassOrProtocolHashTable(bool classes, Array<ObjCOptimizerImage>& objcImages);
|
||||
|
||||
void addDuplicateObjCClassWarning(const char* className,
|
||||
const char* duplicateDefinitionPath,
|
||||
const char* canonicalDefinitionPath);
|
||||
|
||||
static bool inLoadedImageArray(const Array<LoadedImage>& loadedList, ImageNum imageNum);
|
||||
static void buildLoadOrderRecurse(Array<LoadedImage>& loadedList, const Array<const ImageArray*>& imagesArrays, const Image* toAdd);
|
||||
void invalidateInitializerRoots();
|
||||
|
||||
const FileSystem& _fileSystem;
|
||||
const DyldSharedCache* const _dyldCache;
|
||||
const PathOverrides& _pathOverrides;
|
||||
const GradedArchs& _archs;
|
||||
Platform const _platform;
|
||||
uint32_t const _startImageNum;
|
||||
const ImageArray* _dyldImageArray = nullptr;
|
||||
const CacheDylibsBindingHandlers* _handlers = nullptr;
|
||||
const Array<CachedDylibAlias>* _aliases = nullptr;
|
||||
const AtPath _atPathHandling = AtPath::none;
|
||||
uint32_t _mainProgLoadIndex = 0;
|
||||
const char* _mainProgLoadPath = nullptr;
|
||||
Diagnostics _diag;
|
||||
LaunchErrorInfo* _launchErrorInfo = nullptr;
|
||||
PathPool* _tempPaths = nullptr;
|
||||
PathPool* _mustBeMissingPaths = nullptr;
|
||||
OverflowSafeArray<SkippedFile> _skippedFiles;
|
||||
uint32_t _nextIndex = 0;
|
||||
OverflowSafeArray<BuilderLoadedImage,2048> _loadedImages;
|
||||
OverflowSafeArray<Image::LinkedImage,65536> _dependencies; // all dylibs in cache need ~20,000 edges
|
||||
OverflowSafeArray<InterposingTuple> _interposingTuples;
|
||||
OverflowSafeArray<Closure::PatchEntry> _weakDefCacheOverrides;
|
||||
OverflowSafeArray<const char*> _weakDefsFromChainedBinds;
|
||||
OverflowSafeArray<uint8_t> _objcSelectorsHashTable;
|
||||
OverflowSafeArray<Image::ObjCSelectorImage> _objcSelectorsHashTableImages;
|
||||
OverflowSafeArray<uint8_t> _objcClassesHashTable;
|
||||
OverflowSafeArray<uint8_t> _objcProtocolsHashTable;
|
||||
OverflowSafeArray<Image::ObjCClassImage> _objcClassesHashTableImages;
|
||||
OverflowSafeArray<uint8_t> _objcClassesDuplicatesHashTable;
|
||||
PathPool* _objcDuplicateClassWarnings = nullptr;
|
||||
uint32_t _alreadyInitedIndex = 0;
|
||||
bool _isLaunchClosure = false;
|
||||
bool _makingDyldCacheImages = false;
|
||||
bool _dyldCacheIsLive = false; // means kernel is rebasing dyld cache content being viewed
|
||||
bool _makingClosuresInCache = false;
|
||||
bool _makingCustomerCache = false;
|
||||
bool _allowRelativePaths = false;
|
||||
bool _atPathUsed = false;
|
||||
bool _fallbackPathUsed = false;
|
||||
bool _allowMissingLazies = false;
|
||||
bool _dyldCacheInvalidFormatVersion = false;
|
||||
bool _foundNonCachedImage = false; // true means we have one or more images from disk we need to build closure(s) for
|
||||
bool _foundDyldCacheRoots = false; // true if one or more images are roots of the shared cache
|
||||
bool _foundMissingLazyBinds = false; // true if one or more images having missing lazy binds
|
||||
ImageNum _libDyldImageNum = 0;
|
||||
ImageNum _libSystemImageNum = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace closure
|
||||
} // namespace dyld3
|
||||
|
||||
|
||||
#endif /* ClosureBuilder_h */
|
82
src/dyld/dyld3/ClosureFileSystem.h
Normal file
82
src/dyld/dyld3/ClosureFileSystem.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#ifndef ClosureFileSystem_h
|
||||
#define ClosureFileSystem_h
|
||||
|
||||
// For MAXPATHLEN
|
||||
#include <sys/param.h>
|
||||
// For va_list
|
||||
#include <stdarg.h>
|
||||
// For uint64_t
|
||||
#include <stdint.h>
|
||||
|
||||
namespace dyld3 {
|
||||
namespace closure {
|
||||
|
||||
struct LoadedFileInfo {
|
||||
const void* fileContent = nullptr;
|
||||
uint64_t fileContentLen = 0;
|
||||
uint64_t sliceOffset = 0;
|
||||
uint64_t sliceLen : 63,
|
||||
isSipProtected : 1;
|
||||
uint64_t inode = 0;
|
||||
uint64_t mtime = 0;
|
||||
void (*unload)(const LoadedFileInfo&) = nullptr;
|
||||
const char* path = nullptr;
|
||||
};
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
|
||||
class FileSystem {
|
||||
protected:
|
||||
FileSystem() { }
|
||||
|
||||
public:
|
||||
|
||||
// Get the real path for a given path, if it exists.
|
||||
// Returns true if the real path was found and updates the given buffer iff that is the case
|
||||
virtual bool getRealPath(const char possiblePath[MAXPATHLEN], char realPath[MAXPATHLEN]) const = 0;
|
||||
|
||||
// Returns true on success. If an error occurs the given callback will be called with the reason.
|
||||
// On success, info is filled with info about the loaded file. If the path supplied includes a symlink,
|
||||
// the supplier realerPath is filled in with the real path of the file, otherwise it is set to the empty string.
|
||||
virtual bool loadFile(const char* path, LoadedFileInfo& info, char realerPath[MAXPATHLEN], void (^error)(const char* format, ...)) const = 0;
|
||||
|
||||
// Frees the buffer allocated by loadFile()
|
||||
virtual void unloadFile(const LoadedFileInfo& info) const = 0;
|
||||
|
||||
// Frees all but the requested range and adjusts info to new buffer location
|
||||
// Remaining buffer can be freed later with unloadFile()
|
||||
virtual void unloadPartialFile(LoadedFileInfo& info, uint64_t keepStartOffset, uint64_t keepLength) const = 0;
|
||||
|
||||
// If a file exists at path, returns true and sets inode and mtime
|
||||
virtual bool fileExists(const char* path, uint64_t* inode=nullptr, uint64_t* mtime=nullptr,
|
||||
bool* issetuid=nullptr, bool* inodesMatchRuntime = nullptr) const = 0;
|
||||
};
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
} // namespace closure
|
||||
} // namespace dyld3
|
||||
|
||||
#endif /* ClosureFileSystem_h */
|
45
src/dyld/dyld3/ClosureFileSystemNull.cpp
Normal file
45
src/dyld/dyld3/ClosureFileSystemNull.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#include "ClosureFileSystemNull.h"
|
||||
|
||||
using dyld3::closure::FileSystemNull;
|
||||
|
||||
bool FileSystemNull::getRealPath(const char possiblePath[MAXPATHLEN], char realPath[MAXPATHLEN]) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileSystemNull::loadFile(const char* path, LoadedFileInfo& info, char realerPath[MAXPATHLEN], void (^error)(const char* format, ...)) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void FileSystemNull::unloadFile(const LoadedFileInfo& info) const {
|
||||
}
|
||||
|
||||
void FileSystemNull::unloadPartialFile(LoadedFileInfo& info, uint64_t keepStartOffset, uint64_t keepLength) const {
|
||||
}
|
||||
|
||||
bool FileSystemNull::fileExists(const char* path, uint64_t* inode, uint64_t* mtime,
|
||||
bool* issetuid, bool* inodesMatchRuntime) const {
|
||||
return false;
|
||||
}
|
56
src/dyld/dyld3/ClosureFileSystemNull.h
Normal file
56
src/dyld/dyld3/ClosureFileSystemNull.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#ifndef ClosureFileSystemNull_h
|
||||
#define ClosureFileSystemNull_h
|
||||
|
||||
#include "ClosureFileSystem.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace dyld3 {
|
||||
namespace closure {
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
|
||||
class __attribute__((visibility("hidden"))) FileSystemNull : public FileSystem {
|
||||
public:
|
||||
FileSystemNull() : FileSystem() { }
|
||||
|
||||
bool getRealPath(const char possiblePath[MAXPATHLEN], char realPath[MAXPATHLEN]) const override;
|
||||
|
||||
bool loadFile(const char* path, LoadedFileInfo& info, char realerPath[MAXPATHLEN], void (^error)(const char* format, ...)) const override;
|
||||
|
||||
void unloadFile(const LoadedFileInfo& info) const override;
|
||||
|
||||
void unloadPartialFile(LoadedFileInfo& info, uint64_t keepStartOffset, uint64_t keepLength) const override;
|
||||
|
||||
bool fileExists(const char* path, uint64_t* inode=nullptr, uint64_t* mtime=nullptr,
|
||||
bool* issetuid=nullptr, bool* inodesMatchRuntime = nullptr) const override;
|
||||
};
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
} // namespace closure
|
||||
} // namespace dyld3
|
||||
|
||||
#endif /* ClosureFileSystemNull_h */
|
289
src/dyld/dyld3/ClosureFileSystemPhysical.cpp
Normal file
289
src/dyld/dyld3/ClosureFileSystemPhysical.cpp
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#include "ClosureFileSystemPhysical.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#if BUILDING_UPDATE_DYLD_CACHE_BUILDER
|
||||
#include <rootless.h>
|
||||
#endif
|
||||
#include <sys/errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <mach/mach.h>
|
||||
#if !TARGET_OS_SIMULATOR && !TARGET_OS_DRIVERKIT
|
||||
#include <sandbox.h>
|
||||
#include <sandbox/private.h>
|
||||
#endif
|
||||
|
||||
using dyld3::closure::FileSystemPhysical;
|
||||
|
||||
bool FileSystemPhysical::getRealPath(const char possiblePath[MAXPATHLEN], char realPath[MAXPATHLEN]) const {
|
||||
__block bool success = false;
|
||||
// first pass: open file and ask kernel for canonical path
|
||||
forEachPath(possiblePath, ^(const char* aPath, unsigned prefixLen, bool& stop) {
|
||||
int fd = ::open(aPath, O_RDONLY, 0);
|
||||
if ( fd != -1 ) {
|
||||
char tempPath[MAXPATHLEN];
|
||||
success = (fcntl(fd, F_GETPATH, tempPath) == 0);
|
||||
::close(fd);
|
||||
if ( success ) {
|
||||
// if prefix was used, remove it
|
||||
strcpy(realPath, &tempPath[prefixLen]);
|
||||
}
|
||||
stop = true;
|
||||
}
|
||||
});
|
||||
if (success)
|
||||
return success;
|
||||
|
||||
// second pass: file does not exist but may be a symlink to a non-existent file
|
||||
// This is only for use on-device on platforms where dylibs are removed
|
||||
if ( _overlayPath == nullptr && _rootPath == nullptr ) {
|
||||
realpath(possiblePath, realPath);
|
||||
int realpathErrno = errno;
|
||||
// If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
|
||||
success = (realpathErrno == ENOENT) || (realpathErrno == 0);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool sandboxBlocked(const char* path, const char* kind)
|
||||
{
|
||||
#if TARGET_OS_SIMULATOR || TARGET_OS_DRIVERKIT
|
||||
// sandbox calls not yet supported in dyld_sim
|
||||
return false;
|
||||
#else
|
||||
sandbox_filter_type filter = (sandbox_filter_type)(SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT);
|
||||
return ( sandbox_check(getpid(), kind, filter, path) > 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool sandboxBlockedMmap(const char* path)
|
||||
{
|
||||
return sandboxBlocked(path, "file-map-executable");
|
||||
}
|
||||
|
||||
static bool sandboxBlockedOpen(const char* path)
|
||||
{
|
||||
return sandboxBlocked(path, "file-read-data");
|
||||
}
|
||||
|
||||
static bool sandboxBlockedStat(const char* path)
|
||||
{
|
||||
return sandboxBlocked(path, "file-read-metadata");
|
||||
}
|
||||
|
||||
void FileSystemPhysical::forEachPath(const char* path, void (^handler)(const char* fullPath, unsigned prefixLen, bool& stop)) const
|
||||
{
|
||||
bool stop = false;
|
||||
char altPath[PATH_MAX];
|
||||
if ( _overlayPath != nullptr ) {
|
||||
strlcpy(altPath, _overlayPath, PATH_MAX);
|
||||
strlcat(altPath, path, PATH_MAX);
|
||||
handler(altPath, (unsigned)strlen(_overlayPath), stop);
|
||||
if ( stop )
|
||||
return;
|
||||
}
|
||||
if ( _rootPath != nullptr ) {
|
||||
strlcpy(altPath, _rootPath, PATH_MAX);
|
||||
strlcat(altPath, path, PATH_MAX);
|
||||
handler(altPath, (unsigned)strlen(_rootPath), stop);
|
||||
if ( stop )
|
||||
return;
|
||||
}
|
||||
else {
|
||||
handler(path, 0, stop);
|
||||
}
|
||||
}
|
||||
|
||||
static bool isFileRelativePath(const char* path)
|
||||
{
|
||||
if ( path[0] == '/' )
|
||||
return false;
|
||||
if ( path[0] != '.' )
|
||||
return true;
|
||||
if ( path[1] == '/' )
|
||||
return true;
|
||||
if ( (path[1] == '.') && (path[2] == '/') )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true on success. If an error occurs the given callback will be called with the reason.
|
||||
// On success, info is filled with info about the loaded file. If the path supplied includes a symlink,
|
||||
// the supplier realerPath is filled in with the real path of the file, otherwise it is set to the empty string.
|
||||
bool FileSystemPhysical::loadFile(const char* path, LoadedFileInfo& info, char realerPath[MAXPATHLEN], void (^error)(const char* format, ...)) const {
|
||||
if ( !_allowRelativePaths && isFileRelativePath(path) ) {
|
||||
error("relative file paths not allowed '%s'", path);
|
||||
return false;
|
||||
}
|
||||
// open file
|
||||
__block int fd;
|
||||
__block struct stat statBuf;
|
||||
__block bool sipProtected = false;
|
||||
forEachPath(path, ^(const char* aPath, unsigned prefixLen, bool& stop) {
|
||||
fd = ::open(aPath, O_RDONLY, 0);
|
||||
if ( fd == -1 ) {
|
||||
int openErrno = errno;
|
||||
if ( (openErrno == EPERM) && sandboxBlockedOpen(path) )
|
||||
error("file system sandbox blocked open(\"%s\", O_RDONLY)", path);
|
||||
else if ( (openErrno != ENOENT) && (openErrno != ENOTDIR) )
|
||||
error("open(\"%s\", O_RDONLY) failed with errno=%d", path, openErrno);
|
||||
}
|
||||
else {
|
||||
// get file info
|
||||
#if TARGET_OS_SIMULATOR
|
||||
if ( ::stat(aPath, &statBuf) != 0 ) {
|
||||
#else
|
||||
if ( ::fstat(fd, &statBuf) != 0 ) {
|
||||
#endif
|
||||
int statErr = errno;
|
||||
if ( (statErr == EPERM) && sandboxBlockedStat(path) )
|
||||
error("file system sandbox blocked stat(\"%s\")", path);
|
||||
else
|
||||
error("stat(\"%s\") failed with errno=%d", path, errno);
|
||||
::close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
else {
|
||||
// Get the realpath of the file if it is a symlink
|
||||
char tempPath[MAXPATHLEN];
|
||||
if ( fcntl(fd, F_GETPATH, tempPath) == 0 ) {
|
||||
const char* realPathWithin = &tempPath[prefixLen];
|
||||
// Don't set the realpath if it is just the same as the regular path
|
||||
if ( strcmp(path, realPathWithin) == 0 ) {
|
||||
// zero out realerPath if path is fine as-is
|
||||
// <rdar://45018392> don't trash input 'path' if realerPath is same buffer as path
|
||||
if ( realerPath != path )
|
||||
realerPath[0] = '\0';
|
||||
}
|
||||
else
|
||||
strcpy(realerPath, realPathWithin);
|
||||
#if BUILDING_UPDATE_DYLD_CACHE_BUILDER
|
||||
sipProtected = (rootless_check_trusted_fd(fd) == 0);
|
||||
#endif
|
||||
stop = true;
|
||||
}
|
||||
else {
|
||||
error("Could not get real path for \"%s\"\n", path);
|
||||
::close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if ( fd == -1 )
|
||||
return false;
|
||||
|
||||
// only regular files can be loaded
|
||||
if ( !S_ISREG(statBuf.st_mode) ) {
|
||||
error("not a file for %s", path);
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// mach-o files must be at list one page in size
|
||||
if ( statBuf.st_size < 4096 ) {
|
||||
error("file too short %s", path);
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
info.fileContent = nullptr;
|
||||
info.fileContentLen = statBuf.st_size;
|
||||
info.sliceOffset = 0;
|
||||
info.sliceLen = statBuf.st_size;
|
||||
info.isSipProtected = sipProtected;
|
||||
info.inode = statBuf.st_ino;
|
||||
info.mtime = statBuf.st_mtime;
|
||||
info.path = path;
|
||||
|
||||
// mmap() whole file
|
||||
void* wholeFile = ::mmap(nullptr, (size_t)statBuf.st_size, PROT_READ, MAP_PRIVATE|MAP_RESILIENT_CODESIGN, fd, 0);
|
||||
if ( wholeFile == MAP_FAILED ) {
|
||||
int mmapErr = errno;
|
||||
if ( mmapErr == EPERM ) {
|
||||
if ( sandboxBlockedMmap(path) )
|
||||
error("file system sandbox blocked mmap() of '%s'", path);
|
||||
else
|
||||
error("code signing blocked mmap() of '%s'", path);
|
||||
}
|
||||
else {
|
||||
error("mmap() failed with errno=%d for %s", errno, path);
|
||||
}
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
info.fileContent = wholeFile;
|
||||
|
||||
// Set unmap as the unload method.
|
||||
info.unload = [](const LoadedFileInfo& info) {
|
||||
::munmap((void*)info.fileContent, (size_t)info.fileContentLen);
|
||||
};
|
||||
|
||||
::close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileSystemPhysical::unloadFile(const LoadedFileInfo& info) const {
|
||||
if (info.unload)
|
||||
info.unload(info);
|
||||
}
|
||||
|
||||
void FileSystemPhysical::unloadPartialFile(LoadedFileInfo& info, uint64_t keepStartOffset, uint64_t keepLength) const {
|
||||
// Unmap from 0..keepStartOffset and (keepStartOffset+keepLength)..info.fileContentLen
|
||||
if (keepStartOffset)
|
||||
::munmap((void*)info.fileContent, (size_t)keepStartOffset);
|
||||
if ((keepStartOffset + keepLength) != info.fileContentLen) {
|
||||
// Round up to page alignment
|
||||
keepLength = (keepLength + PAGE_SIZE - 1) & (-PAGE_SIZE);
|
||||
::munmap((void*)((char*)info.fileContent + keepStartOffset + keepLength), (size_t)(info.fileContentLen - (keepStartOffset + keepLength)));
|
||||
}
|
||||
info.fileContent = (const void*)((char*)info.fileContent + keepStartOffset);
|
||||
info.fileContentLen = keepLength;
|
||||
}
|
||||
|
||||
bool FileSystemPhysical::fileExists(const char* path, uint64_t* inode, uint64_t* mtime,
|
||||
bool* issetuid, bool* inodesMatchRuntime) const {
|
||||
__block bool result = false;
|
||||
forEachPath(path, ^(const char* aPath, unsigned prefixLen, bool& stop) {
|
||||
struct stat statBuf;
|
||||
if ( ::stat(aPath, &statBuf) == 0 ) {
|
||||
if (inode)
|
||||
*inode = statBuf.st_ino;
|
||||
if (mtime)
|
||||
*mtime = statBuf.st_mtime;
|
||||
if (issetuid)
|
||||
*issetuid = (statBuf.st_mode & (S_ISUID|S_ISGID));
|
||||
if (inodesMatchRuntime)
|
||||
*inodesMatchRuntime = true;
|
||||
stop = true;
|
||||
result = true;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
66
src/dyld/dyld3/ClosureFileSystemPhysical.h
Normal file
66
src/dyld/dyld3/ClosureFileSystemPhysical.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#ifndef ClosureFileSystemPhysical_h
|
||||
#define ClosureFileSystemPhysical_h
|
||||
|
||||
#include "ClosureFileSystem.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace dyld3 {
|
||||
namespace closure {
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
|
||||
class __attribute__((visibility("hidden"))) FileSystemPhysical : public FileSystem {
|
||||
public:
|
||||
FileSystemPhysical(const char* rootPath=nullptr, const char* overlayPath=nullptr, bool allowRelativePaths=true)
|
||||
: FileSystem(), _rootPath(rootPath), _overlayPath(overlayPath), _allowRelativePaths(allowRelativePaths)
|
||||
{ }
|
||||
|
||||
bool getRealPath(const char possiblePath[MAXPATHLEN], char realPath[MAXPATHLEN]) const override;
|
||||
|
||||
bool loadFile(const char* path, LoadedFileInfo& info, char realerPath[MAXPATHLEN], void (^error)(const char* format, ...)) const override;
|
||||
|
||||
void unloadFile(const LoadedFileInfo& info) const override;
|
||||
|
||||
void unloadPartialFile(LoadedFileInfo& info, uint64_t keepStartOffset, uint64_t keepLength) const override;
|
||||
|
||||
bool fileExists(const char* path, uint64_t* inode=nullptr, uint64_t* mtime=nullptr,
|
||||
bool* issetuid=nullptr, bool* inodesMatchRuntime = nullptr) const override;
|
||||
|
||||
private:
|
||||
|
||||
void forEachPath(const char* path, void (^handler)(const char* fullPath, unsigned prefixLen, bool& stop)) const;
|
||||
|
||||
const char* _rootPath;
|
||||
const char* _overlayPath;
|
||||
bool _allowRelativePaths;
|
||||
};
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
} // namespace closure
|
||||
} // namespace dyld3
|
||||
|
||||
#endif /* ClosureFileSystemPhysical_h */
|
773
src/dyld/dyld3/ClosurePrinter.cpp
Normal file
773
src/dyld/dyld3/ClosurePrinter.cpp
Normal file
@ -0,0 +1,773 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "ClosurePrinter.h"
|
||||
#include "JSONWriter.h"
|
||||
|
||||
#include "objc-shared-cache.h"
|
||||
|
||||
using namespace dyld3::json;
|
||||
|
||||
namespace dyld3 {
|
||||
namespace closure {
|
||||
|
||||
static std::string printTarget(const Array<const ImageArray*>& imagesArrays, Image::ResolvedSymbolTarget target)
|
||||
{
|
||||
const Image* targetImage;
|
||||
uint64_t value;
|
||||
switch ( target.image.kind ) {
|
||||
case Image::ResolvedSymbolTarget::kindImage:
|
||||
targetImage = ImageArray::findImage(imagesArrays, target.image.imageNum);
|
||||
if ( target.image.offset & 0x8000000000ULL ) {
|
||||
uint64_t signExtend = target.image.offset | 0xFFFFFF0000000000ULL;
|
||||
return std::string("bind to ") + targetImage->leafName() + " - " + hex8(-signExtend);
|
||||
}
|
||||
else
|
||||
return std::string("bind to ") + targetImage->leafName() + " + " + hex8(target.image.offset);
|
||||
break;
|
||||
case Image::ResolvedSymbolTarget::kindSharedCache:
|
||||
return std::string("bind to dyld cache + ") + hex8(target.sharedCache.offset);
|
||||
break;
|
||||
case Image::ResolvedSymbolTarget::kindAbsolute:
|
||||
value = target.absolute.value;
|
||||
if ( value & 0x2000000000000000LL )
|
||||
value |= 0xC000000000000000LL;
|
||||
return std::string("bind to absolute ") + hex(value);
|
||||
break;
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
static const char* nameForType(TypedBytes::Type type) {
|
||||
switch (type) {
|
||||
// containers
|
||||
case TypedBytes::Type::launchClosure:
|
||||
return "launchClosure";
|
||||
case TypedBytes::Type::imageArray:
|
||||
return "imageArray";
|
||||
case TypedBytes::Type::image:
|
||||
return "image";
|
||||
case TypedBytes::Type::dlopenClosure:
|
||||
return "dlopenClosure";
|
||||
// attributes for Images
|
||||
case TypedBytes::Type::imageFlags:
|
||||
return "imageFlags";
|
||||
case TypedBytes::Type::pathWithHash:
|
||||
return "pathWithHash";
|
||||
case TypedBytes::Type::fileInodeAndTime:
|
||||
return "fileInodeAndTime";
|
||||
case TypedBytes::Type::cdHash:
|
||||
return "cdHash";
|
||||
case TypedBytes::Type::uuid:
|
||||
return "uuid";
|
||||
case TypedBytes::Type::mappingInfo:
|
||||
return "mappingInfo";
|
||||
case TypedBytes::Type::diskSegment:
|
||||
return "diskSegment";
|
||||
case TypedBytes::Type::cacheSegment:
|
||||
return "cacheSegment";
|
||||
case TypedBytes::Type::dependents:
|
||||
return "dependents";
|
||||
case TypedBytes::Type::initOffsets:
|
||||
return "initOffsets";
|
||||
case TypedBytes::Type::dofOffsets:
|
||||
return "dofOffsets";
|
||||
case TypedBytes::Type::codeSignLoc:
|
||||
return "codeSignLoc";
|
||||
case TypedBytes::Type::fairPlayLoc:
|
||||
return "fairPlayLoc";
|
||||
case TypedBytes::Type::rebaseFixups:
|
||||
return "rebaseFixups";
|
||||
case TypedBytes::Type::bindFixups:
|
||||
return "bindFixups";
|
||||
case TypedBytes::Type::cachePatchInfo:
|
||||
return "cachePatchInfo";
|
||||
case TypedBytes::Type::textFixups:
|
||||
return "textFixups";
|
||||
case TypedBytes::Type::imageOverride:
|
||||
return "imageOverride";
|
||||
case TypedBytes::Type::initBefores:
|
||||
return "initBefores";
|
||||
case TypedBytes::Type::initsSection:
|
||||
return "initSection";
|
||||
case TypedBytes::Type::chainedFixupsTargets:
|
||||
return "chainedFixupsTargets";
|
||||
case TypedBytes::Type::termOffsets:
|
||||
return "termOffsets";
|
||||
case TypedBytes::Type::chainedStartsOffset:
|
||||
return "chainedStartsOffset";
|
||||
case TypedBytes::Type::objcFixups:
|
||||
return "objcFixups";
|
||||
// attributes for Closures (launch or dlopen)
|
||||
case TypedBytes::Type::closureFlags:
|
||||
return "closureFlags";
|
||||
case TypedBytes::Type::dyldCacheUUID:
|
||||
return "dyldCacheUUID";
|
||||
case TypedBytes::Type::missingFiles:
|
||||
return "missingFiles";
|
||||
case TypedBytes::Type::envVar:
|
||||
return "envVar";
|
||||
case TypedBytes::Type::topImage:
|
||||
return "topImage";
|
||||
case TypedBytes::Type::libDyldEntry:
|
||||
return "libDyldEntry";
|
||||
case TypedBytes::Type::libSystemNum:
|
||||
return "libSystemNum";
|
||||
case TypedBytes::Type::bootUUID:
|
||||
return "bootUUID";
|
||||
case TypedBytes::Type::mainEntry:
|
||||
return "mainEntry";
|
||||
case TypedBytes::Type::startEntry:
|
||||
return "startEntry";
|
||||
case TypedBytes::Type::cacheOverrides:
|
||||
return "cacheOverrides";
|
||||
case TypedBytes::Type::interposeTuples:
|
||||
return "interposeTuples";
|
||||
case TypedBytes::Type::existingFiles:
|
||||
return "existingFiles";
|
||||
case TypedBytes::Type::selectorTable:
|
||||
return "selectorTable";
|
||||
case TypedBytes::Type::classTable:
|
||||
return "classTable";
|
||||
case TypedBytes::Type::warning:
|
||||
return "warning";
|
||||
case TypedBytes::Type::duplicateClassesTable:
|
||||
return "duplicateClassesTable";
|
||||
}
|
||||
}
|
||||
|
||||
static Node buildImageNode(const Image* image, const Array<const ImageArray*>& imagesArrays, bool printFixups,
|
||||
bool printDependentsDetails, bool printRaw,
|
||||
const DyldSharedCache* dyldCache, const closure::ObjCSelectorOpt* selOpt,
|
||||
const Array<closure::Image::ObjCSelectorImage>& selImages)
|
||||
{
|
||||
__block Node imageNode;
|
||||
|
||||
if ( image->isInvalid() )
|
||||
return imageNode;
|
||||
|
||||
imageNode.map["image-num"].value = hex4(image->imageNum());
|
||||
imageNode.map["path"].value = image->path();
|
||||
|
||||
if (printRaw) {
|
||||
__block Node attributes;
|
||||
image->forEachAttribute(^(const TypedBytes *typedBytes, bool &stop) {
|
||||
Node anAttribute;
|
||||
anAttribute.map["type"].value = decimal((uint32_t)typedBytes->type);
|
||||
anAttribute.map["type-name"].value = nameForType((TypedBytes::Type)typedBytes->type);
|
||||
anAttribute.map["length"].value = decimal(typedBytes->payloadLength);
|
||||
attributes.array.push_back(anAttribute);
|
||||
});
|
||||
imageNode.map["attributes"] = attributes;
|
||||
return imageNode;
|
||||
}
|
||||
|
||||
__block Node imageAliases;
|
||||
image->forEachAlias(^(const char* aliasPath, bool& stop) {
|
||||
Node anAlias;
|
||||
anAlias.value = aliasPath;
|
||||
imageAliases.array.push_back(anAlias);
|
||||
});
|
||||
if ( !imageAliases.array.empty() )
|
||||
imageNode.map["aliases"] = imageAliases;
|
||||
uuid_t uuid;
|
||||
if ( image->getUuid(uuid) ) {
|
||||
uuid_string_t uuidStr;
|
||||
uuid_unparse(uuid, uuidStr);
|
||||
imageNode.map["uuid"].value = uuidStr;
|
||||
}
|
||||
imageNode.map["has-objc"].value = (image->hasObjC() ? "true" : "false");
|
||||
imageNode.map["has-weak-defs"].value = (image->hasWeakDefs() ? "true" : "false");
|
||||
imageNode.map["has-plus-loads"].value = (image->mayHavePlusLoads() ? "true" : "false");
|
||||
imageNode.map["never-unload"].value = (image->neverUnload() ? "true" : "false");
|
||||
imageNode.map["has-precomputed-objc"].value = (image->hasPrecomputedObjC() ? "true" : "false");
|
||||
// imageNode.map["platform-binary"].value = (image->isPlatformBinary() ? "true" : "false");
|
||||
// if ( image->cwdMustBeThisDir() )
|
||||
// imageNode.map["cwd-must-be-this-dir"].value = "true";
|
||||
if ( !image->inDyldCache() ) {
|
||||
uint32_t csFileOffset;
|
||||
uint32_t csSize;
|
||||
if ( image->hasCodeSignature(csFileOffset, csSize) ) {
|
||||
imageNode.map["code-sign-location"].map["offset"].value = hex(csFileOffset);
|
||||
imageNode.map["code-sign-location"].map["size"].value = hex(csSize);
|
||||
}
|
||||
// uint32_t fpTextOffset;
|
||||
// uint32_t fpSize;
|
||||
// if ( image->isFairPlayEncrypted(fpTextOffset, fpSize) ) {
|
||||
// imageNode.map["fairplay-encryption-location"].map["offset"].value = hex(fpTextOffset);
|
||||
// imageNode.map["fairplay-encryption-location"].map["size"].value = hex(fpSize);
|
||||
// }
|
||||
uint64_t inode;
|
||||
uint64_t mTime;
|
||||
if ( image->hasFileModTimeAndInode(inode, mTime) ) {
|
||||
imageNode.map["file-mod-time"].value = hex(inode);
|
||||
imageNode.map["file-inode"].value = hex(mTime);
|
||||
}
|
||||
image->forEachCDHash(^(const uint8_t *cdHash, bool& stop) {
|
||||
std::string cdHashStr;
|
||||
cdHashStr.reserve(24);
|
||||
for (int i=0; i < 20; ++i) {
|
||||
uint8_t byte = cdHash[i];
|
||||
uint8_t nibbleL = byte & 0x0F;
|
||||
uint8_t nibbleH = byte >> 4;
|
||||
if ( nibbleH < 10 )
|
||||
cdHashStr += '0' + nibbleH;
|
||||
else
|
||||
cdHashStr += 'a' + (nibbleH-10);
|
||||
if ( nibbleL < 10 )
|
||||
cdHashStr += '0' + nibbleL;
|
||||
else
|
||||
cdHashStr += 'a' + (nibbleL-10);
|
||||
}
|
||||
if ( cdHashStr != "0000000000000000000000000000000000000000" ) {
|
||||
Node hashNode;
|
||||
hashNode.value = cdHashStr;
|
||||
imageNode.map["cd-hashes"].array.push_back(hashNode);
|
||||
}
|
||||
});
|
||||
imageNode.map["total-vm-size"].value = hex(image->vmSizeToMap());
|
||||
uint64_t sliceOffset = image->sliceOffsetInFile();
|
||||
if ( sliceOffset != 0 )
|
||||
imageNode.map["file-offset-of-slice"].value = hex(sliceOffset);
|
||||
//if ( image->hasTextRelocs() )
|
||||
// imageNode.map["has-text-relocs"].value = "true";
|
||||
image->forEachDiskSegment(^(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool laterReadOnly, bool& stop) {
|
||||
Node segInfoNode;
|
||||
segInfoNode.map["file-offset"].value = hex(fileOffset);
|
||||
segInfoNode.map["file-size"].value = hex(fileSize);
|
||||
segInfoNode.map["vm-size"].value = hex(vmSize);
|
||||
imageNode.map["mappings"].array.push_back(segInfoNode);
|
||||
switch ( permissions ) {
|
||||
case 0:
|
||||
segInfoNode.map["permissions"].value = "--";
|
||||
break;
|
||||
case 1:
|
||||
segInfoNode.map["permissions"].value = "r";
|
||||
break;
|
||||
case 2:
|
||||
segInfoNode.map["permissions"].value = "ro"; // r/w then r/o
|
||||
break;
|
||||
case 3:
|
||||
segInfoNode.map["permissions"].value = "rw";
|
||||
break;
|
||||
case 4:
|
||||
segInfoNode.map["permissions"].value = "rx";
|
||||
break;
|
||||
default:
|
||||
segInfoNode.map["permissions"].value = "??";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if ( printFixups ) {
|
||||
image->forEachFixup(^(uint64_t imageOffsetToRebase, bool &stop) {
|
||||
// rebase
|
||||
imageNode.map["fixups"].map[hex8(imageOffsetToRebase)].value = "rebase";
|
||||
}, ^(uint64_t imageOffsetToBind, Image::ResolvedSymbolTarget target, bool &stop) {
|
||||
// bind
|
||||
imageNode.map["fixups"].map[hex8(imageOffsetToBind)].value = printTarget(imagesArrays, target);
|
||||
}, ^(uint64_t startsStructImageOffset, const Array<Image::ResolvedSymbolTarget>& targets, bool& stop) {
|
||||
// chain
|
||||
imageNode.map["fixups-chain-starts-offset"].value = hex8(startsStructImageOffset);
|
||||
for (const Image::ResolvedSymbolTarget& target: targets) {
|
||||
Node targetNode;
|
||||
targetNode.value = printTarget(imagesArrays, target);
|
||||
imageNode.map["fixups-targets"].array.push_back(targetNode);
|
||||
}
|
||||
|
||||
}, ^(uint64_t imageOffsetToFixup) {
|
||||
// fixupObjCImageInfo
|
||||
imageNode.map["fixups"].map[hex8(imageOffsetToFixup)].value = "objc image info pre-optimized by dyld flag";
|
||||
}, ^(uint64_t imageOffsetToBind, Image::ResolvedSymbolTarget target, bool &stop) {
|
||||
// fixupObjCProtocol
|
||||
imageNode.map["fixups"].map[hex8(imageOffsetToBind)].value = printTarget(imagesArrays, target);
|
||||
}, ^(uint64_t imageOffsetToFixup, uint32_t selectorIndex, bool inSharedCache, bool &stop) {
|
||||
// fixupObjCSelRefs
|
||||
Image::ResolvedSymbolTarget target;
|
||||
if ( inSharedCache ) {
|
||||
const char* selectorString = dyldCache->objcOpt()->selopt()->getEntryForIndex(selectorIndex);
|
||||
target.sharedCache.kind = Image::ResolvedSymbolTarget::kindSharedCache;
|
||||
target.sharedCache.offset = (uint64_t)selectorString - (uint64_t)dyldCache;
|
||||
} else {
|
||||
ImageNum imageNum;
|
||||
uint64_t vmOffset;
|
||||
bool gotLocation = selOpt->getStringLocation(selectorIndex, selImages, imageNum, vmOffset);
|
||||
assert(gotLocation);
|
||||
target.image.kind = Image::ResolvedSymbolTarget::kindImage;
|
||||
target.image.imageNum = imageNum;
|
||||
target.image.offset = vmOffset;
|
||||
}
|
||||
imageNode.map["fixups"].map[hex8(imageOffsetToFixup)].value = printTarget(imagesArrays, target);
|
||||
}, ^(uint64_t imageOffsetToFixup, bool &stop) {
|
||||
// fixupObjCStableSwift
|
||||
imageNode.map["fixups"].map[hex8(imageOffsetToFixup)].value = "objc set stable Swift";
|
||||
}, ^(uint64_t imageOffsetToFixup, bool &stop) {
|
||||
// fixupObjCMethodList
|
||||
imageNode.map["fixups"].map[hex8(imageOffsetToFixup)].value = "objc set fixed up method list";
|
||||
});
|
||||
image->forEachTextReloc(^(uint32_t imageOffsetToRebase, bool &stop) {
|
||||
// rebase
|
||||
imageNode.map["fixups"].map[hex8(imageOffsetToRebase)].value = "text rebase";
|
||||
}, ^(uint32_t imageOffsetToBind, Image::ResolvedSymbolTarget target, bool &stop) {
|
||||
imageNode.map["fixups"].map[hex8(imageOffsetToBind)].value = "text " + printTarget(imagesArrays, target);
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( printFixups ) {
|
||||
if ( dyldCache != nullptr ) {
|
||||
uint32_t imageIndex = image->imageNum() - (uint32_t)dyldCache->cachedDylibsImageArray()->startImageNum();
|
||||
dyldCache->forEachPatchableExport(imageIndex, ^(uint32_t cacheOffsetOfImpl, const char* name) {
|
||||
__block Node implNode;
|
||||
implNode.map["name"].value = name;
|
||||
implNode.map["impl-cache-offset"].value = hex8(cacheOffsetOfImpl);
|
||||
dyldCache->forEachPatchableUseOfExport(imageIndex, cacheOffsetOfImpl, ^(dyld_cache_patchable_location patchLocation) {
|
||||
Node siteNode;
|
||||
siteNode.map["cache-offset"].value = hex8(patchLocation.cacheOffset);
|
||||
if ( patchLocation.addend != 0 )
|
||||
siteNode.map["addend"].value = hex(patchLocation.addend);
|
||||
if ( patchLocation.authenticated != 0 ) {
|
||||
siteNode.map["key"].value = DyldSharedCache::keyName(patchLocation);
|
||||
siteNode.map["address-diversity"].value = patchLocation.usesAddressDiversity ? "true" : "false";
|
||||
siteNode.map["discriminator"].value = hex4(patchLocation.discriminator);
|
||||
}
|
||||
implNode.map["usage-sites"].array.push_back(siteNode);
|
||||
});
|
||||
imageNode.map["patches"].array.push_back(implNode);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add dependents
|
||||
image->forEachDependentImage(^(uint32_t depIndex, Image::LinkKind kind, ImageNum imageNum, bool& stop) {
|
||||
Node depMapNode;
|
||||
const Image* depImage = ImageArray::findImage(imagesArrays, imageNum);
|
||||
depMapNode.map["image-num"].value = hex4(imageNum);
|
||||
if ( depImage != nullptr )
|
||||
depMapNode.map["path"].value = depImage->path();
|
||||
switch ( kind ) {
|
||||
case Image::LinkKind::regular:
|
||||
depMapNode.map["link"].value = "regular";
|
||||
break;
|
||||
case Image::LinkKind::reExport:
|
||||
depMapNode.map["link"].value = "re-export";
|
||||
break;
|
||||
case Image::LinkKind::upward:
|
||||
depMapNode.map["link"].value = "upward";
|
||||
break;
|
||||
case Image::LinkKind::weak:
|
||||
depMapNode.map["link"].value = "weak";
|
||||
break;
|
||||
}
|
||||
imageNode.map["dependents"].array.push_back(depMapNode);
|
||||
});
|
||||
|
||||
// add initializers
|
||||
bool usesInitsSection = image->forEachInitializerSection(^(uint32_t sectionOffset, uint32_t sectionSize) {
|
||||
Node initSectNode;
|
||||
initSectNode.map["offset"].value = hex(sectionOffset);
|
||||
initSectNode.map["size"].value = hex(sectionSize);
|
||||
imageNode.map["initializers-section"].array.push_back(initSectNode);
|
||||
});
|
||||
if ( !usesInitsSection ) {
|
||||
image->forEachInitializer(nullptr, ^(const void* initializer) {
|
||||
Node initNode;
|
||||
initNode.value = hex((long)initializer);
|
||||
imageNode.map["initializer-offsets"].array.push_back(initNode);
|
||||
});
|
||||
}
|
||||
__block Node initBeforeNode;
|
||||
image->forEachImageToInitBefore(^(ImageNum imageToInit, bool& stop) {
|
||||
Node beforeNode;
|
||||
const Image* initImage = ImageArray::findImage(imagesArrays, imageToInit);
|
||||
assert(initImage != nullptr);
|
||||
beforeNode.value = initImage->path();
|
||||
imageNode.map["initializer-order"].array.push_back(beforeNode);
|
||||
});
|
||||
|
||||
// add static terminators
|
||||
image->forEachTerminator(nullptr, ^(const void* terminator) {
|
||||
Node termNode;
|
||||
termNode.value = hex8((long)terminator);
|
||||
imageNode.map["terminator-offsets"].array.push_back(termNode);
|
||||
});
|
||||
|
||||
ImageNum cacheImageNum;
|
||||
if ( image->isOverrideOfDyldCacheImage(cacheImageNum) ) {
|
||||
imageNode.map["override-of-dyld-cache-image"].value = ImageArray::findImage(imagesArrays, cacheImageNum)->path();
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
// add things to init before this image
|
||||
__block Node initBeforeNode;
|
||||
image->forEachInitBefore(groupList, ^(Image beforeImage) {
|
||||
Node beforeNode;
|
||||
beforeNode.value = beforeimage->path();
|
||||
imageNode.map["initializer-order"].array.push_back(beforeNode);
|
||||
});
|
||||
|
||||
// add override info if relevant
|
||||
group.forEachImageRefOverride(groupList, ^(Image standardDylib, Image overrideDylib, bool& stop) {
|
||||
if ( overrideDylib.binaryData() == image->binaryData() ) {
|
||||
imageNode.map["override-of-cached-dylib"].value = standardDylib.path();
|
||||
}
|
||||
});
|
||||
// add dtrace info
|
||||
image->forEachDOF(nullptr, ^(const void* section) {
|
||||
Node initNode;
|
||||
initNode.value = hex((long)section);
|
||||
imageNode.map["dof-offsets"].array.push_back(initNode);
|
||||
});
|
||||
#endif
|
||||
|
||||
return imageNode;
|
||||
}
|
||||
|
||||
|
||||
static Node buildImageArrayNode(const ImageArray* imageArray, const Array<const ImageArray*>& imagesArrays,
|
||||
bool printFixups, bool printDependentsDetails, bool printRaw,
|
||||
const DyldSharedCache* dyldCache, const closure::ObjCSelectorOpt* selOpt,
|
||||
const Array<closure::Image::ObjCSelectorImage>& selImages)
|
||||
{
|
||||
__block Node images;
|
||||
imageArray->forEachImage(^(const Image* image, bool& stop) {
|
||||
images.array.push_back(buildImageNode(image, imagesArrays, printFixups, printDependentsDetails, printRaw, dyldCache, selOpt, selImages));
|
||||
});
|
||||
return images;
|
||||
}
|
||||
|
||||
|
||||
static Node buildClosureNode(const DlopenClosure* closure, const Array<const ImageArray*>& imagesArrays,
|
||||
bool printFixups, bool printRaw, bool printDependentsDetails)
|
||||
{
|
||||
__block Node root;
|
||||
root.map["images"] = buildImageArrayNode(closure->images(), imagesArrays,
|
||||
printFixups, printDependentsDetails, printRaw,
|
||||
nullptr, nullptr, {});
|
||||
|
||||
closure->forEachPatchEntry(^(const Closure::PatchEntry& patchEntry) {
|
||||
Node patchNode;
|
||||
patchNode.map["func-dyld-cache-offset"].value = hex8(patchEntry.exportCacheOffset);
|
||||
patchNode.map["func-image-num"].value = hex8(patchEntry.overriddenDylibInCache);
|
||||
patchNode.map["replacement"].value = printTarget(imagesArrays, patchEntry.replacement);
|
||||
root.map["dyld-cache-fixups"].array.push_back(patchNode);
|
||||
});
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
static Node buildClosureNode(const LaunchClosure* closure, const Array<const ImageArray*>& imagesArrays,
|
||||
bool printFixups, bool printDependentsDetails, bool printRaw,
|
||||
const DyldSharedCache* dyldCache)
|
||||
{
|
||||
__block Node root;
|
||||
|
||||
Array<Image::ObjCSelectorImage> selectorImages;
|
||||
const closure::ObjCSelectorOpt* selectorHashTable = nullptr;
|
||||
bool hasPreoptimizedObjCSelectors = closure->selectorHashTable(selectorImages, selectorHashTable);
|
||||
|
||||
root.map["images"] = buildImageArrayNode(closure->images(), imagesArrays, printFixups,
|
||||
printDependentsDetails, printRaw,
|
||||
dyldCache, selectorHashTable, selectorImages);
|
||||
|
||||
if ( printRaw ) {
|
||||
__block Node attributes;
|
||||
closure->forEachAttribute(^(const TypedBytes *typedBytes, bool &stop) {
|
||||
Node anAttribute;
|
||||
anAttribute.map["type"].value = decimal((uint32_t)typedBytes->type);
|
||||
anAttribute.map["type-name"].value = nameForType((TypedBytes::Type)typedBytes->type);
|
||||
anAttribute.map["length"].value = decimal(typedBytes->payloadLength);
|
||||
attributes.array.push_back(anAttribute);
|
||||
});
|
||||
root.map["attributes"] = attributes;
|
||||
return root;
|
||||
}
|
||||
|
||||
closure->forEachPatchEntry(^(const Closure::PatchEntry& patchEntry) {
|
||||
Node patchNode;
|
||||
patchNode.map["func-dyld-cache-offset"].value = hex8(patchEntry.exportCacheOffset);
|
||||
patchNode.map["func-image-num"].value = hex8(patchEntry.overriddenDylibInCache);
|
||||
patchNode.map["replacement"].value = printTarget(imagesArrays, patchEntry.replacement);
|
||||
root.map["dyld-cache-fixups"].array.push_back(patchNode);
|
||||
});
|
||||
|
||||
Image::ResolvedSymbolTarget entry;
|
||||
if ( closure->mainEntry(entry) )
|
||||
root.map["main"].value = printTarget(imagesArrays, entry);
|
||||
else if ( closure->startEntry(entry) )
|
||||
root.map["start"].value = printTarget(imagesArrays, entry);
|
||||
|
||||
Image::ResolvedSymbolTarget libdyldEntry;
|
||||
closure->libDyldEntry(libdyldEntry);
|
||||
root.map["libdyld-entry"].value = printTarget(imagesArrays, libdyldEntry);
|
||||
|
||||
root.map["uses-@paths"].value = (closure->usedAtPaths() ? "true" : "false");
|
||||
root.map["uses-fallback-paths"].value = (closure->usedFallbackPaths() ? "true" : "false");
|
||||
|
||||
// add missing files array if they exist
|
||||
closure->forEachMustBeMissingFile(^(const char* path, bool& stop) {
|
||||
Node fileNode;
|
||||
fileNode.value = path;
|
||||
root.map["must-be-missing-files"].array.push_back(fileNode);
|
||||
});
|
||||
|
||||
// add skipped files array if they exist
|
||||
closure->forEachSkipIfExistsFile(^(const LaunchClosure::SkippedFile &file, bool &stop) {
|
||||
Node fileNode;
|
||||
fileNode.map["path"].value = file.path;
|
||||
fileNode.map["file-mod-time"].value = hex(file.mtime);
|
||||
fileNode.map["file-inode"].value = hex(file.inode);
|
||||
root.map["skipped-existing-files"].array.push_back(fileNode);
|
||||
});
|
||||
|
||||
// add interposing info, if any
|
||||
closure->forEachInterposingTuple(^(const InterposingTuple& tuple, bool& stop) {
|
||||
Node tupleNode;
|
||||
tupleNode.map["stock"].value = printTarget(imagesArrays, tuple.stockImplementation);
|
||||
tupleNode.map["replace"].value = printTarget(imagesArrays, tuple.newImplementation);
|
||||
root.map["interposing-tuples"].array.push_back(tupleNode);
|
||||
});
|
||||
|
||||
closure->forEachPatchEntry(^(const Closure::PatchEntry& patchEntry) {
|
||||
Node patchNode;
|
||||
patchNode.map["func-dyld-cache-offset"].value = hex8(patchEntry.exportCacheOffset);
|
||||
patchNode.map["func-image-num"].value = hex8(patchEntry.overriddenDylibInCache);
|
||||
patchNode.map["replacement"].value = printTarget(imagesArrays, patchEntry.replacement);
|
||||
root.map["dyld-cache-fixups"].array.push_back(patchNode);
|
||||
});
|
||||
|
||||
root.map["initial-image-count"].value = decimal(closure->initialLoadCount());
|
||||
|
||||
// add env-vars if they exist
|
||||
closure->forEachEnvVar(^(const char* keyEqualValue, bool& stop) {
|
||||
const char* equ = strchr(keyEqualValue, '=');
|
||||
if ( equ != nullptr ) {
|
||||
char key[512];
|
||||
strncpy(key, keyEqualValue, equ-keyEqualValue);
|
||||
key[equ-keyEqualValue] = '\0';
|
||||
root.map["env-vars"].map[key].value = equ+1;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasPreoptimizedObjCSelectors) {
|
||||
__block Node selectorsNode;
|
||||
selectorHashTable->forEachString(selectorImages,
|
||||
^(uint64_t selVMOffset, ImageNum imageNum) {
|
||||
// Convert to a target we can get a real name for
|
||||
dyld3::closure::Image::ResolvedSymbolTarget target;
|
||||
target.image.kind = dyld3::closure::Image::ResolvedSymbolTarget::kindImage;
|
||||
target.image.imageNum = imageNum;
|
||||
target.image.offset = selVMOffset;
|
||||
|
||||
Node targetNode;
|
||||
targetNode.value = printTarget(imagesArrays, target);
|
||||
selectorsNode.array.push_back(targetNode);
|
||||
});
|
||||
|
||||
root.map["objc-selectors"] = selectorsNode;
|
||||
}
|
||||
|
||||
Array<Image::ObjCClassImage> classImages;
|
||||
const ObjCClassOpt* classHashTable = nullptr;
|
||||
const ObjCClassOpt* protocolHashTable = nullptr;
|
||||
if (closure->classAndProtocolHashTables(classImages, classHashTable, protocolHashTable)) {
|
||||
if ( classHashTable != nullptr ) {
|
||||
__block Node classesNode;
|
||||
|
||||
classHashTable->forEachClass(classImages,
|
||||
^(uint64_t classNameVMOffset, ImageNum imageNum) {
|
||||
// Convert to a target we can get a real name for
|
||||
dyld3::closure::Image::ResolvedSymbolTarget target;
|
||||
target.image.kind = dyld3::closure::Image::ResolvedSymbolTarget::kindImage;
|
||||
target.image.imageNum = imageNum;
|
||||
target.image.offset = classNameVMOffset;
|
||||
|
||||
Node targetNode;
|
||||
targetNode.value = printTarget(imagesArrays, target);
|
||||
|
||||
Node classNode;
|
||||
classNode.map["name"] = targetNode;
|
||||
classesNode.array.push_back(classNode);
|
||||
},
|
||||
^(uint64_t classVMOffset, ImageNum imageNum) {
|
||||
dyld3::closure::Image::ResolvedSymbolTarget implTarget;
|
||||
implTarget.image.kind = dyld3::closure::Image::ResolvedSymbolTarget::kindImage;
|
||||
implTarget.image.imageNum = imageNum;
|
||||
implTarget.image.offset = classVMOffset;
|
||||
|
||||
Node implNode;
|
||||
implNode.value = printTarget(imagesArrays, implTarget);
|
||||
classesNode.array.back().map["implementations"].array.push_back(implNode);
|
||||
});
|
||||
|
||||
root.map["objc-classes"] = classesNode;
|
||||
}
|
||||
|
||||
if ( protocolHashTable != nullptr ) {
|
||||
__block Node protocolsNode;
|
||||
|
||||
protocolHashTable->forEachClass(classImages,
|
||||
^(uint64_t protocolNameVMOffset, ImageNum imageNum) {
|
||||
// Convert to a target we can get a real name for
|
||||
dyld3::closure::Image::ResolvedSymbolTarget target;
|
||||
target.image.kind = dyld3::closure::Image::ResolvedSymbolTarget::kindImage;
|
||||
target.image.imageNum = imageNum;
|
||||
target.image.offset = protocolNameVMOffset;
|
||||
|
||||
Node targetNode;
|
||||
targetNode.value = printTarget(imagesArrays, target);
|
||||
|
||||
Node protocolNode;
|
||||
protocolNode.map["name"] = targetNode;
|
||||
protocolsNode.array.push_back(protocolNode);
|
||||
},
|
||||
^(uint64_t protocolVMOffset, ImageNum imageNum) {
|
||||
dyld3::closure::Image::ResolvedSymbolTarget implTarget;
|
||||
implTarget.image.kind = dyld3::closure::Image::ResolvedSymbolTarget::kindImage;
|
||||
implTarget.image.imageNum = imageNum;
|
||||
implTarget.image.offset = protocolVMOffset;
|
||||
|
||||
Node implNode;
|
||||
implNode.value = printTarget(imagesArrays, implTarget);
|
||||
protocolsNode.array.back().map["implementations"].array.push_back(implNode);
|
||||
});
|
||||
|
||||
root.map["objc-protocols"] = protocolsNode;
|
||||
}
|
||||
}
|
||||
|
||||
const ObjCClassDuplicatesOpt* duplicateClassesHashTable = nullptr;
|
||||
closure->duplicateClassesHashTable(duplicateClassesHashTable);
|
||||
if ( duplicateClassesHashTable != nullptr ) {
|
||||
__block Node duplicateClassesNode;
|
||||
duplicateClassesHashTable->forEachClass(^(Image::ObjCDuplicateClass duplicateClass) {
|
||||
objc_opt::objc_clsopt_t* clsOpt = dyldCache->objcOpt()->clsopt();
|
||||
const char* className = clsOpt->getClassNameForIndex(duplicateClass.sharedCacheClassOptIndex);
|
||||
const void* classImpl = clsOpt->getClassForIndex(duplicateClass.sharedCacheClassOptIndex, duplicateClass.sharedCacheClassDuplicateIndex);
|
||||
|
||||
// Convert to a target we can get a real name for
|
||||
dyld3::closure::Image::ResolvedSymbolTarget target;
|
||||
target.sharedCache.kind = dyld3::closure::Image::ResolvedSymbolTarget::kindSharedCache;
|
||||
target.sharedCache.offset = (uint64_t)classImpl - (uint64_t)dyldCache;
|
||||
|
||||
Node targetNode;
|
||||
targetNode.value = printTarget(imagesArrays, target);
|
||||
|
||||
Node duplicateClassNode;
|
||||
duplicateClassNode.map["name"].value = className;
|
||||
duplicateClassNode.map["implementation"] = targetNode;
|
||||
duplicateClassNode.array.push_back(targetNode);
|
||||
|
||||
duplicateClassesNode.array.push_back(duplicateClassNode);
|
||||
});
|
||||
|
||||
root.map["objc-duplicate-classes"] = duplicateClassesNode;
|
||||
}
|
||||
|
||||
// add warnings for objc if they exist
|
||||
closure->forEachWarning(Closure::Warning::duplicateObjCClass, ^(const char *warning, bool &stop) {
|
||||
Node warningNode;
|
||||
warningNode.value = warning;
|
||||
root.map["objc-duplicate-class-warnings"].array.push_back(warningNode);
|
||||
});
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
// add uuid of dyld cache this closure requires
|
||||
closure.dyldCacheUUID();
|
||||
uuid_string_t cacheUuidStr;
|
||||
uuid_unparse(*closure.dyldCacheUUID(), cacheUuidStr);
|
||||
root.map["dyld-cache-uuid"].value = cacheUuidStr;
|
||||
|
||||
// add top level images
|
||||
Node& rootImages = root.map["root-images"];
|
||||
uint32_t initImageCount = closure.mainExecutableImageIndex();
|
||||
rootImages.array.resize(initImageCount+1);
|
||||
for (uint32_t i=0; i <= initImageCount; ++i) {
|
||||
const Image image = closure.group().image(i);
|
||||
uuid_string_t uuidStr;
|
||||
uuid_unparse(image->uuid(), uuidStr);
|
||||
rootImages.array[i].value = uuidStr;
|
||||
}
|
||||
root.map["initial-image-count"].value = decimal(closure.initialImageCount());
|
||||
|
||||
// add images
|
||||
root.map["group-num"].value = decimal(closure.group().groupNum());
|
||||
|
||||
|
||||
__block Node cacheOverrides;
|
||||
closure.group().forEachDyldCacheSymbolOverride(^(uint32_t patchTableIndex, uint32_t imageIndexInClosure, uint32_t imageOffset, bool& stop) {
|
||||
Node patch;
|
||||
patch.map["patch-index"].value = decimal(patchTableIndex);
|
||||
patch.map["replacement"].value = "{closure[" + decimal(imageIndexInClosure) + "]+" + hex(imageOffset) + "}";
|
||||
cacheOverrides.array.push_back(patch);
|
||||
});
|
||||
if ( !cacheOverrides.array.empty() )
|
||||
root.map["dyld-cache-overrides"].array = cacheOverrides.array;
|
||||
#endif
|
||||
return root;
|
||||
}
|
||||
|
||||
void printImageAsJSON(const Image* image, const Array<const ImageArray*>& imagesArrays,
|
||||
bool printFixups, bool printRaw, const DyldSharedCache* dyldCache, std::ostream& out)
|
||||
{
|
||||
Node root = buildImageNode(image, imagesArrays, printFixups, false, printRaw, dyldCache, nullptr, {});
|
||||
printJSON(root, 0, out);
|
||||
}
|
||||
|
||||
void printDyldCacheImagesAsJSON(const DyldSharedCache* dyldCache, bool printFixups, bool printRaw, std::ostream& out)
|
||||
{
|
||||
const dyld3::closure::ImageArray* dylibs = dyldCache->cachedDylibsImageArray();
|
||||
STACK_ALLOC_ARRAY(const ImageArray*, imagesArrays, 2);
|
||||
imagesArrays.push_back(dylibs);
|
||||
|
||||
Node root = buildImageArrayNode(dylibs, imagesArrays, printFixups, false, printRaw, dyldCache, nullptr, {});
|
||||
printJSON(root, 0, out);
|
||||
}
|
||||
|
||||
void printClosureAsJSON(const LaunchClosure* cls, const Array<const ImageArray*>& imagesArrays,
|
||||
bool printFixups, bool printRaw, const DyldSharedCache* dyldCache, std::ostream& out)
|
||||
{
|
||||
Node root = buildClosureNode(cls, imagesArrays, printFixups, false, printRaw, dyldCache);
|
||||
printJSON(root, 0, out);
|
||||
}
|
||||
|
||||
void printClosureAsJSON(const DlopenClosure* cls, const Array<const ImageArray*>& imagesArrays,
|
||||
bool printFixups, bool printRaw, const DyldSharedCache* dyldCache, std::ostream& out)
|
||||
{
|
||||
Node root = buildClosureNode(cls, imagesArrays, printFixups, printRaw, false);
|
||||
printJSON(root, 0, out);
|
||||
}
|
||||
|
||||
|
||||
} // namespace closure
|
||||
} // namespace dyld3
|
54
src/dyld/dyld3/ClosurePrinter.h
Normal file
54
src/dyld/dyld3/ClosurePrinter.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ClosurePrinter_h
|
||||
#define ClosurePrinter_h
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "Closure.h"
|
||||
#include "DyldSharedCache.h"
|
||||
|
||||
|
||||
namespace dyld3 {
|
||||
namespace closure {
|
||||
|
||||
|
||||
void printClosureAsJSON( const LaunchClosure* cls, const Array<const ImageArray*>& imagesArrays, bool printFixups=false,
|
||||
bool printRaw = false, const DyldSharedCache* dyldCache=nullptr, std::ostream& out = std::cout);
|
||||
void printClosureAsJSON( const DlopenClosure* cls, const Array<const ImageArray*>& imagesArrays, bool printFixups=false,
|
||||
bool printRaw = false, const DyldSharedCache* dyldCache=nullptr, std::ostream& out = std::cout);
|
||||
void printImageAsJSON( const Image* image, const Array<const ImageArray*>& imagesArrays, bool printFixups=false,
|
||||
bool printRaw = false, const DyldSharedCache* dyldCache=nullptr, std::ostream& out = std::cout);
|
||||
|
||||
void printDyldCacheImagesAsJSON(const DyldSharedCache* dyldCache, bool printFixups=false, bool printRaw = false,
|
||||
std::ostream& out = std::cout);
|
||||
|
||||
|
||||
} // namespace closure
|
||||
} // namespace dyld3
|
||||
|
||||
|
||||
#endif /* ClosurePrinter_h */
|
717
src/dyld/dyld3/ClosureWriter.cpp
Normal file
717
src/dyld/dyld3/ClosureWriter.cpp
Normal file
@ -0,0 +1,717 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <mach/vm_page_size.h>
|
||||
|
||||
#include "ClosureWriter.h"
|
||||
#include "MachOFile.h"
|
||||
|
||||
|
||||
namespace dyld3 {
|
||||
namespace closure {
|
||||
|
||||
|
||||
//////////////////////////// ContainerTypedBytesWriter ////////////////////////////////////////
|
||||
|
||||
|
||||
void ContainerTypedBytesWriter::setContainerType(TypedBytes::Type containerType)
|
||||
{
|
||||
assert(_vmAllocationStart == 0);
|
||||
_vmAllocationSize = 1024 * 1024;
|
||||
vm_address_t allocationAddr;
|
||||
::vm_allocate(mach_task_self(), &allocationAddr, _vmAllocationSize, VM_FLAGS_ANYWHERE);
|
||||
assert(allocationAddr != 0);
|
||||
_vmAllocationStart = (void*)allocationAddr;
|
||||
_containerTypedBytes = (TypedBytes*)_vmAllocationStart;
|
||||
_containerTypedBytes->type = containerType;
|
||||
_containerTypedBytes->payloadLength = 0;
|
||||
_end = (uint8_t*)_vmAllocationStart + sizeof(TypedBytes);
|
||||
}
|
||||
|
||||
void* ContainerTypedBytesWriter::append(TypedBytes::Type t, const void* payload, uint32_t payloadSize)
|
||||
{
|
||||
assert((payloadSize & 0x3) == 0);
|
||||
if ( (uint8_t*)_end + payloadSize >= (uint8_t*)_vmAllocationStart + _vmAllocationSize ) {
|
||||
// if current buffer too small, grow it
|
||||
size_t growth = _vmAllocationSize;
|
||||
if ( growth < payloadSize )
|
||||
growth = _vmAllocationSize*((payloadSize/_vmAllocationSize)+1);
|
||||
vm_address_t newAllocationAddr;
|
||||
size_t newAllocationSize = _vmAllocationSize+growth;
|
||||
::vm_allocate(mach_task_self(), &newAllocationAddr, newAllocationSize, VM_FLAGS_ANYWHERE);
|
||||
assert(newAllocationAddr != 0);
|
||||
size_t currentInUse = (char*)_end - (char*)_vmAllocationStart;
|
||||
memcpy((void*)newAllocationAddr, _vmAllocationStart, currentInUse);
|
||||
::vm_deallocate(mach_task_self(), (vm_address_t)_vmAllocationStart, _vmAllocationSize);
|
||||
_end = (void*)(newAllocationAddr + currentInUse);
|
||||
_vmAllocationStart = (void*)newAllocationAddr;
|
||||
_containerTypedBytes = (TypedBytes*)_vmAllocationStart;
|
||||
_vmAllocationSize = newAllocationSize;
|
||||
}
|
||||
assert( (uint8_t*)_end + payloadSize < (uint8_t*)_vmAllocationStart + _vmAllocationSize);
|
||||
TypedBytes* tb = (TypedBytes*)_end;
|
||||
tb->type = t;
|
||||
tb->payloadLength = payloadSize;
|
||||
if ( payload != nullptr )
|
||||
::memcpy(tb->payload(), payload, payloadSize);
|
||||
_end = (uint8_t*)_end + sizeof(TypedBytes) + payloadSize;
|
||||
assert((_containerTypedBytes->payloadLength + sizeof(TypedBytes) + payloadSize) < (16 * 1024 * 1024));
|
||||
_containerTypedBytes->payloadLength += sizeof(TypedBytes) + payloadSize;
|
||||
return tb->payload();
|
||||
}
|
||||
|
||||
const void* ContainerTypedBytesWriter::finalizeContainer()
|
||||
{
|
||||
// trim vm allocation down to just what is needed
|
||||
uintptr_t bufferStart = (uintptr_t)_vmAllocationStart;
|
||||
uintptr_t used = round_page((uintptr_t)_end - bufferStart);
|
||||
if ( used < _vmAllocationSize ) {
|
||||
uintptr_t deallocStart = bufferStart + used;
|
||||
::vm_deallocate(mach_task_self(), deallocStart, _vmAllocationSize - used);
|
||||
_end = nullptr;
|
||||
_vmAllocationSize = used;
|
||||
}
|
||||
// mark vm region read-only
|
||||
::vm_protect(mach_task_self(), bufferStart, used, false, VM_PROT_READ);
|
||||
return (void*)_vmAllocationStart;
|
||||
}
|
||||
|
||||
const void* ContainerTypedBytesWriter::currentTypedBytes()
|
||||
{
|
||||
return (void*)_vmAllocationStart;
|
||||
}
|
||||
|
||||
void ContainerTypedBytesWriter::deallocate()
|
||||
{
|
||||
::vm_deallocate(mach_task_self(), (long)_vmAllocationStart, _vmAllocationSize);
|
||||
}
|
||||
|
||||
//////////////////////////// ImageWriter ////////////////////////////////////////
|
||||
|
||||
|
||||
const Image* ImageWriter::finalize()
|
||||
{
|
||||
return (Image*)finalizeContainer();
|
||||
}
|
||||
|
||||
const Image* ImageWriter::currentImage()
|
||||
{
|
||||
return (Image*)currentTypedBytes();
|
||||
}
|
||||
|
||||
void ImageWriter::addPath(const char* path)
|
||||
{
|
||||
uint32_t roundedPathLen = ((uint32_t)strlen(path) + 1 + 3) & (-4);
|
||||
Image::PathAndHash* ph = (Image::PathAndHash*)append(TypedBytes::Type::pathWithHash, nullptr, sizeof(Image::PathAndHash)+roundedPathLen);
|
||||
ph->hash = Image::hashFunction(path);
|
||||
strcpy(ph->path, path);
|
||||
}
|
||||
|
||||
Image::Flags& ImageWriter::getFlags()
|
||||
{
|
||||
if ( _flagsOffset == -1 ) {
|
||||
setContainerType(TypedBytes::Type::image);
|
||||
Image::Flags flags;
|
||||
::bzero(&flags, sizeof(flags));
|
||||
uint8_t* p = (uint8_t*)append(TypedBytes::Type::imageFlags, &flags, sizeof(flags));
|
||||
_flagsOffset = (int)(p - (uint8_t*)currentTypedBytes());
|
||||
}
|
||||
return *((Image::Flags*)((uint8_t*)currentTypedBytes() + _flagsOffset));
|
||||
}
|
||||
|
||||
void ImageWriter::setImageNum(ImageNum num)
|
||||
{
|
||||
getFlags().imageNum = num;
|
||||
}
|
||||
|
||||
void ImageWriter::setHasObjC(bool value)
|
||||
{
|
||||
getFlags().hasObjC = value;
|
||||
}
|
||||
|
||||
void ImageWriter::setIs64(bool value)
|
||||
{
|
||||
getFlags().is64 = value;
|
||||
}
|
||||
|
||||
void ImageWriter::setHasPlusLoads(bool value)
|
||||
{
|
||||
getFlags().mayHavePlusLoads = value;
|
||||
}
|
||||
|
||||
void ImageWriter::setIsBundle(bool value)
|
||||
{
|
||||
getFlags().isBundle = value;
|
||||
}
|
||||
|
||||
void ImageWriter::setIsDylib(bool value)
|
||||
{
|
||||
getFlags().isDylib = value;
|
||||
}
|
||||
|
||||
void ImageWriter::setIsExecutable(bool value)
|
||||
{
|
||||
getFlags().isExecutable = value;
|
||||
}
|
||||
|
||||
void ImageWriter::setHasWeakDefs(bool value)
|
||||
{
|
||||
getFlags().hasWeakDefs = value;
|
||||
}
|
||||
|
||||
void ImageWriter::setUses16KPages(bool value)
|
||||
{
|
||||
getFlags().has16KBpages = value;
|
||||
}
|
||||
|
||||
void ImageWriter::setOverridableDylib(bool value)
|
||||
{
|
||||
getFlags().overridableDylib = value;
|
||||
}
|
||||
|
||||
void ImageWriter::setInvalid()
|
||||
{
|
||||
getFlags().isInvalid = true;
|
||||
}
|
||||
|
||||
void ImageWriter::setInDyldCache(bool value)
|
||||
{
|
||||
getFlags().inDyldCache = value;
|
||||
}
|
||||
|
||||
void ImageWriter::setHasPrecomputedObjC(bool value)
|
||||
{
|
||||
getFlags().hasPrecomputedObjC = value;
|
||||
}
|
||||
|
||||
void ImageWriter::setNeverUnload(bool value)
|
||||
{
|
||||
getFlags().neverUnload = value;
|
||||
}
|
||||
|
||||
void ImageWriter::setUUID(const uuid_t uuid)
|
||||
{
|
||||
append(TypedBytes::Type::uuid, uuid, sizeof(uuid_t));
|
||||
}
|
||||
|
||||
void ImageWriter::addCDHash(const uint8_t cdHash[20])
|
||||
{
|
||||
append(TypedBytes::Type::cdHash, cdHash, 20);
|
||||
}
|
||||
|
||||
void ImageWriter::setDependents(const Array<Image::LinkedImage>& deps)
|
||||
{
|
||||
append(TypedBytes::Type::dependents, deps.begin(), (uint32_t)deps.count()*sizeof(Image::LinkedImage));
|
||||
}
|
||||
|
||||
void ImageWriter::setDofOffsets(const Array<uint32_t>& dofSectionOffsets)
|
||||
{
|
||||
append(TypedBytes::Type::dofOffsets, &dofSectionOffsets[0], (uint32_t)dofSectionOffsets.count()*sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void ImageWriter::setInitOffsets(const uint32_t initOffsets[], uint32_t count)
|
||||
{
|
||||
append(TypedBytes::Type::initOffsets, initOffsets, count*sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void ImageWriter::setTermOffsets(const uint32_t termOffsets[], uint32_t count)
|
||||
{
|
||||
getFlags().hasTerminators = true;
|
||||
append(TypedBytes::Type::termOffsets, termOffsets, count*sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void ImageWriter::setInitSectRange(uint32_t sectionOffset, uint32_t sectionSize)
|
||||
{
|
||||
Image::InitializerSectionRange range = { sectionOffset, sectionSize };
|
||||
append(TypedBytes::Type::initsSection, &range, sizeof(Image::InitializerSectionRange));
|
||||
}
|
||||
|
||||
void ImageWriter::setDiskSegments(const Image::DiskSegment segs[], uint32_t count)
|
||||
{
|
||||
append(TypedBytes::Type::diskSegment, segs, count*sizeof(Image::DiskSegment));
|
||||
for (uint32_t i=0; i < count; ++i) {
|
||||
if ( segs[i].permissions == Image::DiskSegment::kReadOnlyDataPermissions )
|
||||
getFlags().hasReadOnlyData = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ImageWriter::setCachedSegments(const Image::DyldCacheSegment segs[], uint32_t count)
|
||||
{
|
||||
append(TypedBytes::Type::cacheSegment, segs, count*sizeof(Image::DyldCacheSegment));
|
||||
}
|
||||
|
||||
void ImageWriter::setCodeSignatureLocation(uint32_t fileOffset, uint32_t size)
|
||||
{
|
||||
Image::CodeSignatureLocation loc;
|
||||
loc.fileOffset = fileOffset;
|
||||
loc.fileSize = size;
|
||||
append(TypedBytes::Type::codeSignLoc, &loc, sizeof(loc));
|
||||
}
|
||||
|
||||
void ImageWriter::setFairPlayEncryptionRange(uint32_t fileOffset, uint32_t size)
|
||||
{
|
||||
Image::FairPlayRange loc;
|
||||
loc.rangeStart = fileOffset;
|
||||
loc.rangeLength = size;
|
||||
append(TypedBytes::Type::fairPlayLoc, &loc, sizeof(loc));
|
||||
}
|
||||
|
||||
void ImageWriter::setMappingInfo(uint64_t sliceOffset, uint64_t vmSize)
|
||||
{
|
||||
const uint32_t pageSize = getFlags().has16KBpages ? 0x4000 : 0x1000;
|
||||
Image::MappingInfo info;
|
||||
info.sliceOffsetIn4K = (uint32_t)(sliceOffset / 0x1000);
|
||||
info.totalVmPages = (uint32_t)(vmSize / pageSize);
|
||||
append(TypedBytes::Type::mappingInfo, &info, sizeof(info));
|
||||
}
|
||||
|
||||
void ImageWriter::setFileInfo(uint64_t inode, uint64_t mTime)
|
||||
{
|
||||
Image::FileInfo info = { inode, mTime };
|
||||
append(TypedBytes::Type::fileInodeAndTime, &info, sizeof(info));
|
||||
}
|
||||
|
||||
void ImageWriter::setRebaseInfo(const Array<Image::RebasePattern>& fixups)
|
||||
{
|
||||
append(TypedBytes::Type::rebaseFixups, fixups.begin(), (uint32_t)fixups.count()*sizeof(Image::RebasePattern));
|
||||
}
|
||||
|
||||
void ImageWriter::setTextRebaseInfo(const Array<Image::TextFixupPattern>& fixups)
|
||||
{
|
||||
append(TypedBytes::Type::textFixups, fixups.begin(), (uint32_t)fixups.count()*sizeof(Image::TextFixupPattern));
|
||||
}
|
||||
|
||||
void ImageWriter::setBindInfo(const Array<Image::BindPattern>& fixups)
|
||||
{
|
||||
append(TypedBytes::Type::bindFixups, fixups.begin(), (uint32_t)fixups.count()*sizeof(Image::BindPattern));
|
||||
}
|
||||
|
||||
void ImageWriter::setChainedFixups(uint64_t runtimeStartsStructOffset, const Array<Image::ResolvedSymbolTarget>& targets)
|
||||
{
|
||||
getFlags().hasChainedFixups = true;
|
||||
append(TypedBytes::Type::chainedStartsOffset, &runtimeStartsStructOffset, sizeof(uint64_t));
|
||||
append(TypedBytes::Type::chainedFixupsTargets, targets.begin(), (uint32_t)targets.count()*sizeof(Image::ResolvedSymbolTarget));
|
||||
}
|
||||
|
||||
void ImageWriter::setObjCFixupInfo(const Image::ResolvedSymbolTarget& objcProtocolClassTarget,
|
||||
uint64_t objcImageInfoVMOffset,
|
||||
const Array<Image::ProtocolISAFixup>& protocolISAFixups,
|
||||
const Array<Image::SelectorReferenceFixup>& selRefFixups,
|
||||
const Array<Image::ClassStableSwiftFixup>& classStableSwiftFixups,
|
||||
const Array<Image::MethodListFixup>& methodListFixups)
|
||||
{
|
||||
// The layout here is:
|
||||
// ResolvedSymbolTarget
|
||||
// uint64_t vmOffset to objc_imageinfo
|
||||
// uint32_t protocol count
|
||||
// uint32_t selector reference count
|
||||
// array of ProtocolISAFixup
|
||||
// array of SelectorReferenceFixup
|
||||
// optional uint32_t stable swift fixup count
|
||||
// optional uint32_t method list fixup count
|
||||
// optional array of ClassStableSwiftFixup
|
||||
// optional array of MethodListFixup
|
||||
|
||||
uint64_t headerSize = sizeof(Image::ResolvedSymbolTarget) + sizeof(uint64_t) + (sizeof(uint32_t) * 4);
|
||||
uint64_t protocolsSize = (sizeof(Image::ProtocolISAFixup) * protocolISAFixups.count());
|
||||
uint64_t selRefsSize = (sizeof(Image::SelectorReferenceFixup) * selRefFixups.count());
|
||||
uint64_t stableSwiftSize = (sizeof(Image::ClassStableSwiftFixup) * classStableSwiftFixups.count());
|
||||
uint64_t methodListSize = (sizeof(Image::MethodListFixup) * methodListFixups.count());
|
||||
|
||||
uint64_t totalSize = headerSize + protocolsSize + selRefsSize + stableSwiftSize + methodListSize;
|
||||
assert( (totalSize & 3) == 0);
|
||||
uint8_t* buffer = (uint8_t*)append(TypedBytes::Type::objcFixups, nullptr, (uint32_t)totalSize);
|
||||
|
||||
// Set the statically sized data
|
||||
uint32_t protocolFixupCount = (uint32_t)protocolISAFixups.count();
|
||||
uint32_t selRefFixupCount = (uint32_t)selRefFixups.count();
|
||||
memcpy(buffer, &objcProtocolClassTarget, sizeof(Image::ResolvedSymbolTarget));
|
||||
buffer += sizeof(Image::ResolvedSymbolTarget);
|
||||
memcpy(buffer, &objcImageInfoVMOffset, sizeof(uint64_t));
|
||||
buffer += sizeof(uint64_t);
|
||||
memcpy(buffer, &protocolFixupCount, sizeof(uint32_t));
|
||||
buffer += sizeof(uint32_t);
|
||||
memcpy(buffer, &selRefFixupCount, sizeof(uint32_t));
|
||||
buffer += sizeof(uint32_t);
|
||||
|
||||
// Set the protocol fixups
|
||||
if ( protocolFixupCount != 0 ) {
|
||||
memcpy(buffer, protocolISAFixups.begin(), (size_t)protocolsSize);
|
||||
buffer += protocolsSize;
|
||||
}
|
||||
|
||||
// Set the selector reference fixups
|
||||
if ( selRefFixupCount != 0 ) {
|
||||
memcpy(buffer, selRefFixups.begin(), (size_t)selRefsSize);
|
||||
buffer += selRefsSize;
|
||||
}
|
||||
|
||||
// New closures get additional fixups. These are ignored by old dyld's
|
||||
uint32_t stableSwiftFixupCount = (uint32_t)classStableSwiftFixups.count();
|
||||
uint32_t methodListFixupCount = (uint32_t)methodListFixups.count();
|
||||
memcpy(buffer, &stableSwiftFixupCount, sizeof(uint32_t));
|
||||
buffer += sizeof(uint32_t);
|
||||
memcpy(buffer, &methodListFixupCount, sizeof(uint32_t));
|
||||
buffer += sizeof(uint32_t);
|
||||
|
||||
// Set the stable swift fixups
|
||||
if ( stableSwiftFixupCount != 0 ) {
|
||||
memcpy(buffer, classStableSwiftFixups.begin(), (size_t)stableSwiftSize);
|
||||
buffer += stableSwiftSize;
|
||||
}
|
||||
|
||||
// Set the method list fixups
|
||||
if ( methodListFixupCount != 0 ) {
|
||||
memcpy(buffer, methodListFixups.begin(), (size_t)methodListSize);
|
||||
buffer += methodListSize;
|
||||
}
|
||||
}
|
||||
|
||||
void ImageWriter::setAsOverrideOf(ImageNum imageNum)
|
||||
{
|
||||
uint32_t temp = imageNum;
|
||||
append(TypedBytes::Type::imageOverride, &temp, sizeof(temp));
|
||||
}
|
||||
|
||||
void ImageWriter::setInitsOrder(const ImageNum images[], uint32_t count)
|
||||
{
|
||||
append(TypedBytes::Type::initBefores, images, count*sizeof(ImageNum));
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////// ImageArrayWriter ////////////////////////////////////////
|
||||
|
||||
|
||||
ImageArrayWriter::ImageArrayWriter(ImageNum startImageNum, unsigned count, bool hasRoots) : _index(0)
|
||||
{
|
||||
setContainerType(TypedBytes::Type::imageArray);
|
||||
_end = (void*)((uint8_t*)_end + sizeof(ImageArray) - sizeof(TypedBytes) + sizeof(uint32_t)*count);
|
||||
_containerTypedBytes->payloadLength = sizeof(ImageArray) - sizeof(TypedBytes) + sizeof(uint32_t)*count;
|
||||
ImageArray* ia = (ImageArray*)_containerTypedBytes;
|
||||
ia->firstImageNum = startImageNum;
|
||||
ia->count = count;
|
||||
ia->hasRoots = hasRoots;
|
||||
}
|
||||
|
||||
void ImageArrayWriter::appendImage(const Image* image)
|
||||
{
|
||||
ImageArray* ia = (ImageArray*)_containerTypedBytes;
|
||||
ia->offsets[_index++] = _containerTypedBytes->payloadLength;
|
||||
append(TypedBytes::Type::image, image->payload(), image->payloadLength);
|
||||
}
|
||||
|
||||
const ImageArray* ImageArrayWriter::finalize()
|
||||
{
|
||||
return (ImageArray*)finalizeContainer();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////// ClosureWriter ////////////////////////////////////////
|
||||
|
||||
void ClosureWriter::setTopImageNum(ImageNum imageNum)
|
||||
{
|
||||
append(TypedBytes::Type::topImage, &imageNum, sizeof(ImageNum));
|
||||
}
|
||||
|
||||
void ClosureWriter::addCachePatches(const Array<Closure::PatchEntry>& patches)
|
||||
{
|
||||
append(TypedBytes::Type::cacheOverrides, patches.begin(), (uint32_t)patches.count()*sizeof(Closure::PatchEntry));
|
||||
}
|
||||
|
||||
void ClosureWriter::applyInterposing(const LaunchClosure* launchClosure)
|
||||
{
|
||||
const Closure* currentClosure = (Closure*)currentTypedBytes();
|
||||
const ImageArray* images = currentClosure->images();
|
||||
launchClosure->forEachInterposingTuple(^(const InterposingTuple& tuple, bool&) {
|
||||
images->forEachImage(^(const dyld3::closure::Image* image, bool&) {
|
||||
for (const Image::BindPattern& bindPat : image->bindFixups()) {
|
||||
if ( (bindPat.target == tuple.stockImplementation) && (tuple.newImplementation.image.imageNum != image->imageNum()) ) {
|
||||
Image::BindPattern* writePat = const_cast<Image::BindPattern*>(&bindPat);
|
||||
writePat->target = tuple.newImplementation;
|
||||
}
|
||||
}
|
||||
|
||||
// Chained fixups may also be interposed. We can't change elements in the chain, but we can change
|
||||
// the target list.
|
||||
for (const Image::ResolvedSymbolTarget& symbolTarget : image->chainedTargets()) {
|
||||
if ( (symbolTarget == tuple.stockImplementation) && (tuple.newImplementation.image.imageNum != image->imageNum()) ) {
|
||||
Image::ResolvedSymbolTarget* writeTarget = const_cast<Image::ResolvedSymbolTarget*>(&symbolTarget);
|
||||
*writeTarget = tuple.newImplementation;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void ClosureWriter::addWarning(Closure::Warning::Type warningType, const char* warning)
|
||||
{
|
||||
uint32_t roundedMessageLen = ((uint32_t)strlen(warning) + 1 + 3) & (-4);
|
||||
Closure::Warning* ph = (Closure::Warning*)append(TypedBytes::Type::warning, nullptr, sizeof(Closure::Warning)+roundedMessageLen);
|
||||
ph->type = warningType;
|
||||
strcpy(ph->message, warning);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////// LaunchClosureWriter ////////////////////////////////////////
|
||||
|
||||
LaunchClosureWriter::LaunchClosureWriter(const ImageArray* images)
|
||||
{
|
||||
setContainerType(TypedBytes::Type::launchClosure);
|
||||
append(TypedBytes::Type::imageArray, images->payload(), images->payloadLength);
|
||||
}
|
||||
|
||||
const LaunchClosure* LaunchClosureWriter::finalize()
|
||||
{
|
||||
return (LaunchClosure*)finalizeContainer();
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setLibSystemImageNum(ImageNum imageNum)
|
||||
{
|
||||
append(TypedBytes::Type::libSystemNum, &imageNum, sizeof(ImageNum));
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setLibDyldEntry(Image::ResolvedSymbolTarget entry)
|
||||
{
|
||||
append(TypedBytes::Type::libDyldEntry, &entry, sizeof(entry));
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setMainEntry(Image::ResolvedSymbolTarget main)
|
||||
{
|
||||
append(TypedBytes::Type::mainEntry, &main, sizeof(main));
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setStartEntry(Image::ResolvedSymbolTarget start)
|
||||
{
|
||||
append(TypedBytes::Type::startEntry, &start, sizeof(start));
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setUsedFallbackPaths(bool value)
|
||||
{
|
||||
getFlags().usedFallbackPaths = value;
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setUsedAtPaths(bool value)
|
||||
{
|
||||
getFlags().usedAtPaths = value;
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setHasInsertedLibraries(bool value)
|
||||
{
|
||||
getFlags().hasInsertedLibraries = value;
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setInitImageCount(uint32_t count)
|
||||
{
|
||||
getFlags().initImageCount = count;
|
||||
}
|
||||
|
||||
LaunchClosure::Flags& LaunchClosureWriter::getFlags()
|
||||
{
|
||||
if ( _flagsOffset == -1 ) {
|
||||
LaunchClosure::Flags flags;
|
||||
::bzero(&flags, sizeof(flags));
|
||||
uint8_t* p = (uint8_t*)append(TypedBytes::Type::closureFlags, &flags, sizeof(flags));
|
||||
_flagsOffset = (int)(p - (uint8_t*)currentTypedBytes());
|
||||
}
|
||||
return *((LaunchClosure::Flags*)((uint8_t*)currentTypedBytes() + _flagsOffset));
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setMustBeMissingFiles(const Array<const char*>& paths)
|
||||
{
|
||||
uint32_t totalSize = 0;
|
||||
for (const char* s : paths)
|
||||
totalSize += (strlen(s) +1);
|
||||
totalSize = (totalSize + 3) & (-4); // align
|
||||
|
||||
char* buffer = (char*)append(TypedBytes::Type::missingFiles, nullptr, totalSize);
|
||||
char* t = buffer;
|
||||
for (const char* path : paths) {
|
||||
for (const char* s=path; *s != '\0'; ++s)
|
||||
*t++ = *s;
|
||||
*t++ = '\0';
|
||||
}
|
||||
while (t < &buffer[totalSize])
|
||||
*t++ = '\0';
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setMustExistFiles(const Array<LaunchClosure::SkippedFile>& files)
|
||||
{
|
||||
// Start the structure with a count
|
||||
uint32_t totalSize = sizeof(uint64_t);
|
||||
|
||||
// Then make space for the array of mod times and inode numbers
|
||||
totalSize += files.count() * sizeof(uint64_t) * 2;
|
||||
|
||||
// Then the array of paths on the end
|
||||
for (const LaunchClosure::SkippedFile& file : files)
|
||||
totalSize += (strlen(file.path) + 1);
|
||||
totalSize = (totalSize + 3) & (-4); // align
|
||||
|
||||
char* buffer = (char*)append(TypedBytes::Type::existingFiles, nullptr, totalSize);
|
||||
|
||||
// Set the size
|
||||
uint64_t* bufferPtr = (uint64_t*)buffer;
|
||||
*bufferPtr++ = (uint64_t)files.count();
|
||||
|
||||
// And the array of mod times and inode numbers
|
||||
for (const LaunchClosure::SkippedFile& file : files) {
|
||||
*bufferPtr++ = file.inode;
|
||||
*bufferPtr++ = file.mtime;
|
||||
}
|
||||
|
||||
char* t = (char*)bufferPtr;
|
||||
for (const LaunchClosure::SkippedFile& file : files) {
|
||||
for (const char* s=file.path; *s != '\0'; ++s)
|
||||
*t++ = *s;
|
||||
*t++ = '\0';
|
||||
}
|
||||
while (t < &buffer[totalSize])
|
||||
*t++ = '\0';
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::addEnvVar(const char* envVar)
|
||||
{
|
||||
unsigned len = (unsigned)strlen(envVar);
|
||||
char temp[len+8];
|
||||
strcpy(temp, envVar);
|
||||
unsigned paddedSize = len+1;
|
||||
while ( (paddedSize % 4) != 0 )
|
||||
temp[paddedSize++] = '\0';
|
||||
append(TypedBytes::Type::envVar, temp, paddedSize);
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::addInterposingTuples(const Array<InterposingTuple>& tuples)
|
||||
{
|
||||
append(TypedBytes::Type::interposeTuples, tuples.begin(), (uint32_t)tuples.count()*sizeof(InterposingTuple));
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setDyldCacheUUID(const uuid_t uuid)
|
||||
{
|
||||
append(TypedBytes::Type::dyldCacheUUID, uuid, sizeof(uuid_t));
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setBootUUID(const char* uuid)
|
||||
{
|
||||
unsigned len = (unsigned)strlen(uuid);
|
||||
char temp[len+8];
|
||||
strcpy(temp, uuid);
|
||||
unsigned paddedSize = len+1;
|
||||
while ( (paddedSize % 4) != 0 )
|
||||
temp[paddedSize++] = '\0';
|
||||
append(TypedBytes::Type::bootUUID, temp, paddedSize);
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setObjCSelectorInfo(const Array<uint8_t>& hashTable, const Array<Image::ObjCSelectorImage>& hashTableImages) {
|
||||
uint32_t count = (uint32_t)hashTableImages.count();
|
||||
uint32_t totalSize = (uint32_t)(sizeof(count) + (sizeof(Image::ObjCSelectorImage) * count) + hashTable.count());
|
||||
totalSize = (totalSize + 3) & (-4); // align
|
||||
uint8_t* buffer = (uint8_t*)append(TypedBytes::Type::selectorTable, nullptr, totalSize);
|
||||
|
||||
// Write out out the image count
|
||||
memcpy(buffer, &count, sizeof(count));
|
||||
buffer += sizeof(count);
|
||||
|
||||
// Write out out the image nums
|
||||
memcpy(buffer, hashTableImages.begin(), sizeof(Image::ObjCSelectorImage) * count);
|
||||
buffer += sizeof(Image::ObjCSelectorImage) * count;
|
||||
|
||||
// Write out out the image count
|
||||
memcpy(buffer, hashTable.begin(), hashTable.count());
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setObjCClassAndProtocolInfo(const Array<uint8_t>& classHashTable, const Array<uint8_t>& protocolHashTable,
|
||||
const Array<Image::ObjCClassImage>& hashTableImages) {
|
||||
// The layout here is:
|
||||
// uint32_t offset to class table (note this is 0 if there are no classes)
|
||||
// uint32_t offset to protocol table (note this is 0 if there are no protocols)
|
||||
// uint32_t num images
|
||||
// ObjCClassImage[num images]
|
||||
// class hash table
|
||||
// [ padding to 4-byte alignment if needed
|
||||
// protocol hash table
|
||||
// [ padding to 4-byte alignment if needed
|
||||
|
||||
uint32_t numImages = (uint32_t)hashTableImages.count();
|
||||
|
||||
uint32_t headerSize = sizeof(uint32_t) * 3;
|
||||
uint32_t imagesSize = (sizeof(Image::ObjCClassImage) * numImages);
|
||||
uint32_t classTableSize = ((uint32_t)classHashTable.count() + 3) & (-4); // pad to 4-byte multiple
|
||||
uint32_t protocolTableSize = ((uint32_t)protocolHashTable.count() + 3) & (-4); // pad to 4-byte multiple
|
||||
uint32_t offsetToClassTable = (classTableSize == 0) ? 0 : (headerSize + imagesSize);
|
||||
uint32_t offsetToProtocolTable = (protocolTableSize == 0) ? 0 : (headerSize + imagesSize + classTableSize);
|
||||
|
||||
uint32_t totalSize = headerSize + imagesSize + classTableSize + protocolTableSize;
|
||||
assert( (totalSize & 3) == 0);
|
||||
uint8_t* buffer = (uint8_t*)append(TypedBytes::Type::classTable, nullptr, totalSize);
|
||||
|
||||
// Write out out the header
|
||||
memcpy(buffer + 0, &offsetToClassTable, sizeof(uint32_t));
|
||||
memcpy(buffer + 4, &offsetToProtocolTable, sizeof(uint32_t));
|
||||
memcpy(buffer + 8, &numImages, sizeof(uint32_t));
|
||||
|
||||
// Write out out the image nums
|
||||
memcpy(buffer + headerSize, hashTableImages.begin(), imagesSize);
|
||||
|
||||
// Write out out the class hash table
|
||||
if ( offsetToClassTable != 0 )
|
||||
memcpy(buffer + offsetToClassTable, classHashTable.begin(), classHashTable.count());
|
||||
|
||||
// Write out out the protocol hash table
|
||||
if ( offsetToProtocolTable != 0 )
|
||||
memcpy(buffer + offsetToProtocolTable, protocolHashTable.begin(), protocolHashTable.count());
|
||||
}
|
||||
|
||||
void LaunchClosureWriter::setObjCDuplicateClassesInfo(const Array<uint8_t>& hashTable) {
|
||||
uint32_t totalSize = (uint32_t)hashTable.count();
|
||||
totalSize = (totalSize + 3) & (-4); // align
|
||||
uint8_t* buffer = (uint8_t*)append(TypedBytes::Type::duplicateClassesTable, nullptr, totalSize);
|
||||
|
||||
// Write out out the hash table
|
||||
memcpy(buffer, hashTable.begin(), hashTable.count());
|
||||
}
|
||||
|
||||
//////////////////////////// DlopenClosureWriter ////////////////////////////////////////
|
||||
|
||||
DlopenClosureWriter::DlopenClosureWriter(const ImageArray* images)
|
||||
{
|
||||
setContainerType(TypedBytes::Type::dlopenClosure);
|
||||
append(TypedBytes::Type::imageArray, images->payload(), images->payloadLength);
|
||||
}
|
||||
|
||||
const DlopenClosure* DlopenClosureWriter::finalize()
|
||||
{
|
||||
return (DlopenClosure*)finalizeContainer();
|
||||
}
|
||||
|
||||
|
||||
} // namespace closure
|
||||
} // namespace dyld3
|
||||
|
||||
|
||||
|
191
src/dyld/dyld3/ClosureWriter.h
Normal file
191
src/dyld/dyld3/ClosureWriter.h
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ClosureWriter_h
|
||||
#define ClosureWriter_h
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "Closure.h"
|
||||
|
||||
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
namespace closure {
|
||||
|
||||
|
||||
class VIS_HIDDEN ContainerTypedBytesWriter
|
||||
{
|
||||
public:
|
||||
void deallocate();
|
||||
|
||||
protected:
|
||||
void setContainerType(TypedBytes::Type containerType);
|
||||
void* append(TypedBytes::Type t, const void* payload, uint32_t payloadSize);
|
||||
|
||||
const void* currentTypedBytes();
|
||||
const void* finalizeContainer();
|
||||
|
||||
void* _vmAllocationStart = nullptr;
|
||||
size_t _vmAllocationSize = 0;
|
||||
TypedBytes* _containerTypedBytes = nullptr;
|
||||
void* _end = nullptr;
|
||||
};
|
||||
|
||||
|
||||
class VIS_HIDDEN ImageWriter : public ContainerTypedBytesWriter
|
||||
{
|
||||
public:
|
||||
|
||||
void setImageNum(ImageNum num);
|
||||
void addPath(const char* path); // first is canonical, others are aliases
|
||||
void setInvalid();
|
||||
void setInDyldCache(bool);
|
||||
void setHasPrecomputedObjC(bool);
|
||||
void setIs64(bool);
|
||||
void setHasObjC(bool);
|
||||
void setHasPlusLoads(bool);
|
||||
void setIsBundle(bool);
|
||||
void setIsDylib(bool);
|
||||
void setIsExecutable(bool);
|
||||
void setIsRestricted(bool);
|
||||
void setHasWeakDefs(bool);
|
||||
void setUses16KPages(bool);
|
||||
void setOverridableDylib(bool);
|
||||
void setNeverUnload(bool);
|
||||
void setHasTerminators(bool);
|
||||
void setUUID(const uuid_t uuid);
|
||||
void addCDHash(const uint8_t cdHash[20]);
|
||||
void setDependents(const Array<Image::LinkedImage>& deps);
|
||||
void setDofOffsets(const Array<uint32_t>& dofSectionOffsets);
|
||||
void setInitOffsets(const uint32_t initOffsets[], uint32_t count);
|
||||
void setInitSectRange(uint32_t sectionOffset, uint32_t sectionSize);
|
||||
void setTermOffsets(const uint32_t termOffsets[], uint32_t count);
|
||||
void setDiskSegments(const Image::DiskSegment segs[], uint32_t count);
|
||||
void setCachedSegments(const Image::DyldCacheSegment segs[], uint32_t count);
|
||||
void setCodeSignatureLocation(uint32_t fileOffset, uint32_t size);
|
||||
void setFairPlayEncryptionRange(uint32_t fileOffset, uint32_t size);
|
||||
void setMappingInfo(uint64_t sliceOffset, uint64_t vmSize);
|
||||
void setFileInfo(uint64_t inode, uint64_t modTime);
|
||||
void setRebaseInfo(const Array<Image::RebasePattern>&);
|
||||
void setTextRebaseInfo(const Array<Image::TextFixupPattern>&);
|
||||
void setBindInfo(const Array<Image::BindPattern>&);
|
||||
void setObjCFixupInfo(const Image::ResolvedSymbolTarget& objcProtocolClassTarget,
|
||||
uint64_t objcImageInfoVMOffset,
|
||||
const Array<Image::ProtocolISAFixup>& protocolISAFixups,
|
||||
const Array<Image::SelectorReferenceFixup>& selRefFixups,
|
||||
const Array<Image::ClassStableSwiftFixup>& classStableSwiftFixups,
|
||||
const Array<Image::MethodListFixup>& methodListFixups);
|
||||
void setAsOverrideOf(ImageNum);
|
||||
void setInitsOrder(const ImageNum images[], uint32_t count);
|
||||
void setChainedFixups(uint64_t runtimeStartsStructOffset, const Array<Image::ResolvedSymbolTarget>& targets);
|
||||
|
||||
const Image* currentImage();
|
||||
|
||||
const Image* finalize();
|
||||
|
||||
private:
|
||||
Image::Flags& getFlags();
|
||||
|
||||
int _flagsOffset = -1;
|
||||
};
|
||||
|
||||
|
||||
class VIS_HIDDEN ImageArrayWriter : public ContainerTypedBytesWriter
|
||||
{
|
||||
public:
|
||||
ImageArrayWriter(ImageNum startImageNum, unsigned count, bool hasRoots);
|
||||
|
||||
void appendImage(const Image*);
|
||||
const ImageArray* finalize();
|
||||
private:
|
||||
unsigned _index;
|
||||
};
|
||||
|
||||
class VIS_HIDDEN ClosureWriter : public ContainerTypedBytesWriter
|
||||
{
|
||||
public:
|
||||
void setTopImageNum(ImageNum imageNum);
|
||||
void addCachePatches(const Array<Closure::PatchEntry>&);
|
||||
void applyInterposing(const LaunchClosure* launchClosure);
|
||||
void addWarning(Closure::Warning::Type type, const char* warning);
|
||||
};
|
||||
|
||||
class VIS_HIDDEN LaunchClosureWriter : public ClosureWriter
|
||||
{
|
||||
friend class ClosureBuilder;
|
||||
public:
|
||||
LaunchClosureWriter(const ImageArray* images);
|
||||
|
||||
const LaunchClosure* finalize();
|
||||
void setLibSystemImageNum(ImageNum imageNum);
|
||||
void setInitImageCount(uint32_t count);
|
||||
void setLibDyldEntry(Image::ResolvedSymbolTarget dyldEntry);
|
||||
void setMainEntry(Image::ResolvedSymbolTarget main);
|
||||
void setStartEntry(Image::ResolvedSymbolTarget start);
|
||||
void setUsedFallbackPaths(bool);
|
||||
void setUsedAtPaths(bool);
|
||||
void setHasInsertedLibraries(bool);
|
||||
void setMustBeMissingFiles(const Array<const char*>& paths);
|
||||
void setMustExistFiles(const Array<LaunchClosure::SkippedFile>& files);
|
||||
void addInterposingTuples(const Array<InterposingTuple>& tuples);
|
||||
void setDyldCacheUUID(const uuid_t);
|
||||
void setBootUUID(const char* uuid);
|
||||
void addEnvVar(const char* envVar);
|
||||
void setObjCSelectorInfo(const Array<uint8_t>& hashTable, const Array<Image::ObjCSelectorImage>& hashTableImages);
|
||||
void setObjCClassAndProtocolInfo(const Array<uint8_t>& classHashTable, const Array<uint8_t>& protocolHashTable,
|
||||
const Array<Image::ObjCClassImage>& hashTableImages);
|
||||
void setObjCDuplicateClassesInfo(const Array<uint8_t>& hashTable);
|
||||
|
||||
private:
|
||||
LaunchClosure::Flags& getFlags();
|
||||
|
||||
int _flagsOffset = -1;
|
||||
};
|
||||
|
||||
|
||||
class VIS_HIDDEN DlopenClosureWriter : public ClosureWriter
|
||||
{
|
||||
public:
|
||||
DlopenClosureWriter(const ImageArray* images);
|
||||
|
||||
const DlopenClosure* finalize();
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace closure
|
||||
} // namespace dyld3
|
||||
|
||||
|
||||
#endif // ClosureWriter_h
|
||||
|
@ -42,11 +42,13 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
CS_PAGE_SIZE = 4096,
|
||||
CS_PAGE_SIZE_4K = 4096,
|
||||
CS_PAGE_SIZE_16K = 16384,
|
||||
|
||||
CS_HASHTYPE_SHA1 = 1,
|
||||
CS_HASHTYPE_SHA256 = 2,
|
||||
CS_HASHTYPE_SHA256_TRUNCATED = 3,
|
||||
CS_HASHTYPE_SHA384 = 4,
|
||||
|
||||
CS_HASH_SIZE_SHA1 = 20,
|
||||
CS_HASH_SIZE_SHA256 = 32,
|
||||
@ -58,12 +60,18 @@ enum {
|
||||
CSSLOT_RESOURCEDIR = 3,
|
||||
CSSLOT_APPLICATION = 4,
|
||||
CSSLOT_ENTITLEMENTS = 5,
|
||||
CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000,
|
||||
CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5,
|
||||
CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT =
|
||||
CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX,
|
||||
CSSLOT_CMS_SIGNATURE = 0x10000,
|
||||
|
||||
kSecCodeSignatureAdhoc = 2
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
CS_REQUIRE_LV = 0x0002000 // require library validation
|
||||
};
|
||||
|
||||
//
|
||||
// Structure of a SuperBlob
|
||||
@ -99,9 +107,29 @@ struct CS_CodeDirectory {
|
||||
uint8_t platform; // platform identifier; zero if not platform binary
|
||||
uint8_t pageSize; // log2(page size in bytes); 0 => infinite
|
||||
uint32_t spare2; // unused (must be zero)
|
||||
// Version 0x20100 or later
|
||||
uint32_t scatterOffset; // offset of optional scatter vector
|
||||
// followed by dynamic content as located by offset fields above
|
||||
|
||||
char end_earliest[0];
|
||||
|
||||
/* Version 0x20100 */
|
||||
uint32_t scatterOffset; /* offset of optional scatter vector */
|
||||
char end_withScatter[0];
|
||||
|
||||
/* Version 0x20200 */
|
||||
uint32_t teamOffset; /* offset of optional team identifier */
|
||||
char end_withTeam[0];
|
||||
|
||||
/* Version 0x20300 */
|
||||
uint32_t spare3; /* unused (must be zero) */
|
||||
uint64_t codeLimit64; /* limit to main image signature range, 64 bits */
|
||||
char end_withCodeLimit64[0];
|
||||
|
||||
/* Version 0x20400 */
|
||||
uint64_t execSegBase; /* offset of executable segment */
|
||||
uint64_t execSegLimit; /* limit of executable segment */
|
||||
uint64_t execSegFlags; /* exec segment flags */
|
||||
char end_withExecSeg[0];
|
||||
|
||||
/* followed by dynamic content as located by offset fields above */
|
||||
};
|
||||
|
||||
struct CS_Blob {
|
217
src/dyld/dyld3/Diagnostics.cpp
Normal file
217
src/dyld/dyld3/Diagnostics.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <_simple.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <dirent.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/machine.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/nlist.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <pthread.h>
|
||||
#include <libc_private.h>
|
||||
|
||||
#include "Diagnostics.h"
|
||||
|
||||
#if BUILDING_CACHE_BUILDER
|
||||
#include <dispatch/dispatch.h>
|
||||
dispatch_queue_t sWarningQueue = dispatch_queue_create("com.apple.dyld.cache-builder.warnings", NULL);
|
||||
#endif
|
||||
|
||||
Diagnostics::Diagnostics(bool verbose)
|
||||
#if BUILDING_CACHE_BUILDER
|
||||
: _verbose(verbose)
|
||||
, _prefix("")
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
#if BUILDING_CACHE_BUILDER
|
||||
Diagnostics::Diagnostics(const std::string& prefix, bool verbose)
|
||||
: _verbose(verbose)
|
||||
, _prefix(prefix)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
Diagnostics::~Diagnostics()
|
||||
{
|
||||
clearError();
|
||||
}
|
||||
|
||||
void Diagnostics::error(const char* format, ...)
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
error(format, list);
|
||||
va_end(list);
|
||||
}
|
||||
|
||||
void Diagnostics::error(const char* format, va_list list)
|
||||
{
|
||||
//FIXME: this should be assertNoError(), but we currently overwrite some errors
|
||||
//assertNoError();
|
||||
_buffer = _simple_salloc();
|
||||
_simple_vsprintf(_buffer, format, list);
|
||||
|
||||
#if BUILDING_CACHE_BUILDER
|
||||
if ( !_verbose )
|
||||
return;
|
||||
|
||||
if (_prefix.empty()) {
|
||||
fprintf(stderr, "%s", _simple_string(_buffer));
|
||||
} else {
|
||||
fprintf(stderr, "[%s] %s", _prefix.c_str(), _simple_string(_buffer));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Diagnostics::hasError() const
|
||||
{
|
||||
return _buffer != nullptr;
|
||||
}
|
||||
|
||||
bool Diagnostics::noError() const
|
||||
{
|
||||
return _buffer == nullptr;
|
||||
}
|
||||
|
||||
void Diagnostics::clearError()
|
||||
{
|
||||
if ( _buffer )
|
||||
_simple_sfree(_buffer);
|
||||
_buffer = nullptr;
|
||||
}
|
||||
|
||||
void Diagnostics::assertNoError() const
|
||||
{
|
||||
if ( _buffer != nullptr )
|
||||
abort_report_np("%s", _simple_string(_buffer));
|
||||
}
|
||||
|
||||
#if !BUILDING_CACHE_BUILDER
|
||||
const char* Diagnostics::errorMessage() const
|
||||
{
|
||||
return _simple_string(_buffer);
|
||||
}
|
||||
|
||||
#else
|
||||
void Diagnostics::warning(const char* format, ...)
|
||||
{
|
||||
_SIMPLE_STRING tmp = _simple_salloc();
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
_simple_vsprintf(tmp, format, list);
|
||||
va_end(list);
|
||||
#if BUILDING_CACHE_BUILDER
|
||||
dispatch_sync(sWarningQueue, ^{
|
||||
_warnings.insert(_simple_string(tmp));
|
||||
});
|
||||
#else
|
||||
_warnings.insert(_simple_string(tmp));
|
||||
#endif
|
||||
_simple_sfree(tmp);
|
||||
}
|
||||
|
||||
void Diagnostics::verbose(const char* format, ...)
|
||||
{
|
||||
if ( !_verbose )
|
||||
return;
|
||||
|
||||
char* output_string;
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
vasprintf(&output_string, format, list);
|
||||
va_end(list);
|
||||
|
||||
if (_prefix.empty()) {
|
||||
fprintf(stderr, "%s", output_string);
|
||||
} else {
|
||||
fprintf(stderr, "[%s] %s", _prefix.c_str(), output_string);
|
||||
}
|
||||
free(output_string);
|
||||
}
|
||||
|
||||
const std::string Diagnostics::prefix() const
|
||||
{
|
||||
return _prefix;
|
||||
}
|
||||
|
||||
void Diagnostics::copy(const Diagnostics& other)
|
||||
{
|
||||
if ( other.hasError() )
|
||||
error("%s", other.errorMessage().c_str());
|
||||
for (const std::string& warn : other.warnings())
|
||||
warning("%s", warn.c_str());
|
||||
}
|
||||
|
||||
std::string Diagnostics::errorMessage() const
|
||||
{
|
||||
if ( _buffer != nullptr )
|
||||
return _simple_string(_buffer);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
const std::set<std::string> Diagnostics::warnings() const
|
||||
{
|
||||
#if BUILDING_CACHE_BUILDER
|
||||
__block std::set<std::string> retval;
|
||||
dispatch_sync(sWarningQueue, ^{
|
||||
retval = _warnings;
|
||||
});
|
||||
return retval;
|
||||
#else
|
||||
return _warnings;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Diagnostics::clearWarnings()
|
||||
{
|
||||
#if BUILDING_CACHE_BUILDER
|
||||
dispatch_sync(sWarningQueue, ^{
|
||||
_warnings.clear();
|
||||
});
|
||||
#else
|
||||
_warnings.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
82
src/dyld/dyld3/Diagnostics.h
Normal file
82
src/dyld/dyld3/Diagnostics.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef Diagnostics_h
|
||||
#define Diagnostics_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if BUILDING_CACHE_BUILDER
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <dispatch/dispatch.h>
|
||||
#endif
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
|
||||
class VIS_HIDDEN Diagnostics
|
||||
{
|
||||
public:
|
||||
Diagnostics(bool verbose=false);
|
||||
~Diagnostics();
|
||||
|
||||
void error(const char* format, ...) __attribute__((format(printf, 2, 3)));
|
||||
void error(const char* format, va_list list);
|
||||
#if BUILDING_CACHE_BUILDER
|
||||
Diagnostics(const std::string& prefix, bool verbose=false);
|
||||
|
||||
void warning(const char* format, ...) __attribute__((format(printf, 2, 3)));
|
||||
void verbose(const char* format, ...) __attribute__((format(printf, 2, 3)));
|
||||
void copy(const Diagnostics&);
|
||||
#endif
|
||||
|
||||
bool hasError() const;
|
||||
bool noError() const;
|
||||
void clearError();
|
||||
void assertNoError() const;
|
||||
|
||||
#if !BUILDING_CACHE_BUILDER
|
||||
const char* errorMessage() const;
|
||||
#else
|
||||
const std::string prefix() const;
|
||||
std::string errorMessage() const;
|
||||
const std::set<std::string> warnings() const;
|
||||
void clearWarnings();
|
||||
#endif
|
||||
|
||||
private:
|
||||
void* _buffer = nullptr;
|
||||
#if BUILDING_CACHE_BUILDER
|
||||
std::string _prefix;
|
||||
std::set<std::string> _warnings;
|
||||
bool _verbose = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // Diagnostics_h
|
50
src/dyld/dyld3/JSON.h
Normal file
50
src/dyld/dyld3/JSON.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef __JSON_H__
|
||||
#define __JSON_H__
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace dyld3 {
|
||||
namespace json {
|
||||
|
||||
struct Node
|
||||
{
|
||||
std::string value;
|
||||
std::map<std::string, Node> map;
|
||||
std::vector<Node> array;
|
||||
};
|
||||
|
||||
|
||||
} // namespace json
|
||||
} // namespace dyld3
|
||||
|
||||
|
||||
#endif // __JSON_H__
|
57
src/dyld/dyld3/JSONReader.h
Normal file
57
src/dyld/dyld3/JSONReader.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef __JSON_READER_H__
|
||||
#define __JSON_READER_H__
|
||||
|
||||
#include "JSON.h"
|
||||
|
||||
class Diagnostics;
|
||||
|
||||
namespace dyld3 {
|
||||
namespace json {
|
||||
|
||||
Node readJSON(Diagnostics& diags, const char* filePath);
|
||||
|
||||
// Given a map node, returns the node representing the given value.
|
||||
// If it is missing, returns a sentinel node and sets an error on the diagnostic
|
||||
const Node& getRequiredValue(Diagnostics& diags, const Node& node, const char* key);
|
||||
|
||||
// Given a map node, returns the node representing the given value.
|
||||
// If it is missing, return nullptr.
|
||||
const Node* getOptionalValue(Diagnostics& diags, const Node& node, const char* key);
|
||||
|
||||
// Parses an int from the given node, or throws an error if its not an integer payload
|
||||
uint64_t parseRequiredInt(Diagnostics& diags, const Node& node);
|
||||
|
||||
// Parses a string from the given node, or throws an error if its not a string payload
|
||||
const std::string& parseRequiredString(Diagnostics& diags, const Node& node);
|
||||
|
||||
|
||||
} // namespace json
|
||||
} // namespace dyld3
|
||||
|
||||
|
||||
#endif // __JSON_READER_H__
|
197
src/dyld/dyld3/JSONReader.mm
Normal file
197
src/dyld/dyld3/JSONReader.mm
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include "JSONReader.h"
|
||||
#include "Diagnostics.h"
|
||||
|
||||
namespace dyld3 {
|
||||
namespace json {
|
||||
|
||||
static Node gSentinelNode;
|
||||
|
||||
|
||||
const Node& getRequiredValue(Diagnostics& diags, const Node& node, const char* key) {
|
||||
if (diags.hasError())
|
||||
return gSentinelNode;
|
||||
|
||||
if (!node.array.empty()) {
|
||||
diags.error("Cannot get key '%s' from array node\n", key);
|
||||
return gSentinelNode;
|
||||
}
|
||||
if (!node.value.empty()) {
|
||||
diags.error("Cannot get key '%s' from value node\n", key);
|
||||
return gSentinelNode;
|
||||
}
|
||||
|
||||
auto it = node.map.find(key);
|
||||
if (it == node.map.end()) {
|
||||
diags.error("Map node doesn't have element for key '%s'\n", key);
|
||||
return gSentinelNode;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
const Node* getOptionalValue(Diagnostics& diags, const Node& node, const char* key) {
|
||||
if (diags.hasError())
|
||||
return nullptr;
|
||||
|
||||
if (!node.array.empty()) {
|
||||
diags.error("Cannot get key '%s' from array node\n", key);
|
||||
return nullptr;
|
||||
}
|
||||
if (!node.value.empty()) {
|
||||
diags.error("Cannot get key '%s' from value node\n", key);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto it = node.map.find(key);
|
||||
if (it == node.map.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
uint64_t parseRequiredInt(Diagnostics& diags, const Node& node) {
|
||||
if (diags.hasError())
|
||||
return 0;
|
||||
|
||||
if (!node.array.empty()) {
|
||||
diags.error("Cannot get integer value from array node\n");
|
||||
return 0;
|
||||
}
|
||||
if (!node.map.empty()) {
|
||||
diags.error("Cannot get integer value from value node\n");
|
||||
return 0;
|
||||
}
|
||||
if (node.value.empty()) {
|
||||
diags.error("Cannot get integer value from empty node\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return atoi(node.value.c_str());
|
||||
}
|
||||
|
||||
const std::string& parseRequiredString(Diagnostics& diags, const Node& node) {
|
||||
static std::string sentinelString = "";
|
||||
|
||||
if (diags.hasError())
|
||||
return sentinelString;
|
||||
|
||||
if (!node.array.empty()) {
|
||||
diags.error("Cannot get string value from array node\n");
|
||||
return sentinelString;
|
||||
}
|
||||
if (!node.map.empty()) {
|
||||
diags.error("Cannot get string value from value node\n");
|
||||
return sentinelString;
|
||||
}
|
||||
if (node.value.empty()) {
|
||||
diags.error("Cannot get string value from empty node\n");
|
||||
return sentinelString;
|
||||
}
|
||||
return node.value;
|
||||
}
|
||||
|
||||
|
||||
Node parseNode(Diagnostics& diags, id jsonObject) {
|
||||
__block Node node;
|
||||
|
||||
// NSDictionary -> map
|
||||
if ([jsonObject isKindOfClass:[NSDictionary class]]) {
|
||||
NSDictionary* dict = (NSDictionary*)jsonObject;
|
||||
|
||||
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop) {
|
||||
if (![key isKindOfClass:[NSString class]]) {
|
||||
diags.error("JSON map key is not of string type\n");
|
||||
*stop = true;
|
||||
return;
|
||||
}
|
||||
Node childNode = parseNode(diags, value);
|
||||
if (diags.hasError()) {
|
||||
*stop = true;
|
||||
return;
|
||||
}
|
||||
node.map[[key UTF8String]] = childNode;
|
||||
}];
|
||||
|
||||
if (diags.hasError())
|
||||
return Node();
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// NSArray -> array
|
||||
if ([jsonObject isKindOfClass:[NSArray class]]) {
|
||||
NSArray* array = (NSArray*)jsonObject;
|
||||
|
||||
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop) {
|
||||
Node childNode = parseNode(diags, obj);
|
||||
if (diags.hasError()) {
|
||||
*stop = true;
|
||||
return;
|
||||
}
|
||||
node.array.push_back(childNode);
|
||||
}];
|
||||
|
||||
if (diags.hasError())
|
||||
return Node();
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// NSString -> value
|
||||
if ([jsonObject isKindOfClass:[NSString class]]) {
|
||||
node.value = [(NSString*)jsonObject UTF8String];
|
||||
return node;
|
||||
}
|
||||
|
||||
diags.error("Unknown json deserialized type\n");
|
||||
return Node();
|
||||
}
|
||||
|
||||
Node readJSON(Diagnostics& diags, const char* filePath) {
|
||||
NSInputStream* inputStream = [NSInputStream inputStreamWithFileAtPath:[NSString stringWithUTF8String:filePath]];
|
||||
if (!inputStream) {
|
||||
diags.error("Could not option json file: '%s'\n", filePath);
|
||||
return Node();
|
||||
}
|
||||
[inputStream open];
|
||||
|
||||
NSError* error = nil;
|
||||
id jsonObject = [NSJSONSerialization JSONObjectWithStream:inputStream options:NSJSONReadingMutableContainers error:&error];
|
||||
if (!jsonObject) {
|
||||
diags.error("Could not deserializer json file: '%s' because '%s'\n", filePath, [[error localizedFailureReason] UTF8String]);
|
||||
[inputStream close];
|
||||
return Node();
|
||||
}
|
||||
|
||||
Node node = parseNode(diags, jsonObject);
|
||||
[inputStream close];
|
||||
return node;
|
||||
}
|
||||
|
||||
} //namespace json
|
||||
} //namespace dyld3
|
116
src/dyld/dyld3/JSONWriter.h
Normal file
116
src/dyld/dyld3/JSONWriter.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#ifndef __JSON_WRITER_H__
|
||||
#define __JSON_WRITER_H__
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "JSON.h"
|
||||
|
||||
namespace dyld3 {
|
||||
namespace json {
|
||||
|
||||
static inline std::string hex(uint64_t value) {
|
||||
char buff[64];
|
||||
sprintf(buff, "0x%llX", value);
|
||||
return buff;
|
||||
}
|
||||
|
||||
static inline std::string hex4(uint64_t value) {
|
||||
char buff[64];
|
||||
sprintf(buff, "0x%04llX", value);
|
||||
return buff;
|
||||
}
|
||||
|
||||
static inline std::string hex8(uint64_t value) {
|
||||
char buff[64];
|
||||
sprintf(buff, "0x%08llX", value);
|
||||
return buff;
|
||||
}
|
||||
|
||||
static inline std::string decimal(uint64_t value) {
|
||||
char buff[64];
|
||||
sprintf(buff, "%llu", value);
|
||||
return buff;
|
||||
}
|
||||
|
||||
static inline void indentBy(uint32_t spaces, std::ostream& out) {
|
||||
for (uint32_t i=0; i < spaces; ++i) {
|
||||
out << " ";
|
||||
}
|
||||
}
|
||||
|
||||
static inline void printJSON(const Node& node, uint32_t indent, std::ostream& out)
|
||||
{
|
||||
if ( !node.map.empty() ) {
|
||||
out << "{";
|
||||
bool needComma = false;
|
||||
for (const auto& entry : node.map) {
|
||||
if ( needComma )
|
||||
out << ",";
|
||||
out << "\n";
|
||||
indentBy(indent+2, out);
|
||||
out << "\"" << entry.first << "\": ";
|
||||
printJSON(entry.second, indent+2, out);
|
||||
needComma = true;
|
||||
}
|
||||
out << "\n";
|
||||
indentBy(indent, out);
|
||||
out << "}";
|
||||
}
|
||||
else if ( !node.array.empty() ) {
|
||||
out << "[";
|
||||
bool needComma = false;
|
||||
for (const auto& entry : node.array) {
|
||||
if ( needComma )
|
||||
out << ",";
|
||||
out << "\n";
|
||||
indentBy(indent+2, out);
|
||||
printJSON(entry, indent+2, out);
|
||||
needComma = true;
|
||||
}
|
||||
out << "\n";
|
||||
indentBy(indent, out);
|
||||
out << "]";
|
||||
}
|
||||
else {
|
||||
std::string escapedString;
|
||||
escapedString.reserve(node.value.size());
|
||||
for (char c : node.value) {
|
||||
if (c == '"')
|
||||
escapedString += '\\';
|
||||
escapedString += c;
|
||||
}
|
||||
out << "\"" << escapedString << "\"";
|
||||
}
|
||||
if ( indent == 0 )
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
|
||||
} // namespace json
|
||||
} // namespace dyld3
|
||||
|
||||
|
||||
#endif // __JSON_WRITER_H__
|
927
src/dyld/dyld3/Loading.cpp
Normal file
927
src/dyld/dyld3/Loading.cpp
Normal file
@ -0,0 +1,927 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#include <bitset>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <mach/mach.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/dtrace.h>
|
||||
#include <sys/errno.h>
|
||||
#include <unistd.h>
|
||||
#include <System/sys/mman.h>
|
||||
#include <System/sys/csr.h>
|
||||
#include <System/machine/cpu_capabilities.h>
|
||||
#if !TARGET_OS_SIMULATOR && !TARGET_OS_DRIVERKIT
|
||||
#include <sandbox.h>
|
||||
#include <sandbox/private.h>
|
||||
#endif
|
||||
//#include <dispatch/dispatch.h>
|
||||
#include <mach/vm_page_size.h>
|
||||
|
||||
#include "MachOFile.h"
|
||||
#include "MachOLoaded.h"
|
||||
#include "MachOAnalyzer.h"
|
||||
#include "Logging.h"
|
||||
#include "Loading.h"
|
||||
#include "Tracing.h"
|
||||
#include "dyld2.h"
|
||||
#include "dyld_cache_format.h"
|
||||
|
||||
#include "objc-shared-cache.h"
|
||||
|
||||
namespace dyld {
|
||||
void log(const char* m, ...);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
// utility to track a set of ImageNum's in use
|
||||
class VIS_HIDDEN ImageNumSet
|
||||
{
|
||||
public:
|
||||
void add(dyld3::closure::ImageNum num);
|
||||
bool contains(dyld3::closure::ImageNum num) const;
|
||||
|
||||
private:
|
||||
std::bitset<5120> _bitmap;
|
||||
dyld3::OverflowSafeArray<dyld3::closure::ImageNum> _overflowArray;
|
||||
};
|
||||
|
||||
void ImageNumSet::add(dyld3::closure::ImageNum num)
|
||||
{
|
||||
if ( num < 5120 )
|
||||
_bitmap.set(num);
|
||||
else
|
||||
_overflowArray.push_back(num);
|
||||
}
|
||||
|
||||
bool ImageNumSet::contains(dyld3::closure::ImageNum num) const
|
||||
{
|
||||
if ( num < 5120 )
|
||||
return _bitmap.test(num);
|
||||
|
||||
for (dyld3::closure::ImageNum existingNum : _overflowArray) {
|
||||
if ( existingNum == num )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace anonymous
|
||||
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
Loader::Loader(const Array<LoadedImage>& existingImages, Array<LoadedImage>& newImagesStorage,
|
||||
const void* cacheAddress, const Array<const dyld3::closure::ImageArray*>& imagesArrays,
|
||||
const closure::ObjCSelectorOpt* selOpt, const Array<closure::Image::ObjCSelectorImage>& selImages,
|
||||
LogFunc logLoads, LogFunc logSegments, LogFunc logFixups, LogFunc logDofs)
|
||||
: _existingImages(existingImages), _newImages(newImagesStorage),
|
||||
_imagesArrays(imagesArrays), _dyldCacheAddress(cacheAddress), _dyldCacheSelectorOpt(nullptr),
|
||||
_closureSelectorOpt(selOpt), _closureSelectorImages(selImages),
|
||||
_logLoads(logLoads), _logSegments(logSegments), _logFixups(logFixups), _logDofs(logDofs)
|
||||
{
|
||||
#if BUILDING_DYLD
|
||||
// This is only needed for dyld and the launch closure, not the dlopen closures
|
||||
if ( _dyldCacheAddress != nullptr ) {
|
||||
_dyldCacheSelectorOpt = ((const DyldSharedCache*)_dyldCacheAddress)->objcOpt()->selopt();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Loader::addImage(const LoadedImage& li)
|
||||
{
|
||||
_newImages.push_back(li);
|
||||
}
|
||||
|
||||
LoadedImage* Loader::findImage(closure::ImageNum targetImageNum)
|
||||
{
|
||||
#if BUILDING_DYLD
|
||||
// The launch images are different in dyld vs libdyld. In dyld, the new images are
|
||||
// the launch images, while in libdyld, the existing images are the launch images
|
||||
if (LoadedImage* info = _launchImagesCache.findImage(targetImageNum, _newImages)) {
|
||||
return info;
|
||||
}
|
||||
|
||||
for (uint64_t index = 0; index != _newImages.count(); ++index) {
|
||||
LoadedImage& info = _newImages[index];
|
||||
if ( info.image()->representsImageNum(targetImageNum) ) {
|
||||
// Try cache this entry for next time
|
||||
_launchImagesCache.tryAddImage(targetImageNum, index);
|
||||
return &info;
|
||||
}
|
||||
}
|
||||
#elif BUILDING_LIBDYLD
|
||||
for (const LoadedImage& info : _existingImages) {
|
||||
if ( info.image()->representsImageNum(targetImageNum) )
|
||||
return (LoadedImage*)&info;
|
||||
}
|
||||
for (LoadedImage& info : _newImages) {
|
||||
if ( info.image()->representsImageNum(targetImageNum) )
|
||||
return &info;
|
||||
}
|
||||
#else
|
||||
#error Must be building dyld or libdyld
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uintptr_t Loader::resolveTarget(closure::Image::ResolvedSymbolTarget target)
|
||||
{
|
||||
const LoadedImage* info;
|
||||
switch ( target.sharedCache.kind ) {
|
||||
case closure::Image::ResolvedSymbolTarget::kindSharedCache:
|
||||
assert(_dyldCacheAddress != nullptr);
|
||||
return (uintptr_t)_dyldCacheAddress + (uintptr_t)target.sharedCache.offset;
|
||||
|
||||
case closure::Image::ResolvedSymbolTarget::kindImage:
|
||||
info = findImage(target.image.imageNum);
|
||||
assert(info != nullptr);
|
||||
return (uintptr_t)(info->loadedAddress()) + (uintptr_t)target.image.offset;
|
||||
|
||||
case closure::Image::ResolvedSymbolTarget::kindAbsolute:
|
||||
if ( target.absolute.value & (1ULL << 62) )
|
||||
return (uintptr_t)(target.absolute.value | 0xC000000000000000ULL);
|
||||
else
|
||||
return (uintptr_t)target.absolute.value;
|
||||
}
|
||||
assert(0 && "malformed ResolvedSymbolTarget");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Loader::completeAllDependents(Diagnostics& diag, bool& someCacheImageOverridden)
|
||||
{
|
||||
// accumulate all image overrides
|
||||
STACK_ALLOC_ARRAY(ImageOverride, overrides, _existingImages.maxCount() + _newImages.maxCount());
|
||||
for (const auto anArray : _imagesArrays) {
|
||||
// ignore prebuilt Image* in dyld cache
|
||||
if ( anArray->startImageNum() < dyld3::closure::kFirstLaunchClosureImageNum )
|
||||
continue;
|
||||
anArray->forEachImage(^(const dyld3::closure::Image* image, bool& stop) {
|
||||
ImageOverride overrideEntry;
|
||||
if ( image->isOverrideOfDyldCacheImage(overrideEntry.inCache) ) {
|
||||
someCacheImageOverridden = true;
|
||||
overrideEntry.replacement = image->imageNum();
|
||||
overrides.push_back(overrideEntry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// make cache for fast lookup of already loaded images
|
||||
__block ImageNumSet alreadyLoaded;
|
||||
for (const LoadedImage& info : _existingImages) {
|
||||
alreadyLoaded.add(info.image()->imageNum());
|
||||
}
|
||||
alreadyLoaded.add(_newImages.begin()->image()->imageNum());
|
||||
|
||||
// for each image in _newImages, starting at the top image, make sure its dependents are in _allImages
|
||||
uintptr_t index = 0;
|
||||
while ( (index < _newImages.count()) && diag.noError() ) {
|
||||
const closure::Image* image = _newImages[index].image();
|
||||
//fprintf(stderr, "completeAllDependents(): looking at dependents of %s\n", image->path());
|
||||
image->forEachDependentImage(^(uint32_t depIndex, closure::Image::LinkKind kind, closure::ImageNum depImageNum, bool& stop) {
|
||||
// check if imageNum needs to be changed to an override
|
||||
for (const ImageOverride& entry : overrides) {
|
||||
if ( entry.inCache == depImageNum ) {
|
||||
depImageNum = entry.replacement;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// check if this dependent is already loaded
|
||||
if ( !alreadyLoaded.contains(depImageNum) ) {
|
||||
// if not, look in imagesArrays
|
||||
const closure::Image* depImage = closure::ImageArray::findImage(_imagesArrays, depImageNum);
|
||||
if ( depImage != nullptr ) {
|
||||
//dyld::log(" load imageNum=0x%05X, image path=%s\n", depImageNum, depImage->path());
|
||||
if ( _newImages.freeCount() == 0 ) {
|
||||
diag.error("too many initial images");
|
||||
stop = true;
|
||||
}
|
||||
else {
|
||||
_newImages.push_back(LoadedImage::make(depImage));
|
||||
}
|
||||
alreadyLoaded.add(depImageNum);
|
||||
}
|
||||
else {
|
||||
diag.error("unable to locate imageNum=0x%04X, depIndex=%d of %s", depImageNum, depIndex, image->path());
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
void Loader::mapAndFixupAllImages(Diagnostics& diag, bool processDOFs, bool fromOFI)
|
||||
{
|
||||
// scan array and map images not already loaded
|
||||
for (LoadedImage& info : _newImages) {
|
||||
if ( info.loadedAddress() != nullptr ) {
|
||||
// log main executable's segments
|
||||
if ( (info.loadedAddress()->filetype == MH_EXECUTE) && (info.state() == LoadedImage::State::mapped) ) {
|
||||
if ( _logSegments("dyld: mapped by kernel %s\n", info.image()->path()) ) {
|
||||
info.image()->forEachDiskSegment(^(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool laterReadOnly, bool& stop) {
|
||||
uint64_t start = (long)info.loadedAddress() + vmOffset;
|
||||
uint64_t end = start+vmSize-1;
|
||||
if ( (segIndex == 0) && (permissions == 0) ) {
|
||||
start = 0;
|
||||
}
|
||||
_logSegments("%14s (%c%c%c) 0x%012llX->0x%012llX \n", info.loadedAddress()->segmentName(segIndex),
|
||||
(permissions & PROT_READ) ? 'r' : '.', (permissions & PROT_WRITE) ? 'w' : '.', (permissions & PROT_EXEC) ? 'x' : '.' ,
|
||||
start, end);
|
||||
});
|
||||
}
|
||||
}
|
||||
// skip over ones already loaded
|
||||
continue;
|
||||
}
|
||||
if ( info.image()->inDyldCache() ) {
|
||||
if ( info.image()->overridableDylib() ) {
|
||||
struct stat statBuf;
|
||||
if ( stat(info.image()->path(), &statBuf) == 0 ) {
|
||||
// verify file has not changed since closure was built
|
||||
uint64_t inode;
|
||||
uint64_t mtime;
|
||||
if ( info.image()->hasFileModTimeAndInode(inode, mtime) ) {
|
||||
if ( (statBuf.st_mtime != mtime) || (statBuf.st_ino != inode) ) {
|
||||
diag.error("dylib file mtime/inode changed since closure was built for '%s'", info.image()->path());
|
||||
}
|
||||
}
|
||||
else {
|
||||
diag.error("dylib file not expected on disk, must be a root '%s'", info.image()->path());
|
||||
}
|
||||
}
|
||||
else if ( (_dyldCacheAddress != nullptr) && ((dyld_cache_header*)_dyldCacheAddress)->dylibsExpectedOnDisk ) {
|
||||
diag.error("dylib file missing, was in dyld shared cache '%s'", info.image()->path());
|
||||
}
|
||||
}
|
||||
if ( diag.noError() ) {
|
||||
info.setLoadedAddress((MachOLoaded*)((uintptr_t)_dyldCacheAddress + info.image()->cacheOffset()));
|
||||
info.setState(LoadedImage::State::fixedUp);
|
||||
if ( _logSegments("dyld: Using from dyld cache %s\n", info.image()->path()) ) {
|
||||
info.image()->forEachCacheSegment(^(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool &stop) {
|
||||
_logSegments("%14s (%c%c%c) 0x%012lX->0x%012lX \n", info.loadedAddress()->segmentName(segIndex),
|
||||
(permissions & PROT_READ) ? 'r' : '.', (permissions & PROT_WRITE) ? 'w' : '.', (permissions & PROT_EXEC) ? 'x' : '.' ,
|
||||
(long)info.loadedAddress()+(long)vmOffset, (long)info.loadedAddress()+(long)vmOffset+(long)vmSize-1);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mapImage(diag, info, fromOFI);
|
||||
if ( diag.hasError() )
|
||||
break; // out of for loop
|
||||
}
|
||||
|
||||
}
|
||||
if ( diag.hasError() ) {
|
||||
// bummer, need to clean up by unmapping any images just mapped
|
||||
for (LoadedImage& info : _newImages) {
|
||||
if ( (info.state() == LoadedImage::State::mapped) && !info.image()->inDyldCache() && !info.leaveMapped() ) {
|
||||
_logSegments("dyld: unmapping %s\n", info.image()->path());
|
||||
unmapImage(info);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// apply fixups
|
||||
for (LoadedImage& info : _newImages) {
|
||||
// images in shared cache do not need fixups applied
|
||||
if ( info.image()->inDyldCache() )
|
||||
continue;
|
||||
// previously loaded images were previously fixed up
|
||||
if ( info.state() < LoadedImage::State::fixedUp ) {
|
||||
applyFixupsToImage(diag, info);
|
||||
if ( diag.hasError() )
|
||||
break;
|
||||
info.setState(LoadedImage::State::fixedUp);
|
||||
}
|
||||
}
|
||||
|
||||
// find and register dtrace DOFs
|
||||
if ( processDOFs ) {
|
||||
STACK_ALLOC_OVERFLOW_SAFE_ARRAY(DOFInfo, dofImages, _newImages.count());
|
||||
for (LoadedImage& info : _newImages) {
|
||||
info.image()->forEachDOF(info.loadedAddress(), ^(const void* section) {
|
||||
DOFInfo dofInfo;
|
||||
dofInfo.dof = section;
|
||||
dofInfo.imageHeader = info.loadedAddress();
|
||||
dofInfo.imageShortName = info.image()->leafName();
|
||||
dofImages.push_back(dofInfo);
|
||||
});
|
||||
}
|
||||
registerDOFs(dofImages);
|
||||
}
|
||||
}
|
||||
|
||||
bool Loader::sandboxBlocked(const char* path, const char* kind)
|
||||
{
|
||||
#if TARGET_OS_SIMULATOR || TARGET_OS_DRIVERKIT
|
||||
// sandbox calls not yet supported in dyld_sim
|
||||
return false;
|
||||
#else
|
||||
sandbox_filter_type filter = (sandbox_filter_type)(SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT);
|
||||
return ( sandbox_check(getpid(), kind, filter, path) > 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Loader::sandboxBlockedMmap(const char* path)
|
||||
{
|
||||
return sandboxBlocked(path, "file-map-executable");
|
||||
}
|
||||
|
||||
bool Loader::sandboxBlockedOpen(const char* path)
|
||||
{
|
||||
return sandboxBlocked(path, "file-read-data");
|
||||
}
|
||||
|
||||
bool Loader::sandboxBlockedStat(const char* path)
|
||||
{
|
||||
return sandboxBlocked(path, "file-read-metadata");
|
||||
}
|
||||
|
||||
void Loader::mapImage(Diagnostics& diag, LoadedImage& info, bool fromOFI)
|
||||
{
|
||||
dyld3::ScopedTimer timer(DBG_DYLD_TIMING_MAP_IMAGE, info.image()->path(), 0, 0);
|
||||
|
||||
const closure::Image* image = info.image();
|
||||
uint64_t sliceOffset = image->sliceOffsetInFile();
|
||||
const uint64_t totalVMSize = image->vmSizeToMap();
|
||||
uint32_t codeSignFileOffset;
|
||||
uint32_t codeSignFileSize;
|
||||
bool isCodeSigned = image->hasCodeSignature(codeSignFileOffset, codeSignFileSize);
|
||||
|
||||
// open file
|
||||
#if BUILDING_DYLD
|
||||
int fd = dyld::my_open(info.image()->path(), O_RDONLY, 0);
|
||||
#else
|
||||
int fd = ::open(info.image()->path(), O_RDONLY, 0);
|
||||
#endif
|
||||
if ( fd == -1 ) {
|
||||
int openErr = errno;
|
||||
if ( (openErr == EPERM) && sandboxBlockedOpen(image->path()) )
|
||||
diag.error("file system sandbox blocked open(\"%s\", O_RDONLY)", image->path());
|
||||
else
|
||||
diag.error("open(\"%s\", O_RDONLY) failed with errno=%d", image->path(), openErr);
|
||||
return;
|
||||
}
|
||||
|
||||
// get file info
|
||||
struct stat statBuf;
|
||||
#if TARGET_OS_SIMULATOR
|
||||
if ( stat(image->path(), &statBuf) != 0 ) {
|
||||
#else
|
||||
if ( fstat(fd, &statBuf) != 0 ) {
|
||||
#endif
|
||||
int statErr = errno;
|
||||
if ( (statErr == EPERM) && sandboxBlockedStat(image->path()) )
|
||||
diag.error("file system sandbox blocked stat(\"%s\")", image->path());
|
||||
else
|
||||
diag.error("stat(\"%s\") failed with errno=%d", image->path(), statErr);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
// verify file has not changed since closure was built
|
||||
uint64_t inode;
|
||||
uint64_t mtime;
|
||||
if ( image->hasFileModTimeAndInode(inode, mtime) ) {
|
||||
if ( (statBuf.st_mtime != mtime) || (statBuf.st_ino != inode) ) {
|
||||
diag.error("file mtime/inode changed since closure was built for '%s'", image->path());
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// handle case on iOS where sliceOffset in closure is wrong because file was thinned after cache was built
|
||||
if ( (_dyldCacheAddress != nullptr) && !(((dyld_cache_header*)_dyldCacheAddress)->dylibsExpectedOnDisk) ) {
|
||||
if ( sliceOffset != 0 ) {
|
||||
if ( round_page_kernel(codeSignFileOffset+codeSignFileSize) == round_page_kernel(statBuf.st_size) ) {
|
||||
// file is now thin
|
||||
sliceOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// register code signature
|
||||
uint64_t coveredCodeLength = UINT64_MAX;
|
||||
if ( isCodeSigned ) {
|
||||
auto sigTimer = ScopedTimer(DBG_DYLD_TIMING_ATTACH_CODESIGNATURE, 0, 0, 0);
|
||||
fsignatures_t siginfo;
|
||||
siginfo.fs_file_start = sliceOffset; // start of mach-o slice in fat file
|
||||
siginfo.fs_blob_start = (void*)(long)(codeSignFileOffset); // start of CD in mach-o file
|
||||
siginfo.fs_blob_size = codeSignFileSize; // size of CD
|
||||
int result = fcntl(fd, F_ADDFILESIGS_RETURN, &siginfo);
|
||||
if ( result == -1 ) {
|
||||
int errnoCopy = errno;
|
||||
if ( (errnoCopy == EPERM) || (errnoCopy == EBADEXEC) ) {
|
||||
diag.error("code signature invalid (errno=%d) sliceOffset=0x%08llX, codeBlobOffset=0x%08X, codeBlobSize=0x%08X for '%s'",
|
||||
errnoCopy, sliceOffset, codeSignFileOffset, codeSignFileSize, image->path());
|
||||
}
|
||||
else {
|
||||
diag.error("fcntl(fd, F_ADDFILESIGS_RETURN) failed with errno=%d, sliceOffset=0x%08llX, codeBlobOffset=0x%08X, codeBlobSize=0x%08X for '%s'",
|
||||
errnoCopy, sliceOffset, codeSignFileOffset, codeSignFileSize, image->path());
|
||||
}
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
coveredCodeLength = siginfo.fs_file_start;
|
||||
if ( coveredCodeLength < codeSignFileOffset ) {
|
||||
diag.error("code signature does not cover entire file up to signature");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// <rdar://problem/41015217> dyld should use F_CHECK_LV even on unsigned binaries
|
||||
{
|
||||
// <rdar://problem/32684903> always call F_CHECK_LV to preflight
|
||||
fchecklv checkInfo;
|
||||
char messageBuffer[512];
|
||||
messageBuffer[0] = '\0';
|
||||
checkInfo.lv_file_start = sliceOffset;
|
||||
checkInfo.lv_error_message_size = sizeof(messageBuffer);
|
||||
checkInfo.lv_error_message = messageBuffer;
|
||||
int res = fcntl(fd, F_CHECK_LV, &checkInfo);
|
||||
if ( res == -1 ) {
|
||||
diag.error("code signature in (%s) not valid for use in process: %s", image->path(), messageBuffer);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// reserve address range
|
||||
vm_address_t loadAddress = 0;
|
||||
kern_return_t r = vm_allocate(mach_task_self(), &loadAddress, (vm_size_t)totalVMSize, VM_FLAGS_ANYWHERE);
|
||||
if ( r != KERN_SUCCESS ) {
|
||||
diag.error("vm_allocate(size=0x%0llX) failed with result=%d", totalVMSize, r);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( sliceOffset != 0 )
|
||||
_logSegments("dyld: Mapping %s (slice offset=%llu)\n", image->path(), sliceOffset);
|
||||
else
|
||||
_logSegments("dyld: Mapping %s\n", image->path());
|
||||
|
||||
// map each segment
|
||||
__block bool mmapFailure = false;
|
||||
__block const uint8_t* codeSignatureStartAddress = nullptr;
|
||||
__block const uint8_t* linkeditEndAddress = nullptr;
|
||||
__block bool mappedFirstSegment = false;
|
||||
__block uint64_t maxFileOffset = 0;
|
||||
image->forEachDiskSegment(^(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool laterReadOnly, bool& stop) {
|
||||
// <rdar://problem/32363581> Mapping zero filled segments fails with mmap of size 0
|
||||
if ( fileSize == 0 )
|
||||
return;
|
||||
void* segAddress = mmap((void*)(loadAddress+vmOffset), fileSize, permissions, MAP_FIXED | MAP_PRIVATE, fd, sliceOffset+fileOffset);
|
||||
int mmapErr = errno;
|
||||
if ( segAddress == MAP_FAILED ) {
|
||||
if ( mmapErr == EPERM ) {
|
||||
if ( sandboxBlockedMmap(image->path()) )
|
||||
diag.error("file system sandbox blocked mmap() of '%s'", image->path());
|
||||
else
|
||||
diag.error("code signing blocked mmap() of '%s'", image->path());
|
||||
}
|
||||
else {
|
||||
diag.error("mmap(addr=0x%0llX, size=0x%08X) failed with errno=%d for %s", loadAddress+vmOffset, fileSize, mmapErr, image->path());
|
||||
}
|
||||
mmapFailure = true;
|
||||
stop = true;
|
||||
}
|
||||
else if ( codeSignFileOffset > fileOffset ) {
|
||||
codeSignatureStartAddress = (uint8_t*)segAddress + (codeSignFileOffset-fileOffset);
|
||||
linkeditEndAddress = (uint8_t*)segAddress + vmSize;
|
||||
}
|
||||
// sanity check first segment is mach-o header
|
||||
if ( (segAddress != MAP_FAILED) && !mappedFirstSegment ) {
|
||||
mappedFirstSegment = true;
|
||||
const MachOFile* mf = (MachOFile*)segAddress;
|
||||
if ( !mf->isMachO(diag, fileSize) ) {
|
||||
mmapFailure = true;
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
if ( !mmapFailure ) {
|
||||
const MachOLoaded* lmo = (MachOLoaded*)loadAddress;
|
||||
_logSegments("%14s (%c%c%c) 0x%012lX->0x%012lX \n", lmo->segmentName(segIndex),
|
||||
(permissions & PROT_READ) ? 'r' : '.', (permissions & PROT_WRITE) ? 'w' : '.', (permissions & PROT_EXEC) ? 'x' : '.' ,
|
||||
(long)segAddress, (long)segAddress+(long)vmSize-1);
|
||||
}
|
||||
maxFileOffset = fileOffset + fileSize;
|
||||
});
|
||||
if ( mmapFailure ) {
|
||||
::vm_deallocate(mach_task_self(), loadAddress, (vm_size_t)totalVMSize);
|
||||
::close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
// <rdar://problem/47163421> speculatively read whole slice
|
||||
fspecread_t specread = {} ;
|
||||
specread.fsr_offset = sliceOffset;
|
||||
specread.fsr_length = maxFileOffset;
|
||||
specread.fsr_flags = 0;
|
||||
fcntl(fd, F_SPECULATIVE_READ, &specread);
|
||||
_logSegments("dyld: Speculatively read offset=0x%08llX, len=0x%08llX, path=%s\n", sliceOffset, maxFileOffset, image->path());
|
||||
|
||||
// close file
|
||||
close(fd);
|
||||
|
||||
#if BUILDING_LIBDYLD
|
||||
// verify file has not changed since closure was built by checking code signature has not changed
|
||||
struct CDHashWrapper {
|
||||
uint8_t cdHash[20];
|
||||
};
|
||||
|
||||
// Get all the hashes for the image
|
||||
STACK_ALLOC_OVERFLOW_SAFE_ARRAY(CDHashWrapper, expectedCDHashes, 1);
|
||||
image->forEachCDHash(^(const uint8_t *cdHash, bool &stop) {
|
||||
CDHashWrapper cdHashWrapper;
|
||||
memcpy(cdHashWrapper.cdHash, cdHash, sizeof(CDHashWrapper::cdHash));
|
||||
expectedCDHashes.push_back(cdHashWrapper);
|
||||
});
|
||||
|
||||
if (!expectedCDHashes.empty()) {
|
||||
if (expectedCDHashes.count() != 1) {
|
||||
// We should only see a single hash for dylibs
|
||||
diag.error("code signature count invalid");
|
||||
} else if ( codeSignatureStartAddress == nullptr ) {
|
||||
diag.error("code signature missing");
|
||||
}
|
||||
else if ( codeSignatureStartAddress+codeSignFileSize > linkeditEndAddress ) {
|
||||
diag.error("code signature extends beyond end of __LINKEDIT");
|
||||
}
|
||||
else {
|
||||
// Get all the cd hashes for the macho
|
||||
STACK_ALLOC_OVERFLOW_SAFE_ARRAY(CDHashWrapper, foundCDHashes, 1);
|
||||
const MachOLoaded* lmo = (MachOLoaded*)loadAddress;
|
||||
lmo->forEachCDHashOfCodeSignature(codeSignatureStartAddress, codeSignFileSize,
|
||||
^(const uint8_t *cdHash) {
|
||||
CDHashWrapper cdHashWrapper;
|
||||
memcpy(cdHashWrapper.cdHash, cdHash, sizeof(CDHashWrapper::cdHash));
|
||||
foundCDHashes.push_back(cdHashWrapper);
|
||||
});
|
||||
|
||||
if (foundCDHashes.empty()) {
|
||||
diag.error("code signature format invalid");
|
||||
} else if (expectedCDHashes.count() != foundCDHashes.count()) {
|
||||
diag.error("code signature count invalid");
|
||||
} else {
|
||||
// We found a hash, so make sure its equal.
|
||||
if ( ::memcmp(foundCDHashes[0].cdHash, expectedCDHashes[0].cdHash, 20) != 0 )
|
||||
diag.error("code signature changed since closure was built");
|
||||
}
|
||||
}
|
||||
if ( diag.hasError() ) {
|
||||
::vm_deallocate(mach_task_self(), loadAddress, (vm_size_t)totalVMSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR
|
||||
// tell kernel about fairplay encrypted regions
|
||||
uint32_t fpTextOffset;
|
||||
uint32_t fpSize;
|
||||
if ( image->isFairPlayEncrypted(fpTextOffset, fpSize) ) {
|
||||
const mach_header* mh = (mach_header*)loadAddress;
|
||||
int result = ::mremap_encrypted(((uint8_t*)mh) + fpTextOffset, fpSize, 1, mh->cputype, mh->cpusubtype);
|
||||
if ( result != 0 ) {
|
||||
diag.error("could not register fairplay decryption, mremap_encrypted() => %d", result);
|
||||
::vm_deallocate(mach_task_self(), loadAddress, (vm_size_t)totalVMSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
_logLoads("dyld: load %s\n", image->path());
|
||||
|
||||
timer.setData4((uint64_t)loadAddress);
|
||||
info.setLoadedAddress((MachOLoaded*)loadAddress);
|
||||
info.setState(LoadedImage::State::mapped);
|
||||
}
|
||||
|
||||
void Loader::unmapImage(LoadedImage& info)
|
||||
{
|
||||
assert(info.loadedAddress() != nullptr);
|
||||
::vm_deallocate(mach_task_self(), (vm_address_t)info.loadedAddress(), (vm_size_t)(info.image()->vmSizeToMap()));
|
||||
info.setLoadedAddress(nullptr);
|
||||
}
|
||||
|
||||
void Loader::registerDOFs(const Array<DOFInfo>& dofs)
|
||||
{
|
||||
if ( dofs.empty() )
|
||||
return;
|
||||
|
||||
int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR);
|
||||
if ( fd < 0 ) {
|
||||
_logDofs("can't open /dev/" DTRACEMNR_HELPER " to register dtrace DOF sections\n");
|
||||
}
|
||||
else {
|
||||
// allocate a buffer on the stack for the variable length dof_ioctl_data_t type
|
||||
uint8_t buffer[sizeof(dof_ioctl_data_t) + dofs.count()*sizeof(dof_helper_t)];
|
||||
dof_ioctl_data_t* ioctlData = (dof_ioctl_data_t*)buffer;
|
||||
|
||||
// fill in buffer with one dof_helper_t per DOF section
|
||||
ioctlData->dofiod_count = dofs.count();
|
||||
for (unsigned int i=0; i < dofs.count(); ++i) {
|
||||
strlcpy(ioctlData->dofiod_helpers[i].dofhp_mod, dofs[i].imageShortName, DTRACE_MODNAMELEN);
|
||||
ioctlData->dofiod_helpers[i].dofhp_dof = (uintptr_t)(dofs[i].dof);
|
||||
ioctlData->dofiod_helpers[i].dofhp_addr = (uintptr_t)(dofs[i].dof);
|
||||
}
|
||||
|
||||
// tell kernel about all DOF sections en mas
|
||||
// pass pointer to ioctlData because ioctl() only copies a fixed size amount of data into kernel
|
||||
user_addr_t val = (user_addr_t)(unsigned long)ioctlData;
|
||||
if ( ioctl(fd, DTRACEHIOC_ADDDOF, &val) != -1 ) {
|
||||
// kernel returns a unique identifier for each section in the dofiod_helpers[].dofhp_dof field.
|
||||
// Note, the closure marked the image as being never unload, so we don't need to keep the ID around
|
||||
// or support unregistering it later.
|
||||
for (unsigned int i=0; i < dofs.count(); ++i) {
|
||||
_logDofs("dyld: registering DOF section %p in %s with dtrace, ID=0x%08X\n",
|
||||
dofs[i].dof, dofs[i].imageShortName, (int)(ioctlData->dofiod_helpers[i].dofhp_dof));
|
||||
}
|
||||
}
|
||||
else {
|
||||
_logDofs("dyld: ioctl to register dtrace DOF section failed\n");
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
bool Loader::dtraceUserProbesEnabled()
|
||||
{
|
||||
#ifdef DARLING
|
||||
return false;
|
||||
#else
|
||||
uint8_t dofEnabled = *((uint8_t*)_COMM_PAGE_DTRACE_DOF_ENABLED);
|
||||
return ( (dofEnabled & 1) );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Loader::vmAccountingSetSuspended(bool suspend, LogFunc logger)
|
||||
{
|
||||
#if __arm__ || __arm64__
|
||||
// <rdar://problem/29099600> dyld should tell the kernel when it is doing fix-ups caused by roots
|
||||
logger("vm.footprint_suspend=%d\n", suspend);
|
||||
int newValue = suspend ? 1 : 0;
|
||||
int oldValue = 0;
|
||||
size_t newlen = sizeof(newValue);
|
||||
size_t oldlen = sizeof(oldValue);
|
||||
sysctlbyname("vm.footprint_suspend", &oldValue, &oldlen, &newValue, newlen);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Loader::applyFixupsToImage(Diagnostics& diag, LoadedImage& info)
|
||||
{
|
||||
dyld3::ScopedTimer timer(DBG_DYLD_TIMING_APPLY_FIXUPS, (uint64_t)info.loadedAddress(), 0, 0);
|
||||
closure::ImageNum cacheImageNum;
|
||||
const char* leafName = info.image()->leafName();
|
||||
const closure::Image* image = info.image();
|
||||
const uint8_t* imageLoadAddress = (uint8_t*)info.loadedAddress();
|
||||
uintptr_t slide = info.loadedAddress()->getSlide();
|
||||
bool overrideOfCache = info.image()->isOverrideOfDyldCacheImage(cacheImageNum);
|
||||
|
||||
if ( overrideOfCache )
|
||||
vmAccountingSetSuspended(true, _logFixups);
|
||||
image->forEachFixup(^(uint64_t imageOffsetToRebase, bool& stop) {
|
||||
// this is a rebase, add slide
|
||||
uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToRebase);
|
||||
*fixUpLoc += slide;
|
||||
_logFixups("dyld: fixup: %s:%p += %p\n", leafName, fixUpLoc, (void*)slide);
|
||||
},
|
||||
^(uint64_t imageOffsetToBind, closure::Image::ResolvedSymbolTarget bindTarget, bool& stop) {
|
||||
// this is a bind, set to target
|
||||
uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToBind);
|
||||
uintptr_t value = resolveTarget(bindTarget);
|
||||
_logFixups("dyld: fixup: %s:%p = %p\n", leafName, fixUpLoc, (void*)value);
|
||||
*fixUpLoc = value;
|
||||
},
|
||||
^(uint64_t imageOffsetToStartsInfo, const Array<closure::Image::ResolvedSymbolTarget>& targets, bool& stop) {
|
||||
// this is a chain of fixups, fix up all
|
||||
STACK_ALLOC_OVERFLOW_SAFE_ARRAY(const void*, targetAddrs, 128);
|
||||
targetAddrs.reserve(targets.count());
|
||||
for (uint32_t i=0; i < targets.count(); ++i)
|
||||
targetAddrs.push_back((void*)resolveTarget(targets[i]));
|
||||
((dyld3::MachOAnalyzer*)(info.loadedAddress()))->withChainStarts(diag, imageOffsetToStartsInfo, ^(const dyld_chained_starts_in_image* starts) {
|
||||
info.loadedAddress()->fixupAllChainedFixups(diag, starts, slide, targetAddrs, ^(void* loc, void* newValue) {
|
||||
_logFixups("dyld: fixup: %s:%p = %p\n", leafName, loc, newValue);
|
||||
});
|
||||
});
|
||||
},
|
||||
^(uint64_t imageOffsetToFixup) {
|
||||
uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToFixup);
|
||||
_logFixups("dyld: fixup objc image info: %s Setting objc image info for precomputed objc\n", leafName);
|
||||
|
||||
MachOAnalyzer::ObjCImageInfo *imageInfo = (MachOAnalyzer::ObjCImageInfo *)fixUpLoc;
|
||||
((MachOAnalyzer::ObjCImageInfo *)imageInfo)->flags |= MachOAnalyzer::ObjCImageInfo::dyldPreoptimized;
|
||||
},
|
||||
^(uint64_t imageOffsetToBind, closure::Image::ResolvedSymbolTarget bindTarget, bool& stop) {
|
||||
// this is a bind, set to target
|
||||
uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToBind);
|
||||
uintptr_t value = resolveTarget(bindTarget);
|
||||
_logFixups("dyld: fixup objc protocol: %s:%p = %p\n", leafName, fixUpLoc, (void*)value);
|
||||
*fixUpLoc = value;
|
||||
},
|
||||
^(uint64_t imageOffsetToFixup, uint32_t selectorIndex, bool inSharedCache, bool &stop) {
|
||||
// fixupObjCSelRefs
|
||||
closure::Image::ResolvedSymbolTarget fixupTarget;
|
||||
if ( inSharedCache ) {
|
||||
const char* selectorString = _dyldCacheSelectorOpt->getEntryForIndex(selectorIndex);
|
||||
fixupTarget.sharedCache.kind = closure::Image::ResolvedSymbolTarget::kindSharedCache;
|
||||
fixupTarget.sharedCache.offset = (uint64_t)selectorString - (uint64_t)_dyldCacheAddress;
|
||||
} else {
|
||||
closure::ImageNum imageNum;
|
||||
uint64_t vmOffset;
|
||||
bool gotLocation = _closureSelectorOpt->getStringLocation(selectorIndex, _closureSelectorImages, imageNum, vmOffset);
|
||||
assert(gotLocation);
|
||||
fixupTarget.image.kind = closure::Image::ResolvedSymbolTarget::kindImage;
|
||||
fixupTarget.image.imageNum = imageNum;
|
||||
fixupTarget.image.offset = vmOffset;
|
||||
}
|
||||
|
||||
uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToFixup);
|
||||
uintptr_t value = resolveTarget(fixupTarget);
|
||||
_logFixups("dyld: fixup objc selector: %s:%p(was '%s') = %p(now '%s')\n", leafName, fixUpLoc, (const char*)*fixUpLoc, (void*)value, (const char*)value);
|
||||
*fixUpLoc = value;
|
||||
}, ^(uint64_t imageOffsetToFixup, bool &stop) {
|
||||
// fixupObjCStableSwift
|
||||
// Class really is stable Swift, pretending to be pre-stable.
|
||||
// Fix its lie.
|
||||
uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToFixup);
|
||||
uintptr_t value = ((*fixUpLoc) | MachOAnalyzer::ObjCClassInfo::FAST_IS_SWIFT_STABLE) & ~MachOAnalyzer::ObjCClassInfo::FAST_IS_SWIFT_LEGACY;
|
||||
_logFixups("dyld: fixup objc stable Swift: %s:%p = %p\n", leafName, fixUpLoc, (void*)value);
|
||||
*fixUpLoc = value;
|
||||
}, ^(uint64_t imageOffsetToFixup, bool &stop) {
|
||||
// TODO: Implement this
|
||||
});
|
||||
|
||||
#if __i386__
|
||||
__block bool segmentsMadeWritable = false;
|
||||
image->forEachTextReloc(^(uint32_t imageOffsetToRebase, bool& stop) {
|
||||
if ( !segmentsMadeWritable )
|
||||
setSegmentProtects(info, true);
|
||||
uintptr_t* fixUpLoc = (uintptr_t*)(imageLoadAddress + imageOffsetToRebase);
|
||||
*fixUpLoc += slide;
|
||||
_logFixups("dyld: fixup: %s:%p += %p\n", leafName, fixUpLoc, (void*)slide);
|
||||
},
|
||||
^(uint32_t imageOffsetToBind, closure::Image::ResolvedSymbolTarget bindTarget, bool& stop) {
|
||||
// FIXME
|
||||
});
|
||||
if ( segmentsMadeWritable )
|
||||
setSegmentProtects(info, false);
|
||||
#endif
|
||||
|
||||
// make any read-only data segments read-only
|
||||
if ( image->hasReadOnlyData() && !image->inDyldCache() ) {
|
||||
image->forEachDiskSegment(^(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool laterReadOnly, bool& segStop) {
|
||||
if ( laterReadOnly ) {
|
||||
::mprotect((void*)(imageLoadAddress+vmOffset), (size_t)vmSize, VM_PROT_READ);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if ( overrideOfCache )
|
||||
vmAccountingSetSuspended(false, _logFixups);
|
||||
}
|
||||
|
||||
#if __i386__
|
||||
void Loader::setSegmentProtects(const LoadedImage& info, bool write)
|
||||
{
|
||||
info.image()->forEachDiskSegment(^(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t protections, bool laterReadOnly, bool& segStop) {
|
||||
if ( protections & VM_PROT_WRITE )
|
||||
return;
|
||||
uint32_t regionProt = protections;
|
||||
if ( write )
|
||||
regionProt = VM_PROT_WRITE | VM_PROT_READ;
|
||||
kern_return_t r = vm_protect(mach_task_self(), ((uintptr_t)info.loadedAddress())+(uintptr_t)vmOffset, (uintptr_t)vmSize, false, regionProt);
|
||||
assert( r == KERN_SUCCESS );
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BUILDING_DYLD
|
||||
LoadedImage* Loader::LaunchImagesCache::findImage(closure::ImageNum imageNum,
|
||||
Array<LoadedImage>& images) const {
|
||||
if ( (imageNum < _firstImageNum) || (imageNum >= _lastImageNum) )
|
||||
return nullptr;
|
||||
|
||||
uint64_t cacheIndex = imageNum - _firstImageNum;
|
||||
uint32_t imagesIndex = _imageIndices[cacheIndex];
|
||||
if ( imagesIndex == 0 )
|
||||
return nullptr;
|
||||
|
||||
// Note the index is offset by 1 so that 0's are not yet set
|
||||
return &images[imagesIndex - 1];
|
||||
}
|
||||
|
||||
void Loader::LaunchImagesCache::tryAddImage(closure::ImageNum imageNum,
|
||||
uint64_t allImagesIndex) {
|
||||
if ( (imageNum < _firstImageNum) || (imageNum >= _lastImageNum) )
|
||||
return;
|
||||
|
||||
uint64_t cacheIndex = imageNum - _firstImageNum;
|
||||
|
||||
// Note the index is offset by 1 so that 0's are not yet set
|
||||
_imageIndices[cacheIndex] = (uint32_t)allImagesIndex + 1;
|
||||
}
|
||||
|
||||
void forEachLineInFile(const char* buffer, size_t bufferLen, void (^lineHandler)(const char* line, bool& stop))
|
||||
{
|
||||
bool stop = false;
|
||||
const char* const eof = &buffer[bufferLen];
|
||||
for (const char* s = buffer; s < eof; ++s) {
|
||||
char lineBuffer[MAXPATHLEN];
|
||||
char* t = lineBuffer;
|
||||
char* tEnd = &lineBuffer[MAXPATHLEN];
|
||||
while ( (s < eof) && (t != tEnd) ) {
|
||||
if ( *s == '\n' )
|
||||
break;
|
||||
*t++ = *s++;
|
||||
}
|
||||
*t = '\0';
|
||||
lineHandler(lineBuffer, stop);
|
||||
if ( stop )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void forEachLineInFile(const char* path, void (^lineHandler)(const char* line, bool& stop))
|
||||
{
|
||||
int fd = dyld::my_open(path, O_RDONLY, 0);
|
||||
if ( fd != -1 ) {
|
||||
struct stat statBuf;
|
||||
if ( fstat(fd, &statBuf) == 0 ) {
|
||||
const char* lines = (const char*)mmap(nullptr, (size_t)statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if ( lines != MAP_FAILED ) {
|
||||
forEachLineInFile(lines, (size_t)statBuf.st_size, lineHandler);
|
||||
munmap((void*)lines, (size_t)statBuf.st_size);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (BUILDING_LIBDYLD || BUILDING_DYLD)
|
||||
bool internalInstall()
|
||||
{
|
||||
#if TARGET_OS_SIMULATOR
|
||||
return false;
|
||||
#elif __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
uint32_t devFlags = *((uint32_t*)_COMM_PAGE_DEV_FIRM);
|
||||
return ( (devFlags & 1) == 1 );
|
||||
#else
|
||||
return ( csr_check(CSR_ALLOW_APPLE_INTERNAL) == 0 );
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BUILDING_LIBDYLD
|
||||
// hack because libdyld.dylib should not link with libc++.dylib
|
||||
extern "C" void __cxa_pure_virtual() __attribute__((visibility("hidden")));
|
||||
void __cxa_pure_virtual()
|
||||
{
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace dyld3
|
||||
|
||||
|
||||
|
||||
|
||||
|
181
src/dyld/dyld3/Loading.h
Normal file
181
src/dyld/dyld3/Loading.h
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef __DYLD_LOADING_H__
|
||||
#define __DYLD_LOADING_H__
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <mach/mach.h>
|
||||
#include <_simple.h>
|
||||
|
||||
#include "Closure.h"
|
||||
#include "MachOLoaded.h"
|
||||
|
||||
namespace objc_opt {
|
||||
struct objc_clsopt_t;
|
||||
struct objc_selopt_t;
|
||||
}
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
|
||||
//
|
||||
// Tuple of info about a loaded image. Contains the loaded address, Image*, and state.
|
||||
//
|
||||
class VIS_HIDDEN LoadedImage {
|
||||
public:
|
||||
enum class State { unmapped=0, mapped=1, fixedUp=2, beingInited=3, inited=4 };
|
||||
|
||||
static LoadedImage make(const closure::Image* img) { LoadedImage result; result._image = img; return result; }
|
||||
static LoadedImage make(const closure::Image* img, const MachOLoaded* mh)
|
||||
{ LoadedImage result; result._image = img; result.setLoadedAddress(mh); return result; }
|
||||
|
||||
const closure::Image* image() const { return _image; }
|
||||
const MachOLoaded* loadedAddress() const { return (MachOLoaded*)(_loadAddr & (-4096)); }
|
||||
void setLoadedAddress(const MachOLoaded* a) { _loadAddr |= ((uintptr_t)a & (-4096)); }
|
||||
State state() const { return (State)(asBits().state); }
|
||||
void setState(State s) { asBits().state = (int)s; }
|
||||
bool hideFromFlatSearch() const { return asBits().hide; }
|
||||
void setHideFromFlatSearch(bool h) { asBits().hide = h; }
|
||||
bool leaveMapped() const { return asBits().leaveMapped; }
|
||||
void markLeaveMapped() { asBits().leaveMapped = true; }
|
||||
|
||||
private:
|
||||
// since loaded MachO files are always page aligned, that means at least low 12-bits are always zero
|
||||
// so we don't need to record the low 12 bits, instead those bits hold various flags in the _loadeAddr field
|
||||
struct AddrBits {
|
||||
uintptr_t state : 3,
|
||||
hide : 1,
|
||||
leaveMapped : 1,
|
||||
extra : 7,
|
||||
#if __LP64__
|
||||
addr : 52;
|
||||
#else
|
||||
addr : 20;
|
||||
#endif
|
||||
};
|
||||
AddrBits& asBits() { return *((AddrBits*)&_loadAddr); }
|
||||
const AddrBits& asBits() const { return *((AddrBits*)&_loadAddr); }
|
||||
|
||||
// Note: this must be statically initializable so as to not cause static initializers
|
||||
const closure::Image* _image = nullptr;
|
||||
uintptr_t _loadAddr = 0; // really AddrBits
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Utility class to recursively load dependents
|
||||
//
|
||||
class VIS_HIDDEN Loader {
|
||||
public:
|
||||
typedef bool (*LogFunc)(const char*, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
Loader(const Array<LoadedImage>& existingImages, Array<LoadedImage>& newImagesStorage,
|
||||
const void* cacheAddress, const Array<const dyld3::closure::ImageArray*>& imagesArrays,
|
||||
const closure::ObjCSelectorOpt* selOpt, const Array<closure::Image::ObjCSelectorImage>& selImages,
|
||||
LogFunc log_loads, LogFunc log_segments, LogFunc log_fixups, LogFunc log_dofs);
|
||||
|
||||
void addImage(const LoadedImage&);
|
||||
void completeAllDependents(Diagnostics& diag, bool& someCacheImageOverridden);
|
||||
void mapAndFixupAllImages(Diagnostics& diag, bool processDOFs, bool fromOFI=false);
|
||||
uintptr_t resolveTarget(closure::Image::ResolvedSymbolTarget target);
|
||||
LoadedImage* findImage(closure::ImageNum targetImageNum);
|
||||
|
||||
static void unmapImage(LoadedImage& info);
|
||||
static bool dtraceUserProbesEnabled();
|
||||
static void vmAccountingSetSuspended(bool suspend, LogFunc);
|
||||
|
||||
private:
|
||||
|
||||
struct ImageOverride
|
||||
{
|
||||
closure::ImageNum inCache;
|
||||
closure::ImageNum replacement;
|
||||
};
|
||||
|
||||
struct DOFInfo {
|
||||
const void* dof;
|
||||
const mach_header* imageHeader;
|
||||
const char* imageShortName;
|
||||
};
|
||||
|
||||
#if BUILDING_DYLD
|
||||
struct LaunchImagesCache {
|
||||
LoadedImage* findImage(closure::ImageNum targetImageNum,
|
||||
Array<LoadedImage>& images) const;
|
||||
void tryAddImage(closure::ImageNum targetImageNum, uint64_t allImagesIndex);
|
||||
|
||||
static const uint64_t _cacheSize = 128;
|
||||
static const closure::ImageNum _firstImageNum = closure::kFirstLaunchClosureImageNum;
|
||||
static const closure::ImageNum _lastImageNum = closure::kFirstLaunchClosureImageNum + _cacheSize;
|
||||
|
||||
// Note, the cache stores "indices + 1" into the _allImages array.
|
||||
// 0 means we haven't cached an entry yet
|
||||
uint32_t _cacheStorage[_cacheSize] = { 0 };
|
||||
Array<uint32_t> _imageIndices = { &_cacheStorage[0], _cacheSize, _cacheSize };
|
||||
};
|
||||
#endif
|
||||
|
||||
void mapImage(Diagnostics& diag, LoadedImage& info, bool fromOFI);
|
||||
void applyFixupsToImage(Diagnostics& diag, LoadedImage& info);
|
||||
void registerDOFs(const Array<DOFInfo>& dofs);
|
||||
void setSegmentProtects(const LoadedImage& info, bool write);
|
||||
bool sandboxBlockedMmap(const char* path);
|
||||
bool sandboxBlockedOpen(const char* path);
|
||||
bool sandboxBlockedStat(const char* path);
|
||||
bool sandboxBlocked(const char* path, const char* kind);
|
||||
|
||||
const Array<LoadedImage>& _existingImages;
|
||||
Array<LoadedImage>& _newImages;
|
||||
const Array<const closure::ImageArray*>& _imagesArrays;
|
||||
const void* _dyldCacheAddress;
|
||||
const objc_opt::objc_selopt_t* _dyldCacheSelectorOpt;
|
||||
const closure::ObjCSelectorOpt* _closureSelectorOpt;
|
||||
const Array<closure::Image::ObjCSelectorImage>& _closureSelectorImages;
|
||||
#if BUILDING_DYLD
|
||||
LaunchImagesCache _launchImagesCache;
|
||||
#endif
|
||||
LogFunc _logLoads;
|
||||
LogFunc _logSegments;
|
||||
LogFunc _logFixups;
|
||||
LogFunc _logDofs;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#if (BUILDING_LIBDYLD || BUILDING_DYLD)
|
||||
bool internalInstall();
|
||||
#endif
|
||||
#if BUILDING_DYLD
|
||||
void forEachLineInFile(const char* path, void (^lineHandler)(const char* line, bool& stop));
|
||||
void forEachLineInFile(const char* buffer, size_t bufferLen, void (^lineHandler)(const char* line, bool& stop));
|
||||
#endif
|
||||
|
||||
} // namespace dyld3
|
||||
|
||||
#endif // __DYLD_LOADING_H__
|
||||
|
||||
|
188
src/dyld/dyld3/Logging.cpp
Normal file
188
src/dyld/dyld3/Logging.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <_simple.h>
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
|
||||
static bool sVerboseLoading = false;
|
||||
static bool sVerboseInitializers = false;
|
||||
static bool sVerboseSegments = false;
|
||||
static bool sVerboseAPIs = false;
|
||||
static bool sVerboseNotifications = false;
|
||||
static bool sVerboseFixups = false;
|
||||
static bool sVerboseDOFs = false;
|
||||
|
||||
static void vlog_default(const char* format, va_list list)
|
||||
{
|
||||
_simple_vdprintf(2, format, list);
|
||||
}
|
||||
|
||||
static void (*sLogFunction)(const char* format, va_list list) = &vlog_default;
|
||||
static void (*sHaltFunction)(const char* message) __attribute__((noreturn)) = nullptr;
|
||||
|
||||
void halt(const char* message)
|
||||
{
|
||||
(*sHaltFunction)(message);
|
||||
}
|
||||
|
||||
static void vlog(const char* format, va_list list)
|
||||
{
|
||||
(*sLogFunction)(format, list);
|
||||
}
|
||||
|
||||
bool log_loads(const char* format, ...)
|
||||
{
|
||||
if ( !sVerboseLoading )
|
||||
return false;
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
vlog(format, list);
|
||||
va_end(list);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool log_segments(const char* format, ...)
|
||||
{
|
||||
if ( !sVerboseSegments )
|
||||
return false;
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
vlog(format, list);
|
||||
va_end(list);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool log_fixups(const char* format, ...)
|
||||
{
|
||||
if ( !sVerboseFixups )
|
||||
return false;
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
vlog(format, list);
|
||||
va_end(list);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool log_initializers(const char* format, ...)
|
||||
{
|
||||
if ( !sVerboseInitializers )
|
||||
return false;
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
vlog(format, list);
|
||||
va_end(list);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool log_apis(const char* format, ...)
|
||||
{
|
||||
if ( !sVerboseAPIs )
|
||||
return false;
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
vlog(format, list);
|
||||
va_end(list);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool log_notifications(const char* format, ...)
|
||||
{
|
||||
if ( !sVerboseNotifications )
|
||||
return false;
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
vlog(format, list);
|
||||
va_end(list);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool log_dofs(const char* format, ...)
|
||||
{
|
||||
if ( !sVerboseDOFs )
|
||||
return false;
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
vlog(format, list);
|
||||
va_end(list);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setLoggingFromEnvs(const char* envp[])
|
||||
{
|
||||
for(const char** p = envp; *p != NULL; p++) {
|
||||
const char* keyEqualsValue = *p;
|
||||
const char* equals = strchr(keyEqualsValue, '=');
|
||||
if ( equals != NULL ) {
|
||||
//const char* value = &equals[1];
|
||||
const size_t keyLen = equals-keyEqualsValue;
|
||||
char key[keyLen+1];
|
||||
strncpy(key, keyEqualsValue, keyLen);
|
||||
key[keyLen] = '\0';
|
||||
if ( strcmp(key, "DYLD_PRINT_LIBRARIES") == 0 ) {
|
||||
sVerboseLoading = true;
|
||||
}
|
||||
else if ( strcmp(key, "DYLD_PRINT_SEGMENTS") == 0 ) {
|
||||
sVerboseSegments = true;
|
||||
}
|
||||
else if ( strcmp(key, "DYLD_PRINT_INITIALIZERS") == 0 ) {
|
||||
sVerboseInitializers = true;
|
||||
}
|
||||
else if ( strcmp(key, "DYLD_PRINT_APIS") == 0 ) {
|
||||
sVerboseAPIs = true;
|
||||
}
|
||||
else if ( strcmp(key, "DYLD_PRINT_NOTIFICATIONS") == 0 ) {
|
||||
sVerboseNotifications = true;
|
||||
}
|
||||
else if ( strcmp(key, "DYLD_PRINT_BINDINGS") == 0 ) {
|
||||
sVerboseFixups = true;
|
||||
}
|
||||
else if ( strcmp(key, "DYLD_PRINT_DOFS") == 0 ) {
|
||||
sVerboseDOFs = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setLoggingFunction(void (*func)(const char* format, va_list list))
|
||||
{
|
||||
sLogFunction = func;
|
||||
}
|
||||
|
||||
void setHaltFunction(void (*func)(const char* message) __attribute__((noreturn)))
|
||||
{
|
||||
sHaltFunction = func;
|
||||
}
|
||||
|
||||
|
||||
} // namespace dyld3
|
||||
|
62
src/dyld/dyld3/Logging.h
Normal file
62
src/dyld/dyld3/Logging.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef __DYLD_LOGGING_H__
|
||||
#define __DYLD_LOGGING_H__
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define VIS_HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
|
||||
bool log_loads(const char* format, ...) __attribute__((format(printf, 1, 2))) VIS_HIDDEN;
|
||||
bool log_apis(const char* format, ...) __attribute__((format(printf, 1, 2))) VIS_HIDDEN;
|
||||
bool log_segments(const char* format, ...) __attribute__((format(printf, 1, 2))) VIS_HIDDEN;
|
||||
bool log_initializers(const char* format, ...) __attribute__((format(printf, 1, 2))) VIS_HIDDEN;
|
||||
bool log_fixups(const char* format, ...) __attribute__((format(printf, 1, 2))) VIS_HIDDEN;
|
||||
bool log_notifications(const char* format, ...) __attribute__((format(printf, 1, 2))) VIS_HIDDEN;
|
||||
bool log_dofs(const char* format, ...) __attribute__((format(printf, 1, 2))) VIS_HIDDEN;
|
||||
|
||||
void halt(const char* message) __attribute((noreturn)) VIS_HIDDEN ;
|
||||
|
||||
|
||||
// only called during libdyld set up
|
||||
void setLoggingFromEnvs(const char* envp[]) VIS_HIDDEN ;
|
||||
void setLoggingFunction(void (*func)(const char* format, va_list list)) VIS_HIDDEN;
|
||||
void setHaltFunction(void (*func)(const char* message) __attribute__((noreturn))) VIS_HIDDEN;
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace dyld3
|
||||
|
||||
#endif // __DYLD_LOGGING_H__
|
||||
|
||||
|
3938
src/dyld/dyld3/MachOAnalyzer.cpp
Normal file
3938
src/dyld/dyld3/MachOAnalyzer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
353
src/dyld/dyld3/MachOAnalyzer.h
Normal file
353
src/dyld/dyld3/MachOAnalyzer.h
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#ifndef MachOAnalyzer_h
|
||||
#define MachOAnalyzer_h
|
||||
|
||||
|
||||
#include "MachOLoaded.h"
|
||||
#include "Array.h"
|
||||
#include "ClosureFileSystem.h"
|
||||
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
// Extra functionality on loaded mach-o files only used during closure building
|
||||
struct VIS_HIDDEN MachOAnalyzer : public MachOLoaded
|
||||
{
|
||||
// protected members of subclass promoted to public here
|
||||
using MachOLoaded::SegmentInfo;
|
||||
using MachOLoaded::SectionInfo;
|
||||
using MachOLoaded::forEachSegment;
|
||||
using MachOLoaded::forEachSection;
|
||||
using MachOLoaded::forEachDependentDylib;
|
||||
using MachOLoaded::getDylibInstallName;
|
||||
using MachOLoaded::FoundSymbol;
|
||||
using MachOLoaded::findExportedSymbol;
|
||||
|
||||
static closure::LoadedFileInfo load(Diagnostics& diag, const closure::FileSystem& fileSystem,
|
||||
const char* logicalPath, const GradedArchs& archs, Platform platform, char realerPath[MAXPATHLEN]);
|
||||
static const MachOAnalyzer* validMainExecutable(Diagnostics& diag, const mach_header* mh, const char* path, uint64_t sliceLength,
|
||||
const GradedArchs& archs, Platform platform);
|
||||
|
||||
typedef void (^ExportsCallback)(const char* symbolName, uint64_t imageOffset, uint64_t flags,
|
||||
uint64_t other, const char* importName, bool& stop);
|
||||
bool validMachOForArchAndPlatform(Diagnostics& diag, size_t mappedSize, const char* path, const GradedArchs& archs, Platform platform) const;
|
||||
uint64_t mappedSize() const;
|
||||
bool hasObjC() const;
|
||||
bool hasPlusLoadMethod(Diagnostics& diag) const;
|
||||
uint64_t preferredLoadAddress() const;
|
||||
void forEachLocalSymbol(Diagnostics& diag, void (^callback)(const char* symbolName, uint64_t n_value, uint8_t n_type, uint8_t n_sect, uint16_t n_desc, bool& stop)) const;
|
||||
void forEachRPath(void (^callback)(const char* rPath, bool& stop)) const;
|
||||
|
||||
bool isEncrypted() const;
|
||||
void forEachCDHash(void (^handler)(const uint8_t cdHash[20])) const;
|
||||
bool hasCodeSignature(uint32_t& fileOffset, uint32_t& size) const;
|
||||
bool usesLibraryValidation() const;
|
||||
bool isRestricted() const;
|
||||
bool getEntry(uint32_t& offset, bool& usesCRT) const;
|
||||
bool isSlideable() const;
|
||||
bool hasInitializer(Diagnostics& diag, bool contentRebased, const void* dyldCache=nullptr) const;
|
||||
void forEachInitializerPointerSection(Diagnostics& diag, void (^callback)(uint32_t sectionOffset, uint32_t sectionSize, const uint8_t* content, bool& stop)) const;
|
||||
void forEachInitializer(Diagnostics& diag, bool contentRebased, void (^callback)(uint32_t offset), const void* dyldCache=nullptr) const;
|
||||
bool hasTerminators(Diagnostics& diag, bool contentRebased) const;
|
||||
void forEachTerminator(Diagnostics& diag, bool contentRebased, void (^callback)(uint32_t offset)) const;
|
||||
void forEachDOFSection(Diagnostics& diag, void (^callback)(uint32_t offset)) const;
|
||||
uint32_t segmentCount() const;
|
||||
void forEachExportedSymbol(Diagnostics& diag, ExportsCallback callback) const;
|
||||
void forEachWeakDef(Diagnostics& diag, void (^callback)(bool strongDef, uint32_t dataSegIndex, uint64_t dataSegOffset,
|
||||
uint64_t addend, const char* symbolName, bool& stop)) const;
|
||||
void forEachIndirectPointer(Diagnostics& diag, void (^handler)(uint64_t pointerAddress, bool bind, int bindLibOrdinal,
|
||||
const char* bindSymbolName, bool bindWeakImport, bool bindLazy, bool selfModifyingStub, bool& stop)) const;
|
||||
void forEachInterposingSection(Diagnostics& diag, void (^handler)(uint64_t vmOffset, uint64_t vmSize, bool& stop)) const;
|
||||
const void* content(uint64_t vmOffset);
|
||||
void forEachLocalReloc(void (^handler)(uint64_t runtimeOffset, bool& stop)) const;
|
||||
void forEachExternalReloc(void (^handler)(uint64_t runtimeOffset, int libOrdinal, const char* symbolName, bool& stop)) const;
|
||||
|
||||
const void* getRebaseOpcodes(uint32_t& size) const;
|
||||
const void* getBindOpcodes(uint32_t& size) const;
|
||||
const void* getLazyBindOpcodes(uint32_t& size) const;
|
||||
const void* getSplitSeg(uint32_t& size) const;
|
||||
uint64_t segAndOffsetToRuntimeOffset(uint8_t segIndex, uint64_t segOffset) const;
|
||||
bool hasLazyPointers(uint32_t& runtimeOffset, uint32_t& size) const;
|
||||
void forEachRebase(Diagnostics& diag, bool ignoreLazyPointer, void (^callback)(uint64_t runtimeOffset, bool& stop)) const;
|
||||
void forEachTextRebase(Diagnostics& diag, void (^callback)(uint64_t runtimeOffset, bool& stop)) const;
|
||||
void forEachBind(Diagnostics& diag, void (^callback)(uint64_t runtimeOffset, int libOrdinal, const char* symbolName,
|
||||
bool weakImport, bool lazyBind, uint64_t addend, bool& stop),
|
||||
void (^strongHandler)(const char* symbolName),
|
||||
void (^missingLazyBindHandler)()) const;
|
||||
void forEachChainedFixupTarget(Diagnostics& diag, void (^callback)(int libOrdinal, const char* symbolName, uint64_t addend, bool weakImport, bool& stop)) const;
|
||||
bool canHavePrecomputedDlopenClosure(const char* path, void (^failureReason)(const char*)) const;
|
||||
void forEachRebase(Diagnostics& diag, void (^handler)(const char* opcodeName, const LinkEditInfo& leInfo, const SegmentInfo segments[],
|
||||
bool segIndexSet, uint32_t pointerSize, uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, bool& stop)) const;
|
||||
void forEachBind(Diagnostics& diag, void (^handler)(const char* opcodeName, const LinkEditInfo& leInfo, const SegmentInfo segments[],
|
||||
bool segIndexSet, bool libraryOrdinalSet, uint32_t dylibCount, int libOrdinal,
|
||||
uint32_t pointerSize, uint8_t segmentIndex, uint64_t segmentOffset,
|
||||
uint8_t type, const char* symbolName, bool weakImport, bool lazyBind, uint64_t addend, bool& stop),
|
||||
void (^strongHandler)(const char* symbolName),
|
||||
void (^missingLazyBindHandler)()) const;
|
||||
bool canBePlacedInDyldCache(const char* path, void (^failureReason)(const char*)) const;
|
||||
uint32_t loadCommandsFreeSpace() const;
|
||||
|
||||
#if DEBUG
|
||||
void validateDyldCacheDylib(Diagnostics& diag, const char* path) const;
|
||||
#endif
|
||||
void withChainStarts(Diagnostics& diag, uint64_t startsStructOffsetHint, void (^callback)(const dyld_chained_starts_in_image*)) const;
|
||||
uint64_t chainStartsOffset() const;
|
||||
uint16_t chainedPointerFormat() const;
|
||||
bool hasUnalignedPointerFixups() const;
|
||||
|
||||
const MachOAnalyzer* remapIfZeroFill(Diagnostics& diag, const closure::FileSystem& fileSystem, closure::LoadedFileInfo& info) const;
|
||||
|
||||
struct ObjCInfo {
|
||||
uint32_t selRefCount;
|
||||
uint32_t classDefCount;
|
||||
uint32_t protocolDefCount;
|
||||
};
|
||||
ObjCInfo getObjCInfo() const;
|
||||
|
||||
// This optionally caches a list of sections for lookup
|
||||
struct SectionCache {
|
||||
private:
|
||||
SectionInfo buffer[2];
|
||||
|
||||
public:
|
||||
SectionCache(const MachOAnalyzer* ma) : ma(ma) { }
|
||||
|
||||
bool findSectionForVMAddr(uint64_t vmAddr, bool (^sectionHandler)(const SectionInfo& sectionInfo));
|
||||
|
||||
const MachOAnalyzer* ma = nullptr;
|
||||
dyld3::OverflowSafeArray<SectionInfo> sectionInfos = { buffer, sizeof(buffer) / sizeof(buffer[0]) };
|
||||
};
|
||||
|
||||
// Caches data useful for converting from raw data to VM addresses
|
||||
struct VMAddrConverter {
|
||||
uint64_t preferredLoadAddress = 0;
|
||||
intptr_t slide = 0;
|
||||
uint16_t chainedPointerFormat = 0;
|
||||
bool contentRebased = false;
|
||||
};
|
||||
|
||||
struct ObjCClassInfo {
|
||||
// These fields are all present on the objc_class_t struct
|
||||
uint64_t isaVMAddr = 0;
|
||||
uint64_t superclassVMAddr = 0;
|
||||
//uint64_t methodCacheBuckets;
|
||||
//uint64_t methodCacheProperties;
|
||||
uint64_t dataVMAddr = 0;
|
||||
|
||||
// This field is only present if this is a Swift object, ie, has the Swift
|
||||
// fast bits set
|
||||
uint32_t swiftClassFlags = 0;
|
||||
|
||||
// These are taken from the low bits of the dataVMAddr value
|
||||
bool isSwiftLegacy = false;
|
||||
bool isSwiftStable = false;
|
||||
|
||||
// Cache the data to convert vmAddr's
|
||||
MachOAnalyzer::VMAddrConverter vmAddrConverter;
|
||||
|
||||
// These are from the class_ro_t which data points to
|
||||
enum class ReadOnlyDataField {
|
||||
name,
|
||||
baseMethods
|
||||
};
|
||||
|
||||
uint64_t getReadOnlyDataField(ReadOnlyDataField field, uint32_t pointerSize) const;
|
||||
uint64_t nameVMAddr(uint32_t pointerSize) const {
|
||||
return getReadOnlyDataField(ReadOnlyDataField::name, pointerSize);
|
||||
}
|
||||
uint64_t baseMethodsVMAddr(uint32_t pointerSize) const {
|
||||
return getReadOnlyDataField(ReadOnlyDataField::baseMethods, pointerSize);
|
||||
}
|
||||
|
||||
// These are embedded in the Mach-O itself by the compiler
|
||||
enum FastDataBits {
|
||||
FAST_IS_SWIFT_LEGACY = 0x1,
|
||||
FAST_IS_SWIFT_STABLE = 0x2
|
||||
};
|
||||
|
||||
// These are embedded by the Swift compiler in the swiftClassFlags field
|
||||
enum SwiftClassFlags {
|
||||
isSwiftPreStableABI = 0x1
|
||||
};
|
||||
|
||||
// Note this is taken from the objc runtime
|
||||
bool isUnfixedBackwardDeployingStableSwift() const {
|
||||
// Only classes marked as Swift legacy need apply.
|
||||
if (!isSwiftLegacy) return false;
|
||||
|
||||
// Check the true legacy vs stable distinguisher.
|
||||
// The low bit of Swift's ClassFlags is SET for true legacy
|
||||
// and UNSET for stable pretending to be legacy.
|
||||
bool isActuallySwiftLegacy = (swiftClassFlags & isSwiftPreStableABI) != 0;
|
||||
return !isActuallySwiftLegacy;
|
||||
}
|
||||
};
|
||||
|
||||
struct ObjCImageInfo {
|
||||
uint32_t version;
|
||||
uint32_t flags;
|
||||
|
||||
// FIXME: Put this somewhere objc can see it.
|
||||
enum : uint32_t {
|
||||
dyldPreoptimized = 1 << 7
|
||||
};
|
||||
};
|
||||
|
||||
struct ObjCMethod {
|
||||
uint64_t nameVMAddr; // & SEL
|
||||
uint64_t typesVMAddr; // & const char *
|
||||
uint64_t impVMAddr; // & IMP
|
||||
|
||||
// We also need to know where the reference to the nameVMAddr was
|
||||
// This is so that we know how to rebind that location
|
||||
uint64_t nameLocationVMAddr;
|
||||
};
|
||||
|
||||
struct ObjCCategory {
|
||||
uint64_t nameVMAddr;
|
||||
uint64_t clsVMAddr;
|
||||
uint64_t instanceMethodsVMAddr;
|
||||
uint64_t classMethodsVMAddr;
|
||||
uint64_t protocolsVMAddr;
|
||||
uint64_t instancePropertiesVMAddr;
|
||||
};
|
||||
|
||||
struct ObjCProtocol {
|
||||
uint64_t isaVMAddr;
|
||||
uint64_t nameVMAddr;
|
||||
//uint64_t protocolsVMAddr;
|
||||
uint64_t instanceMethodsVMAddr;
|
||||
uint64_t classMethodsVMAddr;
|
||||
uint64_t optionalInstanceMethodsVMAddr;
|
||||
uint64_t optionalClassMethodsVMAddr;
|
||||
//uint64_t instancePropertiesVMAddr;
|
||||
//uint32_t size;
|
||||
//uint32_t flags;
|
||||
// Fields below this point are not always present on disk.
|
||||
//uint64_t extendedMethodTypesVMAddr;
|
||||
//uint64_t demangledNameVMAddr;
|
||||
//uint64_t classPropertiesVMAddr;
|
||||
|
||||
// Note this isn't in a protocol, but we use it in dyld to track if the protocol
|
||||
// is large enough to avoid a reallocation in objc.
|
||||
bool requiresObjCReallocation;
|
||||
};
|
||||
|
||||
enum class PrintableStringResult {
|
||||
CanPrint,
|
||||
FairPlayEncrypted,
|
||||
ProtectedSection,
|
||||
UnknownSection
|
||||
};
|
||||
|
||||
const char* getPrintableString(uint64_t stringVMAddr, PrintableStringResult& result,
|
||||
SectionCache* sectionCache = nullptr,
|
||||
bool (^sectionHandler)(const SectionInfo& sectionInfo) = nullptr) const;
|
||||
|
||||
void forEachObjCClass(Diagnostics& diag, bool contentRebased,
|
||||
void (^handler)(Diagnostics& diag, uint64_t classVMAddr,
|
||||
uint64_t classSuperclassVMAddr, uint64_t classDataVMAddr,
|
||||
const ObjCClassInfo& objcClass, bool isMetaClass)) const;
|
||||
|
||||
void forEachObjCCategory(Diagnostics& diag, bool contentRebased,
|
||||
void (^handler)(Diagnostics& diag, uint64_t categoryVMAddr,
|
||||
const dyld3::MachOAnalyzer::ObjCCategory& objcCategory)) const;
|
||||
|
||||
void forEachObjCProtocol(Diagnostics& diag, bool contentRebased,
|
||||
void (^handler)(Diagnostics& diag, uint64_t protocolVMAddr,
|
||||
const dyld3::MachOAnalyzer::ObjCProtocol& objCProtocol)) const;
|
||||
|
||||
// Walk a method list starting from its vmAddr.
|
||||
// Note, classes, categories, protocols, etc, all share the same method list struture so can all use this.
|
||||
void forEachObjCMethod(uint64_t methodListVMAddr, bool contentRebased,
|
||||
void (^handler)(uint64_t methodVMAddr, const ObjCMethod& method)) const;
|
||||
|
||||
void forEachObjCSelectorReference(Diagnostics& diag, bool contentRebased,
|
||||
void (^handler)(uint64_t selRefVMAddr, uint64_t selRefTargetVMAddr)) const;
|
||||
|
||||
void forEachObjCMethodName(void (^handler)(const char* methodName)) const;
|
||||
|
||||
bool hasObjCMessageReferences() const;
|
||||
|
||||
const ObjCImageInfo* objcImageInfo() const;
|
||||
|
||||
void forEachWeakDef(Diagnostics& diag, void (^handler)(const char* symbolName, uintptr_t imageOffset, bool isFromExportTrie)) const;
|
||||
|
||||
private:
|
||||
|
||||
struct SegmentStuff
|
||||
{
|
||||
uint64_t fileOffset;
|
||||
uint64_t fileSize;
|
||||
uint64_t writable : 1,
|
||||
executable : 1,
|
||||
textRelocsAllowed : 1, // segment supports text relocs (i386 only)
|
||||
segSize : 61;
|
||||
};
|
||||
|
||||
enum class Malformed { linkeditOrder, linkeditAlignment, linkeditPermissions, dyldInfoAndlocalRelocs, segmentOrder, textPermissions, executableData, codeSigAlignment };
|
||||
bool enforceFormat(Malformed) const;
|
||||
|
||||
const uint8_t* getContentForVMAddr(const LayoutInfo& info, uint64_t vmAddr) const;
|
||||
bool validLoadCommands(Diagnostics& diag, const char* path, size_t fileLen) const;
|
||||
bool validEmbeddedPaths(Diagnostics& diag, Platform platform, const char* path) const;
|
||||
bool validSegments(Diagnostics& diag, const char* path, size_t fileLen) const;
|
||||
bool validLinkedit(Diagnostics& diag, const char* path) const;
|
||||
bool validLinkeditLayout(Diagnostics& diag, const char* path) const;
|
||||
bool validRebaseInfo(Diagnostics& diag, const char* path) const;
|
||||
bool validBindInfo(Diagnostics& diag, const char* path) const;
|
||||
bool validMain(Diagnostics& diag, const char* path) const;
|
||||
bool validChainedFixupsInfo(Diagnostics& diag, const char* path) const;
|
||||
|
||||
bool invalidRebaseState(Diagnostics& diag, const char* opcodeName, const char* path, const LinkEditInfo& leInfo, const SegmentInfo segments[],
|
||||
bool segIndexSet, uint32_t pointerSize, uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type) const;
|
||||
bool invalidBindState(Diagnostics& diag, const char* opcodeName, const char* path, const LinkEditInfo& leInfo, const SegmentInfo segments[],
|
||||
bool segIndexSet, bool libraryOrdinalSet, uint32_t dylibCount, int libOrdinal, uint32_t pointerSize,
|
||||
uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, const char* symbolName) const;
|
||||
bool doLocalReloc(Diagnostics& diag, uint32_t r_address, bool& stop, void (^callback)(uint32_t dataSegIndex, uint64_t dataSegOffset, uint8_t type, bool& stop)) const;
|
||||
uint8_t relocPointerType() const;
|
||||
int libOrdinalFromDesc(uint16_t n_desc) const;
|
||||
bool doExternalReloc(Diagnostics& diag, uint32_t r_address, uint32_t r_symbolnum, LinkEditInfo& leInfo, bool& stop,
|
||||
void (^callback)(uint32_t dataSegIndex, uint64_t dataSegOffset, uint8_t type, int libOrdinal,
|
||||
uint64_t addend, const char* symbolName, bool weakImport, bool lazy, bool& stop)) const;
|
||||
|
||||
void getAllSegmentsInfos(Diagnostics& diag, SegmentInfo segments[]) const;
|
||||
bool segmentHasTextRelocs(uint32_t segIndex) const;
|
||||
uint64_t relocBaseAddress(const SegmentInfo segmentsInfos[], uint32_t segCount) const;
|
||||
bool segIndexAndOffsetForAddress(uint64_t addr, const SegmentInfo segmentsInfos[], uint32_t segCount, uint32_t& segIndex, uint64_t& segOffset) const;
|
||||
void parseOrgArm64eChainedFixups(Diagnostics& diag, void (^targetCount)(uint32_t totalTargets, bool& stop),
|
||||
void (^addTarget)(const LinkEditInfo& leInfo, const SegmentInfo segments[], bool libraryOrdinalSet, uint32_t dylibCount, int libOrdinal, uint8_t type, const char* symbolName, uint64_t addend, bool weakImport, bool& stop),
|
||||
void (^addChainStart)(const LinkEditInfo& leInfo, const SegmentInfo segments[], uint8_t segmentIndex, bool segIndexSet, uint64_t segmentOffset, uint16_t format, bool& stop)) const;
|
||||
bool contentIsRegularStub(const uint8_t* helperContent) const;
|
||||
uint64_t entryAddrFromThreadCmd(const thread_command* cmd) const;
|
||||
void recurseTrie(Diagnostics& diag, const uint8_t* const start, const uint8_t* p, const uint8_t* const end,
|
||||
OverflowSafeArray<char>& cummulativeString, int curStrOffset, bool& stop, MachOAnalyzer::ExportsCallback callback) const;
|
||||
void analyzeSegmentsLayout(uint64_t& vmSpace, bool& hasZeroFill) const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace dyld3
|
||||
|
||||
#endif /* MachOAnalyzer_h */
|
1205
src/dyld/dyld3/MachOFile.cpp
Normal file
1205
src/dyld/dyld3/MachOFile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
273
src/dyld/dyld3/MachOFile.h
Normal file
273
src/dyld/dyld3/MachOFile.h
Normal file
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MachOFile_h
|
||||
#define MachOFile_h
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "Diagnostics.h"
|
||||
#include "SupportedArchs.h"
|
||||
#include <mach-o/fixup-chains.h>
|
||||
#include <mach-o/loader.h>
|
||||
|
||||
// needed until dyld builds with a newer SDK
|
||||
#ifndef CPU_SUBTYPE_ARM64E
|
||||
#define CPU_SUBTYPE_ARM64E 2
|
||||
#endif
|
||||
#ifndef CPU_TYPE_ARM64_32
|
||||
#define CPU_TYPE_ARM64_32 0x0200000C
|
||||
#endif
|
||||
#ifndef CPU_SUBTYPE_ARM64_32_V8
|
||||
#define CPU_SUBTYPE_ARM64_32_V8 1
|
||||
#endif
|
||||
#ifndef BIND_OPCODE_THREADED
|
||||
#define BIND_OPCODE_THREADED 0xD0
|
||||
#endif
|
||||
#ifndef BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB
|
||||
#define BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB 0x00
|
||||
#endif
|
||||
#ifndef BIND_SUBOPCODE_THREADED_APPLY
|
||||
#define BIND_SUBOPCODE_THREADED_APPLY 0x01
|
||||
#endif
|
||||
#ifndef BIND_SPECIAL_DYLIB_WEAK_LOOKUP
|
||||
#define BIND_SPECIAL_DYLIB_WEAK_LOOKUP (-3)
|
||||
#endif
|
||||
#ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
|
||||
#define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
|
||||
#endif
|
||||
#ifndef SG_READ_ONLY
|
||||
#define SG_READ_ONLY 0x10
|
||||
#endif
|
||||
|
||||
#ifndef LC_DYLD_EXPORTS_TRIE
|
||||
#define LC_DYLD_EXPORTS_TRIE 0x80000033
|
||||
#endif
|
||||
#ifndef LC_DYLD_CHAINED_FIXUPS
|
||||
#define LC_DYLD_CHAINED_FIXUPS 0x80000034
|
||||
#endif
|
||||
|
||||
#ifndef S_INIT_FUNC_OFFSETS
|
||||
#define S_INIT_FUNC_OFFSETS 0x16
|
||||
#endif
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
|
||||
|
||||
/// Returns true if (addLHS + addRHS) > b, or if the add overflowed
|
||||
template<typename T>
|
||||
inline bool greaterThanAddOrOverflow(uint32_t addLHS, uint32_t addRHS, T b) {
|
||||
return (addLHS > b) || (addRHS > (b-addLHS));
|
||||
}
|
||||
|
||||
/// Returns true if (addLHS + addRHS) > b, or if the add overflowed
|
||||
template<typename T>
|
||||
inline bool greaterThanAddOrOverflow(uint64_t addLHS, uint64_t addRHS, T b) {
|
||||
return (addLHS > b) || (addRHS > (b-addLHS));
|
||||
}
|
||||
|
||||
|
||||
// Note, this should match PLATFORM_* values in <mach-o/loader.h>
|
||||
enum class Platform {
|
||||
unknown = 0,
|
||||
macOS = 1, // PLATFORM_MACOS
|
||||
iOS = 2, // PLATFORM_IOS
|
||||
tvOS = 3, // PLATFORM_TVOS
|
||||
watchOS = 4, // PLATFORM_WATCHOS
|
||||
bridgeOS = 5, // PLATFORM_BRIDGEOS
|
||||
iOSMac = 6, // PLATFORM_IOSMAC
|
||||
iOS_simulator = 7, // PLATFORM_IOSSIMULATOR
|
||||
tvOS_simulator = 8, // PLATFORM_TVOSSIMULATOR
|
||||
watchOS_simulator = 9, // PLATFORM_WATCHOSSIMULATOR
|
||||
driverKit = 10, // PLATFORM_DRIVERKIT
|
||||
};
|
||||
|
||||
struct MachOFile; // forward ref
|
||||
|
||||
// A prioritized list of architectures
|
||||
class VIS_HIDDEN GradedArchs {
|
||||
public:
|
||||
// never construct new ones - just use existing static instances
|
||||
GradedArchs() = delete;
|
||||
GradedArchs(const GradedArchs&) = delete;
|
||||
|
||||
static const GradedArchs& forCurrentOS(const MachOFile* mainExecutable);
|
||||
static const GradedArchs& forName(const char* archName, bool forMainExecutable = false);
|
||||
|
||||
int grade(uint32_t cputype, uint32_t cpusubtype) const;
|
||||
const char* name() const;
|
||||
|
||||
// pre-built lists for existing hardware
|
||||
static const GradedArchs i386; // 32-bit Mac
|
||||
static const GradedArchs x86_64; // older Mac
|
||||
static const GradedArchs x86_64h; // haswell Mac
|
||||
static const GradedArchs arm64; // A11 or earlier iPhone or iPad
|
||||
#if SUPPORT_ARCH_arm64e
|
||||
static const GradedArchs arm64e; // A12 or later iPhone or iPad
|
||||
static const GradedArchs arm64e_compat; // A12 running arm64 main executable
|
||||
#endif
|
||||
static const GradedArchs armv7k; // watch thru series 3
|
||||
static const GradedArchs armv7s; // deprecated
|
||||
static const GradedArchs armv7; // deprecated
|
||||
#if SUPPORT_ARCH_arm64_32
|
||||
static const GradedArchs arm64_32; // watch series 4 and later
|
||||
#endif
|
||||
|
||||
// private:
|
||||
// should be private, but compiler won't statically initialize static members above
|
||||
struct CpuGrade { uint32_t type; uint32_t subtype; uint32_t grade; };
|
||||
const CpuGrade _orderedCpuTypes[3]; // zero terminated
|
||||
};
|
||||
|
||||
|
||||
// A file read/mapped into memory
|
||||
struct VIS_HIDDEN FatFile : fat_header
|
||||
{
|
||||
static const FatFile* isFatFile(const void* fileContent);
|
||||
void forEachSlice(Diagnostics& diag, uint64_t fileLen, void (^callback)(uint32_t sliceCpuType, uint32_t sliceCpuSubType, const void* sliceStart, uint64_t sliceSize, bool& stop)) const;
|
||||
bool isFatFileWithSlice(Diagnostics& diag, uint64_t fileLen, const GradedArchs& archs, uint64_t& sliceOffset, uint64_t& sliceLen, bool& missingSlice) const;
|
||||
|
||||
private:
|
||||
bool isValidSlice(Diagnostics& diag, uint64_t fileLen, uint32_t sliceIndex,
|
||||
uint32_t sliceCpuType, uint32_t sliceCpuSubType, uint64_t sliceOffset, uint64_t sliceLen) const;
|
||||
};
|
||||
|
||||
|
||||
// A mach-o file read/mapped into memory
|
||||
// Only info from mach_header or load commands is accessible (no LINKEDIT info)
|
||||
struct VIS_HIDDEN MachOFile : mach_header
|
||||
{
|
||||
static const char* archName(uint32_t cputype, uint32_t cpusubtype);
|
||||
static const char* platformName(Platform platform);
|
||||
static uint32_t cpuTypeFromArchName(const char* archName);
|
||||
static uint32_t cpuSubtypeFromArchName(const char* archName);
|
||||
static void packedVersionToString(uint32_t packedVersion, char versionString[32]);
|
||||
static const char* currentArchName();
|
||||
static Platform currentPlatform();
|
||||
static uint64_t read_uleb128(Diagnostics& diag, const uint8_t*& p, const uint8_t* end);
|
||||
static int64_t read_sleb128(Diagnostics& diag, const uint8_t*& p, const uint8_t* end);
|
||||
static bool isSimulatorPlatform(Platform platform);
|
||||
static bool isSharedCacheEligiblePath(const char* path);
|
||||
|
||||
bool hasMachOMagic() const;
|
||||
bool isMachO(Diagnostics& diag, uint64_t fileSize) const;
|
||||
bool isDylib() const;
|
||||
bool isBundle() const;
|
||||
bool isMainExecutable() const;
|
||||
bool isDynamicExecutable() const;
|
||||
bool isStaticExecutable() const;
|
||||
bool isPreload() const;
|
||||
bool isPIE() const;
|
||||
bool isArch(const char* archName) const;
|
||||
const char* archName() const;
|
||||
bool is64() const;
|
||||
size_t machHeaderSize() const;
|
||||
uint32_t pointerSize() const;
|
||||
bool uses16KPages() const;
|
||||
bool supportsPlatform(Platform) const;
|
||||
bool isZippered() const;
|
||||
bool inDyldCache() const;
|
||||
bool isSimulatorBinary() const;
|
||||
bool getUuid(uuid_t uuid) const;
|
||||
bool hasWeakDefs() const;
|
||||
bool hasThreadLocalVariables() const;
|
||||
bool getDylibInstallName(const char** installName, uint32_t* compatVersion, uint32_t* currentVersion) const;
|
||||
void forEachSupportedPlatform(void (^callback)(Platform platform, uint32_t minOS, uint32_t sdk)) const;
|
||||
const char* installName() const; // returns nullptr is no install name
|
||||
void forEachDependentDylib(void (^callback)(const char* loadPath, bool isWeak, bool isReExport, bool isUpward, uint32_t compatVersion, uint32_t curVersion, bool& stop)) const;
|
||||
bool canBePlacedInDyldCache(const char* path, void (^failureReason)(const char*)) const;
|
||||
bool canBeFairPlayEncrypted() const;
|
||||
bool isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const;
|
||||
bool allowsAlternatePlatform() const;
|
||||
bool hasChainedFixups() const;
|
||||
void forDyldEnv(void (^callback)(const char* envVar, bool& stop)) const;
|
||||
bool enforceCompatVersion() const;
|
||||
|
||||
struct SegmentInfo
|
||||
{
|
||||
uint64_t fileOffset;
|
||||
uint64_t fileSize;
|
||||
uint64_t vmAddr;
|
||||
uint64_t vmSize;
|
||||
uint64_t sizeOfSections;
|
||||
const char* segName;
|
||||
uint32_t loadCommandOffset;
|
||||
uint32_t protections;
|
||||
uint32_t textRelocs : 1, // segment has text relocs (i386 only)
|
||||
readOnlyData : 1,
|
||||
isProtected : 1, // segment is protected
|
||||
segIndex : 13,
|
||||
p2align : 16;
|
||||
bool readable() const { return protections & VM_PROT_READ; }
|
||||
bool writable() const { return protections & VM_PROT_WRITE; }
|
||||
bool executable() const { return protections & VM_PROT_EXECUTE; }
|
||||
};
|
||||
|
||||
struct SectionInfo
|
||||
{
|
||||
SegmentInfo segInfo;
|
||||
uint64_t sectAddr;
|
||||
uint64_t sectSize;
|
||||
const char* sectName;
|
||||
uint32_t sectFileOffset;
|
||||
uint32_t sectFlags;
|
||||
uint32_t sectAlignP2;
|
||||
uint32_t reserved1;
|
||||
uint32_t reserved2;
|
||||
};
|
||||
|
||||
void forEachSegment(void (^callback)(const SegmentInfo& info, bool& stop)) const;
|
||||
void forEachSection(void (^callback)(const SectionInfo& sectInfo, bool malformedSectionRange, bool& stop)) const;
|
||||
|
||||
protected:
|
||||
bool hasMachOBigEndianMagic() const;
|
||||
void forEachLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& stop)) const;
|
||||
bool hasLoadCommand(uint32_t) const;
|
||||
|
||||
const encryption_info_command* findFairPlayEncryptionLoadCommand() const;
|
||||
|
||||
struct ArchInfo
|
||||
{
|
||||
const char* name;
|
||||
uint32_t cputype;
|
||||
uint32_t cpusubtype;
|
||||
};
|
||||
static const ArchInfo _s_archInfos[];
|
||||
|
||||
struct PlatformInfo
|
||||
{
|
||||
const char* name;
|
||||
Platform platform;
|
||||
uint32_t loadCommand;
|
||||
};
|
||||
static const PlatformInfo _s_platformInfos[];
|
||||
};
|
||||
|
||||
|
||||
} // namespace dyld3
|
||||
|
||||
#endif /* MachOFile_h */
|
1268
src/dyld/dyld3/MachOLoaded.cpp
Normal file
1268
src/dyld/dyld3/MachOLoaded.cpp
Normal file
File diff suppressed because it is too large
Load Diff
201
src/dyld/dyld3/MachOLoaded.h
Normal file
201
src/dyld/dyld3/MachOLoaded.h
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#ifndef MachOLoaded_h
|
||||
#define MachOLoaded_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Array.h"
|
||||
#include "MachOFile.h"
|
||||
|
||||
|
||||
class CacheBuilder;
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
|
||||
// A mach-o mapped into memory with zero-fill expansion
|
||||
// Can be used in dyld at runtime or during closure building
|
||||
struct VIS_HIDDEN MachOLoaded : public MachOFile
|
||||
{
|
||||
typedef const MachOLoaded* (^DependentToMachOLoaded)(const MachOLoaded* image, uint32_t depIndex);
|
||||
|
||||
// for dlsym()
|
||||
bool hasExportedSymbol(const char* symbolName, DependentToMachOLoaded finder, void** result,
|
||||
bool* resultPointsToInstructions) const;
|
||||
|
||||
// for DYLD_PRINT_SEGMENTS
|
||||
const char* segmentName(uint32_t segIndex) const;
|
||||
|
||||
// used to see if main executable overlaps shared region
|
||||
bool intersectsRange(uintptr_t start, uintptr_t length) const;
|
||||
|
||||
// for _dyld_get_image_slide()
|
||||
intptr_t getSlide() const;
|
||||
|
||||
// for dladdr()
|
||||
bool findClosestSymbol(uint64_t unSlidAddr, const char** symbolName, uint64_t* symbolUnslidAddr) const;
|
||||
|
||||
// for _dyld_find_unwind_sections()
|
||||
const void* findSectionContent(const char* segName, const char* sectName, uint64_t& size) const;
|
||||
|
||||
// used at runtime to validate loaded image matches closure
|
||||
void forEachCDHashOfCodeSignature(const void* codeSigStart, size_t codeSignLen,
|
||||
void (^callback)(const uint8_t cdHash[20])) const;
|
||||
|
||||
// used by DyldSharedCache to find closure
|
||||
static const uint8_t* trieWalk(Diagnostics& diag, const uint8_t* start, const uint8_t* end, const char* symbol);
|
||||
|
||||
// used by cache builder during error handling in chain bind processing
|
||||
const char* dependentDylibLoadPath(uint32_t depIndex) const;
|
||||
|
||||
// used by closure builder to find the offset and size of the trie.
|
||||
bool hasExportTrie(uint32_t& runtimeOffset, uint32_t& size) const;
|
||||
|
||||
// used by dyld/libdyld to apply fixups
|
||||
#if BUILDING_DYLD || BUILDING_LIBDYLD
|
||||
void fixupAllChainedFixups(Diagnostics& diag, const dyld_chained_starts_in_image* starts, uintptr_t slide,
|
||||
Array<const void*> bindTargets, void (^fixupLogger)(void* loc, void* newValue)) const;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// For use with new rebase/bind scheme were each fixup location on disk contains info on what
|
||||
// fix up it needs plus the offset to the next fixup.
|
||||
union ChainedFixupPointerOnDisk
|
||||
{
|
||||
union Arm64e {
|
||||
dyld_chained_ptr_arm64e_auth_rebase authRebase;
|
||||
dyld_chained_ptr_arm64e_auth_bind authBind;
|
||||
dyld_chained_ptr_arm64e_rebase rebase;
|
||||
dyld_chained_ptr_arm64e_bind bind;
|
||||
|
||||
uint64_t signExtendedAddend() const;
|
||||
uint64_t unpackTarget() const;
|
||||
const char* keyName() const;
|
||||
uint64_t signPointer(void* loc, uint64_t target) const;
|
||||
};
|
||||
|
||||
union Generic64 {
|
||||
dyld_chained_ptr_64_rebase rebase;
|
||||
dyld_chained_ptr_64_bind bind;
|
||||
|
||||
uint64_t signExtendedAddend() const;
|
||||
uint64_t unpackedTarget() const;
|
||||
};
|
||||
|
||||
union Generic32 {
|
||||
dyld_chained_ptr_32_rebase rebase;
|
||||
dyld_chained_ptr_32_bind bind;
|
||||
|
||||
uint64_t signExtendedAddend() const;
|
||||
};
|
||||
|
||||
typedef dyld_chained_ptr_32_cache_rebase Cache32;
|
||||
|
||||
uint64_t raw64;
|
||||
Arm64e arm64e;
|
||||
Generic64 generic64;
|
||||
|
||||
uint32_t raw32;
|
||||
Generic32 generic32;
|
||||
Cache32 cache32;
|
||||
|
||||
|
||||
bool isRebase(uint16_t pointerFormat, uint64_t preferedLoadAddress, uint64_t& targetRuntimeOffset) const;
|
||||
bool isBind(uint16_t pointerFormat, uint32_t& bindOrdinal) const;
|
||||
};
|
||||
|
||||
|
||||
struct LayoutInfo {
|
||||
uintptr_t slide;
|
||||
uintptr_t textUnslidVMAddr;
|
||||
uintptr_t linkeditUnslidVMAddr;
|
||||
uint32_t linkeditFileOffset;
|
||||
uint32_t linkeditFileSize;
|
||||
uint32_t linkeditSegIndex;
|
||||
};
|
||||
|
||||
struct LinkEditInfo
|
||||
{
|
||||
const dyld_info_command* dyldInfo;
|
||||
const linkedit_data_command* exportsTrie;
|
||||
const linkedit_data_command* chainedFixups;
|
||||
const symtab_command* symTab;
|
||||
const dysymtab_command* dynSymTab;
|
||||
const linkedit_data_command* splitSegInfo;
|
||||
const linkedit_data_command* functionStarts;
|
||||
const linkedit_data_command* dataInCode;
|
||||
const linkedit_data_command* codeSig;
|
||||
LayoutInfo layout;
|
||||
};
|
||||
void getLinkEditPointers(Diagnostics& diag, LinkEditInfo&) const;
|
||||
|
||||
// use by dyldinfo
|
||||
void forEachFixupInAllChains(Diagnostics& diag, const dyld_chained_starts_in_image* starts, bool notifyNonPointers,
|
||||
void (^callback)(ChainedFixupPointerOnDisk* fixupLocation, const dyld_chained_starts_in_segment* segInfo, bool& stop)) const;
|
||||
protected:
|
||||
friend CacheBuilder;
|
||||
|
||||
struct FoundSymbol {
|
||||
enum class Kind { headerOffset, absolute, resolverOffset };
|
||||
Kind kind;
|
||||
bool isThreadLocal;
|
||||
bool isWeakDef;
|
||||
const MachOLoaded* foundInDylib;
|
||||
uint64_t value;
|
||||
uint32_t resolverFuncOffset;
|
||||
const char* foundSymbolName;
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
friend CacheBuilder;
|
||||
|
||||
bool findExportedSymbol(Diagnostics& diag, const char* symbolName, bool weakImport, FoundSymbol& foundInfo, DependentToMachOLoaded finder) const;
|
||||
|
||||
void getLinkEditLoadCommands(Diagnostics& diag, LinkEditInfo& result) const;
|
||||
void getLayoutInfo(LayoutInfo&) const;
|
||||
const uint8_t* getLinkEditContent(const LayoutInfo& info, uint32_t fileOffset) const;
|
||||
const uint8_t* getExportsTrie(const LinkEditInfo& info, uint64_t& trieSize) const;
|
||||
void forEachGlobalSymbol(Diagnostics& diag, void (^callback)(const char* symbolName, uint64_t n_value, uint8_t n_type, uint8_t n_sect, uint16_t n_desc, bool& stop)) const;
|
||||
void forEachLocalSymbol(Diagnostics& diag, void (^callback)(const char* symbolName, uint64_t n_value, uint8_t n_type, uint8_t n_sect, uint16_t n_desc, bool& stop)) const;
|
||||
uint32_t dependentDylibCount() const;
|
||||
bool findClosestFunctionStart(uint64_t address, uint64_t* functionStartAddress) const;
|
||||
|
||||
// This calls the callback for all code directories required for a given platform/binary combination.
|
||||
// On watchOS main executables this is all cd hashes.
|
||||
// On watchOS dylibs this is only the single cd hash we need (by rank defined by dyld, not the kernel).
|
||||
// On all other platforms this always returns a single best cd hash (ranked to match the kernel).
|
||||
// Note the callback parameter is really a CS_CodeDirectory.
|
||||
void forEachCodeDirectoryBlob(const void* codeSigStart, size_t codeSignLen, void (^callback)(const void* cd)) const;
|
||||
bool walkChain(Diagnostics& diag, const dyld_chained_starts_in_segment* segInfo, uint32_t pageIndex, uint16_t offsetInPage,
|
||||
bool notifyNonPointers, void (^handler)(ChainedFixupPointerOnDisk* fixupLocation, const dyld_chained_starts_in_segment* segInfo, bool& stop)) const;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace dyld3
|
||||
|
||||
#endif /* MachOLoaded_h */
|
431
src/dyld/dyld3/Map.h
Normal file
431
src/dyld/dyld3/Map.h
Normal file
@ -0,0 +1,431 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#ifndef Map_h
|
||||
#define Map_h
|
||||
|
||||
#include "Array.h"
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Hash {
|
||||
static size_t hash(const T&);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Equal {
|
||||
static bool equal(const T&a, const T& b);
|
||||
};
|
||||
|
||||
template<typename KeyT, typename ValueT, class GetHash = Hash<KeyT>, class IsEqual = Equal<KeyT>>
|
||||
class Map {
|
||||
typedef std::pair<KeyT, ValueT> NodeT;
|
||||
typedef NodeT* iterator;
|
||||
typedef const NodeT* const_iterator;
|
||||
|
||||
enum : size_t {
|
||||
SentinelHash = (size_t)-1
|
||||
};
|
||||
|
||||
public:
|
||||
Map() {
|
||||
// Keep the hash buffer about 75% full
|
||||
nextHashBufferGrowth = 768;
|
||||
hashBufferUseCount = 0;
|
||||
hashBuffer.reserve(1024);
|
||||
for (size_t i = 0; i != 1024; ++i) {
|
||||
hashBuffer.push_back(SentinelHash);
|
||||
}
|
||||
nodeBuffer.reserve(1024);
|
||||
}
|
||||
|
||||
iterator find(const KeyT& key) {
|
||||
// Find the index to look up in the hash buffer
|
||||
size_t hashIndex = GetHash::hash(key) & (hashBuffer.count() - 1);
|
||||
|
||||
// Note we'll use a quadratic probe to look past identical hashes until we find our node or a sentinel
|
||||
size_t probeAmount = 1;
|
||||
while (true) {
|
||||
size_t nodeBufferIndex = hashBuffer[hashIndex];
|
||||
|
||||
if (nodeBufferIndex == SentinelHash) {
|
||||
// This node is unused, so we don't have this element
|
||||
return end();
|
||||
}
|
||||
|
||||
// If that hash is in use, then check if that node is actually the one we are trying to find
|
||||
if (IsEqual::equal(nodeBuffer[nodeBufferIndex].first, key)) {
|
||||
// Keys match so we found this element
|
||||
return &nodeBuffer[nodeBufferIndex];
|
||||
}
|
||||
|
||||
// We didn't find this node, so try with a later one
|
||||
hashIndex += probeAmount;
|
||||
hashIndex &= (hashBuffer.count() - 1);
|
||||
++probeAmount;
|
||||
}
|
||||
|
||||
assert(0 && "unreachable");
|
||||
}
|
||||
|
||||
const_iterator find(const KeyT& key) const {
|
||||
// Find the index to look up in the hash buffer
|
||||
size_t hashIndex = GetHash::hash(key) & (hashBuffer.count() - 1);
|
||||
|
||||
// Note we'll use a quadratic probe to look past identical hashes until we find our node or a sentinel
|
||||
size_t probeAmount = 1;
|
||||
while (true) {
|
||||
size_t nodeBufferIndex = hashBuffer[hashIndex];
|
||||
|
||||
if (nodeBufferIndex == SentinelHash) {
|
||||
// This node is unused, so we don't have this element
|
||||
return end();
|
||||
}
|
||||
|
||||
// If that hash is in use, then check if that node is actually the one we are trying to find
|
||||
if (IsEqual::equal(nodeBuffer[nodeBufferIndex].first, key)) {
|
||||
// Keys match so we found this element
|
||||
return &nodeBuffer[nodeBufferIndex];
|
||||
}
|
||||
|
||||
// We didn't find this node, so try with a later one
|
||||
hashIndex += probeAmount;
|
||||
hashIndex &= (hashBuffer.count() - 1);
|
||||
++probeAmount;
|
||||
}
|
||||
|
||||
assert(0 && "unreachable");
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
return nodeBuffer.begin();
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return nodeBuffer.end();
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return nodeBuffer.begin();
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return nodeBuffer.end();
|
||||
}
|
||||
|
||||
const Array<NodeT>& array() const {
|
||||
return nodeBuffer;
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(NodeT&& v) {
|
||||
// First see if we have enough space. We don't want the hash buffer to get too full.
|
||||
if (hashBufferUseCount == nextHashBufferGrowth) {
|
||||
// Grow and rehash everything.
|
||||
size_t newHashTableSize = hashBuffer.count() * 2;
|
||||
nextHashBufferGrowth *= 2;
|
||||
|
||||
dyld3::OverflowSafeArray<size_t> newHashBuffer;
|
||||
newHashBuffer.reserve(newHashTableSize);
|
||||
for (size_t i = 0; i != newHashTableSize; ++i) {
|
||||
newHashBuffer.push_back(SentinelHash);
|
||||
}
|
||||
|
||||
// Walk the existing nodes trying to populate the new hash buffer and looking for collisions
|
||||
for (size_t i = 0; i != nodeBuffer.count(); ++i) {
|
||||
const KeyT& key = nodeBuffer[i].first;
|
||||
size_t newHashIndex = GetHash::hash(key) & (newHashBuffer.count() - 1);
|
||||
|
||||
// Note we'll use a quadratic probe to look past identical hashes until we find our node or a sentinel
|
||||
size_t probeAmount = 1;
|
||||
while (true) {
|
||||
size_t newNodeBufferIndex = newHashBuffer[newHashIndex];
|
||||
|
||||
if (newNodeBufferIndex == SentinelHash) {
|
||||
// This node is unused, so we don't have this element. Lets add it
|
||||
newHashBuffer[newHashIndex] = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't bother checking for matching keys here. We know we are adding elements with different keys
|
||||
// Just probe to find the next sentinel
|
||||
|
||||
// We didn't find this node, so try with a later one
|
||||
newHashIndex += probeAmount;
|
||||
newHashIndex &= (newHashBuffer.count() - 1);
|
||||
++probeAmount;
|
||||
}
|
||||
}
|
||||
|
||||
// Use the new buffer
|
||||
hashBuffer = std::move(newHashBuffer);
|
||||
}
|
||||
|
||||
// Find the index to look up in the hash buffer
|
||||
size_t hashIndex = GetHash::hash(v.first) & (hashBuffer.count() - 1);
|
||||
|
||||
// Note we'll use a quadratic probe to look past identical hashes until we find our node or a sentinel
|
||||
size_t probeAmount = 1;
|
||||
while (true) {
|
||||
size_t nodeBufferIndex = hashBuffer[hashIndex];
|
||||
|
||||
if (nodeBufferIndex == SentinelHash) {
|
||||
// This node is unused, so we don't have this element. Lets add it
|
||||
hashBuffer[hashIndex] = nodeBuffer.count();
|
||||
++hashBufferUseCount;
|
||||
nodeBuffer.push_back(v);
|
||||
return { &nodeBuffer.back(), true };
|
||||
}
|
||||
|
||||
// If that hash is in use, then check if that node is actually the one we are trying to insert
|
||||
if (IsEqual::equal(nodeBuffer[nodeBufferIndex].first, v.first)) {
|
||||
// Keys match. We already have this element
|
||||
return { &nodeBuffer[nodeBufferIndex], false };
|
||||
}
|
||||
|
||||
// We didn't find this node, so try with a later one
|
||||
hashIndex += probeAmount;
|
||||
hashIndex &= (hashBuffer.count() - 1);
|
||||
++probeAmount;
|
||||
}
|
||||
|
||||
assert(0 && "unreachable");
|
||||
}
|
||||
|
||||
|
||||
ValueT& operator[](KeyT idx) {
|
||||
auto itAndInserted = insert({ idx, ValueT() });
|
||||
return itAndInserted.first->second;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t nextHashBufferGrowth;
|
||||
size_t hashBufferUseCount;
|
||||
dyld3::OverflowSafeArray<size_t> hashBuffer;
|
||||
dyld3::OverflowSafeArray<NodeT> nodeBuffer;
|
||||
};
|
||||
|
||||
template<typename KeyT, typename ValueT, class GetHash = Hash<KeyT>, class IsEqual = Equal<KeyT>>
|
||||
class MultiMap {
|
||||
|
||||
struct NextNode {
|
||||
size_t isDuplicateHead : 1;
|
||||
size_t isDuplicateEntry : 1;
|
||||
size_t isDuplicateTail : 1;
|
||||
size_t nextIndex : 29;
|
||||
|
||||
bool hasAnyDuplicates() const {
|
||||
return isDuplicateHead || isDuplicateEntry || isDuplicateTail;
|
||||
}
|
||||
|
||||
bool hasMoreDuplicates() const {
|
||||
return isDuplicateHead || isDuplicateEntry;
|
||||
}
|
||||
|
||||
static NextNode makeNoDuplicates() {
|
||||
return { 0, 0, 0, 0 };
|
||||
}
|
||||
|
||||
static NextNode makeDuplicateTailNode() {
|
||||
return { 0, 0, 1, 0 };
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(NextNode) == sizeof(size_t), "Invalid size");
|
||||
|
||||
typedef std::pair<KeyT, ValueT> NodeT;
|
||||
typedef std::tuple<KeyT, ValueT, NextNode> NodeEntryT;
|
||||
typedef NodeT* iterator;
|
||||
typedef const NodeT* const_iterator;
|
||||
|
||||
enum : size_t {
|
||||
SentinelHash = (size_t)-1
|
||||
};
|
||||
|
||||
public:
|
||||
MultiMap() {
|
||||
// Keep the hash buffer about 75% full
|
||||
nextHashBufferGrowth = 768;
|
||||
hashBufferUseCount = 0;
|
||||
hashBuffer.reserve(1024);
|
||||
for (size_t i = 0; i != 1024; ++i) {
|
||||
hashBuffer.push_back(SentinelHash);
|
||||
}
|
||||
nodeBuffer.reserve(1024);
|
||||
}
|
||||
|
||||
void forEachEntry(void (^handler)(const KeyT& key, const ValueT** values, uint64_t valuesCount)) const {
|
||||
// Walk the top level nodes, skipping dupes
|
||||
for (const NodeEntryT& headNode : nodeBuffer) {
|
||||
NextNode nextNode = std::get<2>(headNode);
|
||||
if (!nextNode.hasAnyDuplicates()) {
|
||||
const ValueT* value[1] = { &std::get<1>(headNode) };
|
||||
handler(std::get<0>(headNode), value, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!nextNode.isDuplicateHead)
|
||||
continue;
|
||||
|
||||
// This is the head of a list. Work out how long the list is
|
||||
uint64_t valuesCount = 1;
|
||||
while (std::get<2>(nodeBuffer[nextNode.nextIndex]).hasMoreDuplicates()) {
|
||||
nextNode = std::get<2>(nodeBuffer[nextNode.nextIndex]);
|
||||
++valuesCount;
|
||||
}
|
||||
|
||||
// Add one more for the last node
|
||||
++valuesCount;
|
||||
|
||||
// Now make an array with that many value for the callback
|
||||
const ValueT* values[valuesCount];
|
||||
// Copy in the head
|
||||
values[0] = &std::get<1>(headNode);
|
||||
|
||||
// And copy the remainder
|
||||
nextNode = std::get<2>(headNode);
|
||||
valuesCount = 1;
|
||||
while (std::get<2>(nodeBuffer[nextNode.nextIndex]).hasMoreDuplicates()) {
|
||||
values[valuesCount] = &std::get<1>(nodeBuffer[nextNode.nextIndex]);
|
||||
nextNode = std::get<2>(nodeBuffer[nextNode.nextIndex]);
|
||||
++valuesCount;
|
||||
}
|
||||
|
||||
// Add in the last node
|
||||
values[valuesCount] = &std::get<1>(nodeBuffer[nextNode.nextIndex]);
|
||||
++valuesCount;
|
||||
|
||||
// Finally call the handler with a whole array of values.
|
||||
handler(std::get<0>(headNode), values, valuesCount);
|
||||
}
|
||||
}
|
||||
|
||||
void insert(NodeT&& v) {
|
||||
// First see if we have enough space. We don't want the hash buffer to get too full.
|
||||
if (hashBufferUseCount == nextHashBufferGrowth) {
|
||||
// Grow and rehash everything.
|
||||
size_t newHashTableSize = hashBuffer.count() * 2;
|
||||
nextHashBufferGrowth *= 2;
|
||||
|
||||
dyld3::OverflowSafeArray<size_t> newHashBuffer;
|
||||
newHashBuffer.reserve(newHashTableSize);
|
||||
for (size_t i = 0; i != newHashTableSize; ++i) {
|
||||
newHashBuffer.push_back(SentinelHash);
|
||||
}
|
||||
|
||||
// Walk the existing nodes trying to populate the new hash buffer and looking for collisions
|
||||
for (size_t i = 0; i != nodeBuffer.count(); ++i) {
|
||||
// Skip nodes which are not the head of the list
|
||||
// They aren't moving the buffer anyway
|
||||
NextNode nextNode = std::get<2>(nodeBuffer[i]);
|
||||
if (nextNode.isDuplicateEntry || nextNode.isDuplicateTail)
|
||||
continue;
|
||||
const KeyT& key = std::get<0>(nodeBuffer[i]);
|
||||
size_t newHashIndex = GetHash::hash(key) & (newHashBuffer.count() - 1);
|
||||
|
||||
// Note we'll use a quadratic probe to look past identical hashes until we find our node or a sentinel
|
||||
size_t probeAmount = 1;
|
||||
while (true) {
|
||||
size_t newNodeBufferIndex = newHashBuffer[newHashIndex];
|
||||
|
||||
if (newNodeBufferIndex == SentinelHash) {
|
||||
// This node is unused, so we don't have this element. Lets add it
|
||||
newHashBuffer[newHashIndex] = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't bother checking for matching keys here. We know we are adding elements with different keys
|
||||
// Just probe to find the next sentinel
|
||||
|
||||
// We didn't find this node, so try with a later one
|
||||
newHashIndex += probeAmount;
|
||||
newHashIndex &= (newHashBuffer.count() - 1);
|
||||
++probeAmount;
|
||||
}
|
||||
}
|
||||
|
||||
// Use the new buffer
|
||||
hashBuffer = std::move(newHashBuffer);
|
||||
}
|
||||
|
||||
// Find the index to look up in the hash buffer
|
||||
size_t hashIndex = GetHash::hash(v.first) & (hashBuffer.count() - 1);
|
||||
|
||||
// Note we'll use a quadratic probe to look past identical hashes until we find our node or a sentinel
|
||||
size_t probeAmount = 1;
|
||||
while (true) {
|
||||
size_t nodeBufferIndex = hashBuffer[hashIndex];
|
||||
|
||||
if (nodeBufferIndex == SentinelHash) {
|
||||
// This node is unused, so we don't have this element. Lets add it
|
||||
hashBuffer[hashIndex] = nodeBuffer.count();
|
||||
++hashBufferUseCount;
|
||||
nodeBuffer.push_back({ v.first, v.second, NextNode::makeNoDuplicates() } );
|
||||
return;
|
||||
}
|
||||
|
||||
// If that hash is in use, then check if that node is actually the one we are trying to insert
|
||||
if (IsEqual::equal(std::get<0>(nodeBuffer[nodeBufferIndex]), v.first)) {
|
||||
// Keys match. We already have this element
|
||||
// But this is a multimap so add the new element too
|
||||
// Walk from this node to find the end of the chain
|
||||
while (std::get<2>(nodeBuffer[nodeBufferIndex]).hasMoreDuplicates()) {
|
||||
nodeBufferIndex = std::get<2>(nodeBuffer[nodeBufferIndex]).nextIndex;
|
||||
}
|
||||
NextNode& tailNode = std::get<2>(nodeBuffer[nodeBufferIndex]);
|
||||
if (!tailNode.hasAnyDuplicates()) {
|
||||
// If the previous node has no duplicates then its now the new head of a list
|
||||
tailNode.isDuplicateHead = 1;
|
||||
tailNode.nextIndex = nodeBuffer.count();
|
||||
} else {
|
||||
// This must be a tail node. Update it to be an entry node
|
||||
assert(tailNode.isDuplicateTail);
|
||||
tailNode.isDuplicateTail = 0;
|
||||
tailNode.isDuplicateEntry = 1;
|
||||
tailNode.nextIndex = nodeBuffer.count();
|
||||
}
|
||||
//.nextIndex = nodeBuffer.count();
|
||||
nodeBuffer.push_back({ v.first, v.second, NextNode::makeDuplicateTailNode() } );
|
||||
return;
|
||||
}
|
||||
|
||||
// We didn't find this node, so try with a later one
|
||||
hashIndex += probeAmount;
|
||||
hashIndex &= (hashBuffer.count() - 1);
|
||||
++probeAmount;
|
||||
}
|
||||
|
||||
assert(0 && "unreachable");
|
||||
}
|
||||
|
||||
private:
|
||||
size_t nextHashBufferGrowth;
|
||||
size_t hashBufferUseCount;
|
||||
dyld3::OverflowSafeArray<size_t> hashBuffer;
|
||||
dyld3::OverflowSafeArray<NodeEntryT> nodeBuffer;
|
||||
};
|
||||
|
||||
} // namespace dyld3
|
||||
|
||||
#endif /* Map_h */
|
555
src/dyld/dyld3/PathOverrides.cpp
Normal file
555
src/dyld/dyld3/PathOverrides.cpp
Normal file
@ -0,0 +1,555 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <mach/mach.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sys/errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
#include "PathOverrides.h"
|
||||
|
||||
|
||||
|
||||
namespace dyld3 {
|
||||
namespace closure {
|
||||
|
||||
#if BUILDING_LIBDYLD
|
||||
PathOverrides gPathOverrides;
|
||||
#endif
|
||||
|
||||
|
||||
// based on ANSI-C strstr()
|
||||
static const char* strrstr(const char* str, const char* sub)
|
||||
{
|
||||
const size_t sublen = strlen(sub);
|
||||
for(const char* p = &str[strlen(str)]; p != str; --p) {
|
||||
if ( strncmp(p, sub, sublen) == 0 )
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void PathOverrides::setFallbackPathHandling(FallbackPathMode mode)
|
||||
{
|
||||
_fallbackPathMode = mode;
|
||||
}
|
||||
|
||||
void PathOverrides::setEnvVars(const char* envp[], const MachOFile* mainExe, const char* mainExePath)
|
||||
{
|
||||
for (const char** p = envp; *p != NULL; p++) {
|
||||
addEnvVar(*p, false);
|
||||
}
|
||||
if ( mainExe != nullptr )
|
||||
setMainExecutable(mainExe, mainExePath);
|
||||
}
|
||||
|
||||
void PathOverrides::setMainExecutable(const dyld3::MachOFile* mainExe, const char* mainExePath)
|
||||
{
|
||||
assert(mainExe != nullptr);
|
||||
assert(mainExe->isMainExecutable());
|
||||
// process any LC_DYLD_ENVIRONMENT load commands in main executable
|
||||
mainExe->forDyldEnv(^(const char* envVar, bool& stop) {
|
||||
addEnvVar(envVar, true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
#if !BUILDING_LIBDYLD
|
||||
// libdyld is never unloaded
|
||||
PathOverrides::~PathOverrides()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void PathOverrides::forEachInsertedDylib(void (^handler)(const char* dylibPath, bool &stop)) const
|
||||
{
|
||||
if ( _insertedDylibs != nullptr ) {
|
||||
forEachInColonList(_insertedDylibs, nullptr, ^(const char* path, bool &stop) {
|
||||
handler(path, stop);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void PathOverrides::handleEnvVar(const char* key, const char* value, void (^handler)(const char* envVar)) const
|
||||
{
|
||||
if ( value == nullptr )
|
||||
return;
|
||||
size_t allocSize = strlen(key) + strlen(value) + 2;
|
||||
char buffer[allocSize];
|
||||
strlcpy(buffer, key, allocSize);
|
||||
strlcat(buffer, "=", allocSize);
|
||||
strlcat(buffer, value, allocSize);
|
||||
handler(buffer);
|
||||
}
|
||||
|
||||
// Note, this method only returns variables set on the environment, not those from the load command
|
||||
void PathOverrides::forEachEnvVar(void (^handler)(const char* envVar)) const
|
||||
{
|
||||
handleEnvVar("DYLD_LIBRARY_PATH", _dylibPathOverridesEnv, handler);
|
||||
handleEnvVar("DYLD_FRAMEWORK_PATH", _frameworkPathOverridesEnv, handler);
|
||||
handleEnvVar("DYLD_FALLBACK_FRAMEWORK_PATH", _frameworkPathFallbacksEnv, handler);
|
||||
handleEnvVar("DYLD_FALLBACK_LIBRARY_PATH", _dylibPathFallbacksEnv, handler);
|
||||
handleEnvVar("DYLD_INSERT_LIBRARIES", _insertedDylibs, handler);
|
||||
handleEnvVar("DYLD_IMAGE_SUFFIX", _imageSuffix, handler);
|
||||
handleEnvVar("DYLD_ROOT_PATH", _rootPath, handler);
|
||||
}
|
||||
|
||||
// Note, this method only returns variables set on the executable load command, not those from the environment
|
||||
void PathOverrides::forEachExecutableEnvVar(void (^handler)(const char* envVar)) const
|
||||
{
|
||||
handleEnvVar("DYLD_LIBRARY_PATH", _dylibPathOverridesExeLC, handler);
|
||||
handleEnvVar("DYLD_FRAMEWORK_PATH", _frameworkPathOverridesExeLC, handler);
|
||||
handleEnvVar("DYLD_FALLBACK_FRAMEWORK_PATH", _frameworkPathFallbacksExeLC, handler);
|
||||
handleEnvVar("DYLD_FALLBACK_LIBRARY_PATH", _dylibPathFallbacksExeLC, handler);
|
||||
}
|
||||
|
||||
const char* PathOverrides::addString(const char* str)
|
||||
{
|
||||
if ( _pathPool == nullptr )
|
||||
_pathPool = PathPool::allocate();
|
||||
return _pathPool->add(str);
|
||||
}
|
||||
|
||||
void PathOverrides::setString(const char*& var, const char* value)
|
||||
{
|
||||
if ( var == nullptr ) {
|
||||
var = addString(value);
|
||||
return;
|
||||
}
|
||||
// string already in use, build new appended string
|
||||
char tmp[strlen(var)+strlen(value)+2];
|
||||
strcpy(tmp, var);
|
||||
strcat(tmp, ":");
|
||||
strcat(tmp, value);
|
||||
var = addString(tmp);
|
||||
}
|
||||
|
||||
void PathOverrides::addEnvVar(const char* keyEqualsValue, bool forExecutable)
|
||||
{
|
||||
// We have to make a copy of the env vars because the dyld
|
||||
// semantics is that the env vars are only looked at once
|
||||
// at launch (using setenv() at runtime does not change dyld behavior).
|
||||
const char* equals = strchr(keyEqualsValue, '=');
|
||||
if ( equals != NULL ) {
|
||||
if ( strncmp(keyEqualsValue, "DYLD_LIBRARY_PATH", 17) == 0 ) {
|
||||
setString(forExecutable ? _dylibPathOverridesExeLC : _dylibPathOverridesEnv, &keyEqualsValue[18]);
|
||||
}
|
||||
else if ( strncmp(keyEqualsValue, "DYLD_FRAMEWORK_PATH", 19) == 0 ) {
|
||||
setString(forExecutable ? _frameworkPathOverridesExeLC : _frameworkPathOverridesEnv, &keyEqualsValue[20]);
|
||||
}
|
||||
else if ( strncmp(keyEqualsValue, "DYLD_FALLBACK_FRAMEWORK_PATH", 28) == 0 ) {
|
||||
setString(forExecutable ? _frameworkPathFallbacksExeLC : _frameworkPathFallbacksEnv, &keyEqualsValue[29]);
|
||||
}
|
||||
else if ( strncmp(keyEqualsValue, "DYLD_FALLBACK_LIBRARY_PATH", 26) == 0 ) {
|
||||
setString(forExecutable ? _dylibPathFallbacksExeLC : _dylibPathFallbacksEnv, &keyEqualsValue[27]);
|
||||
}
|
||||
else if ( strncmp(keyEqualsValue, "DYLD_INSERT_LIBRARIES", 21) == 0 ) {
|
||||
setString(_insertedDylibs, &keyEqualsValue[22]);
|
||||
}
|
||||
else if ( strncmp(keyEqualsValue, "DYLD_IMAGE_SUFFIX", 17) == 0 ) {
|
||||
setString(_imageSuffix, &keyEqualsValue[18]);
|
||||
}
|
||||
else if ( strncmp(keyEqualsValue, "DYLD_ROOT_PATH", 14) == 0 ) {
|
||||
setString(_rootPath, &keyEqualsValue[15]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PathOverrides::forEachInColonList(const char* list1, const char* list2, void (^handler)(const char* path, bool& stop))
|
||||
{
|
||||
for (const char* list : { list1, list2 }) {
|
||||
if (list == nullptr)
|
||||
continue;
|
||||
char buffer[strlen(list)+1];
|
||||
const char* t = list;
|
||||
bool stop = false;
|
||||
for (const char* s=list; *s != '\0'; ++s) {
|
||||
if (*s != ':')
|
||||
continue;
|
||||
size_t len = s - t;
|
||||
memcpy(buffer, t, len);
|
||||
buffer[len] = '\0';
|
||||
handler(buffer, stop);
|
||||
if ( stop )
|
||||
return;
|
||||
t = s+1;
|
||||
}
|
||||
handler(t, stop);
|
||||
if (stop)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PathOverrides::forEachDylibFallback(Platform platform, void (^handler)(const char* fallbackDir, bool& stop)) const
|
||||
{
|
||||
__block bool stop = false;
|
||||
if ( (_dylibPathFallbacksEnv != nullptr) || (_dylibPathFallbacksExeLC != nullptr) ) {
|
||||
forEachInColonList(_dylibPathFallbacksEnv, _dylibPathFallbacksExeLC, ^(const char* pth, bool& innerStop) {
|
||||
handler(pth, innerStop);
|
||||
if ( innerStop )
|
||||
stop = true;
|
||||
});
|
||||
}
|
||||
else {
|
||||
switch ( platform ) {
|
||||
case Platform::macOS:
|
||||
switch ( _fallbackPathMode ) {
|
||||
case FallbackPathMode::classic:
|
||||
// "$HOME/lib"
|
||||
handler("/usr/local/lib", stop);
|
||||
if ( stop )
|
||||
break;
|
||||
[[clang::fallthrough]];
|
||||
case FallbackPathMode::restricted:
|
||||
handler("/usr/lib", stop);
|
||||
break;
|
||||
case FallbackPathMode::none:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Platform::iOS:
|
||||
case Platform::watchOS:
|
||||
case Platform::tvOS:
|
||||
case Platform::bridgeOS:
|
||||
case Platform::driverKit:
|
||||
case Platform::unknown:
|
||||
if ( _fallbackPathMode != FallbackPathMode::none ) {
|
||||
handler("/usr/local/lib", stop);
|
||||
if ( stop )
|
||||
break;
|
||||
}
|
||||
// fall into /usr/lib case
|
||||
[[clang::fallthrough]];
|
||||
case Platform::iOSMac:
|
||||
case Platform::iOS_simulator:
|
||||
case Platform::watchOS_simulator:
|
||||
case Platform::tvOS_simulator:
|
||||
if ( _fallbackPathMode != FallbackPathMode::none )
|
||||
handler("/usr/lib", stop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PathOverrides::forEachFrameworkFallback(Platform platform, void (^handler)(const char* fallbackDir, bool& stop)) const
|
||||
{
|
||||
__block bool stop = false;
|
||||
if ( (_frameworkPathFallbacksEnv != nullptr) || (_frameworkPathFallbacksExeLC != nullptr) ) {
|
||||
forEachInColonList(_frameworkPathFallbacksEnv, _frameworkPathFallbacksExeLC, ^(const char* pth, bool& innerStop) {
|
||||
handler(pth, innerStop);
|
||||
if ( innerStop )
|
||||
stop = true;
|
||||
});
|
||||
}
|
||||
else {
|
||||
switch ( platform ) {
|
||||
case Platform::macOS:
|
||||
switch ( _fallbackPathMode ) {
|
||||
case FallbackPathMode::classic:
|
||||
// "$HOME/Library/Frameworks"
|
||||
handler("/Library/Frameworks", stop);
|
||||
if ( stop )
|
||||
break;
|
||||
// "/Network/Library/Frameworks"
|
||||
// fall thru
|
||||
[[clang::fallthrough]];
|
||||
case FallbackPathMode::restricted:
|
||||
handler("/System/Library/Frameworks", stop);
|
||||
break;
|
||||
case FallbackPathMode::none:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Platform::iOS:
|
||||
case Platform::watchOS:
|
||||
case Platform::tvOS:
|
||||
case Platform::bridgeOS:
|
||||
case Platform::iOSMac:
|
||||
case Platform::iOS_simulator:
|
||||
case Platform::watchOS_simulator:
|
||||
case Platform::tvOS_simulator:
|
||||
case Platform::driverKit:
|
||||
case Platform::unknown:
|
||||
if ( _fallbackPathMode != FallbackPathMode::none )
|
||||
handler("/System/Library/Frameworks", stop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// copy path and add suffix to result
|
||||
//
|
||||
// /path/foo.dylib _debug => /path/foo_debug.dylib
|
||||
// foo.dylib _debug => foo_debug.dylib
|
||||
// foo _debug => foo_debug
|
||||
// /path/bar _debug => /path/bar_debug
|
||||
// /path/bar.A.dylib _debug => /path/bar.A_debug.dylib
|
||||
//
|
||||
void PathOverrides::addSuffix(const char* path, const char* suffix, char* result) const
|
||||
{
|
||||
strcpy(result, path);
|
||||
|
||||
// find last slash
|
||||
char* start = strrchr(result, '/');
|
||||
if ( start != NULL )
|
||||
start++;
|
||||
else
|
||||
start = result;
|
||||
|
||||
// find last dot after last slash
|
||||
char* dot = strrchr(start, '.');
|
||||
if ( dot != NULL ) {
|
||||
strcpy(dot, suffix);
|
||||
strcat(&dot[strlen(suffix)], &path[dot-result]);
|
||||
}
|
||||
else {
|
||||
strcat(result, suffix);
|
||||
}
|
||||
}
|
||||
|
||||
void PathOverrides::forEachImageSuffix(const char* path, bool isFallbackPath, bool pathIsInDyldCacheWhichCannotBeOverridden, bool& stop, void (^handler)(const char* possiblePath, bool isFallbackPath, bool& stop)) const
|
||||
{
|
||||
if ( (_imageSuffix == nullptr) || pathIsInDyldCacheWhichCannotBeOverridden ) {
|
||||
handler(path, isFallbackPath, stop);
|
||||
}
|
||||
else {
|
||||
forEachInColonList(_imageSuffix, nullptr, ^(const char* suffix, bool& innerStop) {
|
||||
char npath[strlen(path)+strlen(suffix)+8];
|
||||
addSuffix(path, suffix, npath);
|
||||
handler(npath, isFallbackPath, innerStop);
|
||||
if ( innerStop )
|
||||
stop = true;
|
||||
});
|
||||
if ( !stop )
|
||||
handler(path, isFallbackPath, stop);
|
||||
}
|
||||
}
|
||||
|
||||
void PathOverrides::forEachPathVariant(const char* initialPath, bool pathIsInDyldCacheWhichCannotBeOverridden, void (^handler)(const char* possiblePath, bool isFallbackPath, bool& stop), Platform platform) const
|
||||
{
|
||||
__block bool stop = false;
|
||||
|
||||
|
||||
if ( !pathIsInDyldCacheWhichCannotBeOverridden ) {
|
||||
// check for overrides
|
||||
const char* frameworkPartialPath = getFrameworkPartialPath(initialPath);
|
||||
if ( frameworkPartialPath != nullptr ) {
|
||||
const size_t frameworkPartialPathLen = strlen(frameworkPartialPath);
|
||||
// look at each DYLD_FRAMEWORK_PATH directory
|
||||
if ( (_frameworkPathOverridesEnv != nullptr) || (_frameworkPathOverridesExeLC != nullptr) ) {
|
||||
forEachInColonList(_frameworkPathOverridesEnv, _frameworkPathOverridesExeLC, ^(const char* frDir, bool &innerStop) {
|
||||
char npath[strlen(frDir)+frameworkPartialPathLen+8];
|
||||
strcpy(npath, frDir);
|
||||
strcat(npath, "/");
|
||||
strcat(npath, frameworkPartialPath);
|
||||
forEachImageSuffix(npath, false, pathIsInDyldCacheWhichCannotBeOverridden, innerStop, handler);
|
||||
if ( innerStop )
|
||||
stop = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
const char* libraryLeafName = getLibraryLeafName(initialPath);
|
||||
const size_t libraryLeafNameLen = strlen(libraryLeafName);
|
||||
// look at each DYLD_LIBRARY_PATH directory
|
||||
if ( (_dylibPathOverridesEnv != nullptr) || (_dylibPathOverridesExeLC != nullptr) ) {
|
||||
forEachInColonList(_dylibPathOverridesEnv, _dylibPathOverridesExeLC, ^(const char* libDir, bool &innerStop) {
|
||||
char npath[strlen(libDir)+libraryLeafNameLen+8];
|
||||
strcpy(npath, libDir);
|
||||
strcat(npath, "/");
|
||||
strcat(npath, libraryLeafName);
|
||||
forEachImageSuffix(npath, false, pathIsInDyldCacheWhichCannotBeOverridden, innerStop, handler);
|
||||
if ( innerStop )
|
||||
stop = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
if ( stop )
|
||||
return;
|
||||
}
|
||||
|
||||
// try original path
|
||||
forEachImageSuffix(initialPath, false, pathIsInDyldCacheWhichCannotBeOverridden, stop, handler);
|
||||
if ( stop )
|
||||
return;
|
||||
|
||||
// check fallback paths
|
||||
if ( const char* frameworkPartialPath = getFrameworkPartialPath(initialPath) ) {
|
||||
const size_t frameworkPartialPathLen = strlen(frameworkPartialPath);
|
||||
// look at each DYLD_FALLBACK_FRAMEWORK_PATH directory
|
||||
bool usesDefaultFallbackPaths = (_frameworkPathFallbacksEnv == nullptr) && (_frameworkPathFallbacksExeLC == nullptr);
|
||||
forEachFrameworkFallback(platform, ^(const char* dir, bool& innerStop) {
|
||||
char npath[strlen(dir)+frameworkPartialPathLen+8];
|
||||
strcpy(npath, dir);
|
||||
strcat(npath, "/");
|
||||
strcat(npath, frameworkPartialPath);
|
||||
forEachImageSuffix(npath, usesDefaultFallbackPaths, pathIsInDyldCacheWhichCannotBeOverridden, innerStop, handler);
|
||||
if ( innerStop )
|
||||
stop = true;
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
const char* libraryLeafName = getLibraryLeafName(initialPath);
|
||||
const size_t libraryLeafNameLen = strlen(libraryLeafName);
|
||||
// look at each DYLD_FALLBACK_LIBRARY_PATH directory
|
||||
bool usesDefaultFallbackPaths = (_dylibPathFallbacksEnv == nullptr) && (_dylibPathFallbacksExeLC == nullptr);
|
||||
forEachDylibFallback(platform, ^(const char* dir, bool& innerStop) {
|
||||
char libpath[strlen(dir)+libraryLeafNameLen+8];
|
||||
strcpy(libpath, dir);
|
||||
strcat(libpath, "/");
|
||||
strcat(libpath, libraryLeafName);
|
||||
forEachImageSuffix(libpath, usesDefaultFallbackPaths, pathIsInDyldCacheWhichCannotBeOverridden, innerStop, handler);
|
||||
if ( innerStop )
|
||||
stop = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Find framework path
|
||||
//
|
||||
// /path/foo.framework/foo => foo.framework/foo
|
||||
// /path/foo.framework/Versions/A/foo => foo.framework/Versions/A/foo
|
||||
// /path/foo.framework/Frameworks/bar.framework/bar => bar.framework/bar
|
||||
// /path/foo.framework/Libraries/bar.dylb => NULL
|
||||
// /path/foo.framework/bar => NULL
|
||||
//
|
||||
// Returns nullptr if not a framework path
|
||||
//
|
||||
const char* PathOverrides::getFrameworkPartialPath(const char* path) const
|
||||
{
|
||||
const char* dirDot = strrstr(path, ".framework/");
|
||||
if ( dirDot != nullptr ) {
|
||||
const char* dirStart = dirDot;
|
||||
for ( ; dirStart >= path; --dirStart) {
|
||||
if ( (*dirStart == '/') || (dirStart == path) ) {
|
||||
const char* frameworkStart = &dirStart[1];
|
||||
if ( dirStart == path )
|
||||
--frameworkStart;
|
||||
size_t len = dirDot - frameworkStart;
|
||||
char framework[len+1];
|
||||
strncpy(framework, frameworkStart, len);
|
||||
framework[len] = '\0';
|
||||
const char* leaf = strrchr(path, '/');
|
||||
if ( leaf != nullptr ) {
|
||||
if ( strcmp(framework, &leaf[1]) == 0 ) {
|
||||
return frameworkStart;
|
||||
}
|
||||
if ( _imageSuffix != nullptr ) {
|
||||
// some debug frameworks have install names that end in _debug
|
||||
if ( strncmp(framework, &leaf[1], len) == 0 ) {
|
||||
if ( strcmp( _imageSuffix, &leaf[len+1]) == 0 )
|
||||
return frameworkStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
const char* PathOverrides::getLibraryLeafName(const char* path)
|
||||
{
|
||||
const char* start = strrchr(path, '/');
|
||||
if ( start != nullptr )
|
||||
return &start[1];
|
||||
else
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////// PathPool ////////////////////////////////////////
|
||||
|
||||
|
||||
PathPool* PathPool::allocate()
|
||||
{
|
||||
vm_address_t addr;
|
||||
::vm_allocate(mach_task_self(), &addr, kAllocationSize, VM_FLAGS_ANYWHERE);
|
||||
PathPool* p = (PathPool*)addr;
|
||||
p->_next = nullptr;
|
||||
p->_current = &(p->_buffer[0]);
|
||||
p->_bytesFree = kAllocationSize - sizeof(PathPool);
|
||||
return p;
|
||||
}
|
||||
|
||||
void PathPool::deallocate(PathPool* pool) {
|
||||
do {
|
||||
PathPool* next = pool->_next;
|
||||
::vm_deallocate(mach_task_self(), (vm_address_t)pool, kAllocationSize);
|
||||
pool = next;
|
||||
} while (pool);
|
||||
}
|
||||
|
||||
const char* PathPool::add(const char* path)
|
||||
{
|
||||
size_t len = strlen(path) + 1;
|
||||
if ( len < _bytesFree ) {
|
||||
char* result = _current;
|
||||
strcpy(_current, path);
|
||||
_current += len;
|
||||
_bytesFree -= len;
|
||||
return result;
|
||||
}
|
||||
if ( _next == nullptr )
|
||||
_next = allocate();
|
||||
return _next->add(path);
|
||||
}
|
||||
|
||||
void PathPool::forEachPath(void (^handler)(const char* path))
|
||||
{
|
||||
for (const char* s = _buffer; s < _current; ++s) {
|
||||
handler(s);
|
||||
s += strlen(s);
|
||||
}
|
||||
|
||||
if ( _next != nullptr )
|
||||
_next->forEachPath(handler);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace closure
|
||||
} // namespace dyld3
|
||||
|
||||
|
||||
|
||||
|
||||
|
115
src/dyld/dyld3/PathOverrides.h
Normal file
115
src/dyld/dyld3/PathOverrides.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef __DYLD_PATH_OVERRIDES_H__
|
||||
#define __DYLD_PATH_OVERRIDES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Logging.h"
|
||||
#include "MachOFile.h"
|
||||
|
||||
|
||||
namespace dyld3 {
|
||||
namespace closure {
|
||||
|
||||
|
||||
class VIS_HIDDEN PathPool
|
||||
{
|
||||
public:
|
||||
static PathPool* allocate();
|
||||
static void deallocate(PathPool* pool);
|
||||
const char* add(const char* path);
|
||||
void forEachPath(void (^handler)(const char* path));
|
||||
|
||||
private:
|
||||
enum { kAllocationSize = 32*1024 };
|
||||
|
||||
PathPool* _next;
|
||||
char* _current;
|
||||
size_t _bytesFree;
|
||||
char _buffer[];
|
||||
};
|
||||
|
||||
|
||||
class VIS_HIDDEN PathOverrides
|
||||
{
|
||||
public:
|
||||
#if !BUILDING_LIBDYLD
|
||||
// libdyld is never unloaded
|
||||
~PathOverrides();
|
||||
#endif
|
||||
enum class FallbackPathMode { classic, restricted, none };
|
||||
|
||||
void setFallbackPathHandling(FallbackPathMode mode);
|
||||
void setEnvVars(const char* envp[], const dyld3::MachOFile* mainExe, const char* mainExePath);
|
||||
void setMainExecutable(const dyld3::MachOFile* mainExe, const char* mainExePath);
|
||||
void forEachPathVariant(const char* requestedPath, bool pathIsInDyldCacheWhichCannotBeOverridden, void (^handler)(const char* possiblePath, bool isFallbackPath, bool& stop),
|
||||
Platform plat=MachOFile::currentPlatform()) const;
|
||||
|
||||
void forEachEnvVar(void (^handler)(const char* envVar)) const;
|
||||
void forEachExecutableEnvVar(void (^handler)(const char* envVar)) const;
|
||||
void forEachInsertedDylib(void (^handler)(const char* dylibPath, bool &stop)) const;
|
||||
|
||||
private:
|
||||
void setString(const char*& var, const char* value);
|
||||
const char* addString(const char* str);
|
||||
static void forEachInColonList(const char* list1, const char* list2, void (^callback)(const char* path, bool& stop));
|
||||
void addEnvVar(const char* keyEqualsValue, bool forExecutable);
|
||||
const char* getFrameworkPartialPath(const char* path) const;
|
||||
static const char* getLibraryLeafName(const char* path);
|
||||
void handleListEnvVar(const char* key, const char** list, void (^handler)(const char* envVar)) const;
|
||||
void handleEnvVar(const char* key, const char* value, void (^handler)(const char* envVar)) const;
|
||||
void forEachDylibFallback(Platform platform, void (^handler)(const char* fallbackDir, bool& stop)) const;
|
||||
void forEachFrameworkFallback(Platform platform, void (^handler)(const char* fallbackDir, bool& stop)) const;
|
||||
void forEachImageSuffix(const char* path, bool isFallbackPath, bool pathIsInDyldCacheWhichCannotBeOverridden, bool& stop, void (^handler)(const char* possiblePath, bool isFallbackPath, bool& stop)) const;
|
||||
void addSuffix(const char* path, const char* suffix, char* result) const;
|
||||
|
||||
PathPool* _pathPool = nullptr;
|
||||
const char* _dylibPathOverridesEnv = nullptr;
|
||||
const char* _frameworkPathOverridesEnv = nullptr;
|
||||
const char* _dylibPathFallbacksEnv = nullptr;
|
||||
const char* _frameworkPathFallbacksEnv = nullptr;
|
||||
const char* _dylibPathOverridesExeLC = nullptr;
|
||||
const char* _frameworkPathOverridesExeLC = nullptr;
|
||||
const char* _dylibPathFallbacksExeLC = nullptr;
|
||||
const char* _frameworkPathFallbacksExeLC = nullptr;
|
||||
const char* _insertedDylibs = nullptr;
|
||||
const char* _imageSuffix = nullptr;
|
||||
const char* _rootPath = nullptr; // simulator only
|
||||
FallbackPathMode _fallbackPathMode = FallbackPathMode::classic;
|
||||
};
|
||||
|
||||
#if BUILDING_LIBDYLD
|
||||
extern PathOverrides gPathOverrides;
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace closure
|
||||
} // namespace dyld3
|
||||
|
||||
#endif // __DYLD_PATH_OVERRIDES_H__
|
||||
|
||||
|
806
src/dyld/dyld3/SharedCacheRuntime.cpp
Normal file
806
src/dyld/dyld3/SharedCacheRuntime.cpp
Normal file
@ -0,0 +1,806 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/ldsyms.h>
|
||||
#include <mach/shared_region.h>
|
||||
#include <mach/mach.h>
|
||||
#include <Availability.h>
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#include "dyld_cache_format.h"
|
||||
#include "SharedCacheRuntime.h"
|
||||
#include "Loading.h"
|
||||
#include "BootArgs.h"
|
||||
|
||||
#define ENABLE_DYLIBS_TO_OVERRIDE_CACHE_SIZE 1024
|
||||
|
||||
// should be in mach/shared_region.h
|
||||
extern "C" int __shared_region_check_np(uint64_t* startaddress);
|
||||
extern "C" int __shared_region_map_and_slide_np(int fd, uint32_t count, const shared_file_mapping_np mappings[], long slide, const dyld_cache_slide_info2* slideInfo, size_t slideInfoSize);
|
||||
|
||||
|
||||
namespace dyld {
|
||||
extern int my_stat(const char* path, struct stat* buf);
|
||||
extern int my_open(const char* path, int flag, int other);
|
||||
extern void log(const char*, ...);
|
||||
}
|
||||
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
|
||||
struct CacheInfo
|
||||
{
|
||||
int fd;
|
||||
shared_file_mapping_np mappings[3];
|
||||
uint64_t slideInfoAddressUnslid;
|
||||
size_t slideInfoSize;
|
||||
uint64_t sharedRegionStart;
|
||||
uint64_t sharedRegionSize;
|
||||
uint64_t maxSlide;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#if __i386__
|
||||
#define ARCH_NAME "i386"
|
||||
#define ARCH_CACHE_MAGIC "dyld_v1 i386"
|
||||
#elif __x86_64__
|
||||
#define ARCH_NAME "x86_64"
|
||||
#define ARCH_CACHE_MAGIC "dyld_v1 x86_64"
|
||||
#define ARCH_NAME_H "x86_64h"
|
||||
#define ARCH_CACHE_MAGIC_H "dyld_v1 x86_64h"
|
||||
#elif __ARM_ARCH_7K__
|
||||
#define ARCH_NAME "armv7k"
|
||||
#define ARCH_CACHE_MAGIC "dyld_v1 armv7k"
|
||||
#elif __ARM_ARCH_7A__
|
||||
#define ARCH_NAME "armv7"
|
||||
#define ARCH_CACHE_MAGIC "dyld_v1 armv7"
|
||||
#elif __ARM_ARCH_7S__
|
||||
#define ARCH_NAME "armv7s"
|
||||
#define ARCH_CACHE_MAGIC "dyld_v1 armv7s"
|
||||
#elif __arm64e__
|
||||
#define ARCH_NAME "arm64e"
|
||||
#define ARCH_CACHE_MAGIC "dyld_v1 arm64e"
|
||||
#elif __arm64__
|
||||
#if __LP64__
|
||||
#define ARCH_NAME "arm64"
|
||||
#define ARCH_CACHE_MAGIC "dyld_v1 arm64"
|
||||
#else
|
||||
#define ARCH_NAME "arm64_32"
|
||||
#define ARCH_CACHE_MAGIC "dyld_v1arm64_32"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if !TARGET_OS_SIMULATOR
|
||||
static void rebaseChainV2(uint8_t* pageContent, uint16_t startOffset, uintptr_t slideAmount, const dyld_cache_slide_info2* slideInfo)
|
||||
{
|
||||
const uintptr_t deltaMask = (uintptr_t)(slideInfo->delta_mask);
|
||||
const uintptr_t valueMask = ~deltaMask;
|
||||
const uintptr_t valueAdd = (uintptr_t)(slideInfo->value_add);
|
||||
const unsigned deltaShift = __builtin_ctzll(deltaMask) - 2;
|
||||
|
||||
uint32_t pageOffset = startOffset;
|
||||
uint32_t delta = 1;
|
||||
while ( delta != 0 ) {
|
||||
uint8_t* loc = pageContent + pageOffset;
|
||||
uintptr_t rawValue = *((uintptr_t*)loc);
|
||||
delta = (uint32_t)((rawValue & deltaMask) >> deltaShift);
|
||||
uintptr_t value = (rawValue & valueMask);
|
||||
if ( value != 0 ) {
|
||||
value += valueAdd;
|
||||
value += slideAmount;
|
||||
}
|
||||
*((uintptr_t*)loc) = value;
|
||||
//dyld::log(" pageOffset=0x%03X, loc=%p, org value=0x%08llX, new value=0x%08llX, delta=0x%X\n", pageOffset, loc, (uint64_t)rawValue, (uint64_t)value, delta);
|
||||
pageOffset += delta;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !__LP64__ && !TARGET_OS_SIMULATOR
|
||||
static void rebaseChainV4(uint8_t* pageContent, uint16_t startOffset, uintptr_t slideAmount, const dyld_cache_slide_info4* slideInfo)
|
||||
{
|
||||
const uintptr_t deltaMask = (uintptr_t)(slideInfo->delta_mask);
|
||||
const uintptr_t valueMask = ~deltaMask;
|
||||
const uintptr_t valueAdd = (uintptr_t)(slideInfo->value_add);
|
||||
const unsigned deltaShift = __builtin_ctzll(deltaMask) - 2;
|
||||
|
||||
uint32_t pageOffset = startOffset;
|
||||
uint32_t delta = 1;
|
||||
while ( delta != 0 ) {
|
||||
uint8_t* loc = pageContent + pageOffset;
|
||||
uintptr_t rawValue = *((uintptr_t*)loc);
|
||||
delta = (uint32_t)((rawValue & deltaMask) >> deltaShift);
|
||||
uintptr_t value = (rawValue & valueMask);
|
||||
if ( (value & 0xFFFF8000) == 0 ) {
|
||||
// small positive non-pointer, use as-is
|
||||
}
|
||||
else if ( (value & 0x3FFF8000) == 0x3FFF8000 ) {
|
||||
// small negative non-pointer
|
||||
value |= 0xC0000000;
|
||||
}
|
||||
else {
|
||||
value += valueAdd;
|
||||
value += slideAmount;
|
||||
}
|
||||
*((uintptr_t*)loc) = value;
|
||||
//dyld::log(" pageOffset=0x%03X, loc=%p, org value=0x%08llX, new value=0x%08llX, delta=0x%X\n", pageOffset, loc, (uint64_t)rawValue, (uint64_t)value, delta);
|
||||
pageOffset += delta;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void getCachePath(const SharedCacheOptions& options, size_t pathBufferSize, char pathBuffer[])
|
||||
{
|
||||
// set cache dir
|
||||
if ( options.cacheDirOverride != nullptr ) {
|
||||
strlcpy(pathBuffer, options.cacheDirOverride, pathBufferSize);
|
||||
}
|
||||
else {
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
strlcpy(pathBuffer, IPHONE_DYLD_SHARED_CACHE_DIR, sizeof(IPHONE_DYLD_SHARED_CACHE_DIR));
|
||||
#else
|
||||
strlcpy(pathBuffer, MACOSX_DYLD_SHARED_CACHE_DIR, sizeof(MACOSX_DYLD_SHARED_CACHE_DIR));
|
||||
#endif
|
||||
}
|
||||
|
||||
// append file component of cache file
|
||||
if ( pathBuffer[strlen(pathBuffer)-1] != '/' )
|
||||
strlcat(pathBuffer, "/", pathBufferSize);
|
||||
#if __x86_64__ && !__IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
if ( options.useHaswell ) {
|
||||
size_t len = strlen(pathBuffer);
|
||||
struct stat haswellStatBuf;
|
||||
strlcat(pathBuffer, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME_H, pathBufferSize);
|
||||
if ( dyld::my_stat(pathBuffer, &haswellStatBuf) == 0 )
|
||||
return;
|
||||
// no haswell cache file, use regular x86_64 cache
|
||||
pathBuffer[len] = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
strlcat(pathBuffer, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, pathBufferSize);
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR
|
||||
// use .development cache if it exists
|
||||
struct stat enableStatBuf;
|
||||
struct stat devCacheStatBuf;
|
||||
struct stat optCacheStatBuf;
|
||||
bool developmentDevice = dyld3::internalInstall();
|
||||
bool enableFileExists = (dyld::my_stat(IPHONE_DYLD_SHARED_CACHE_DIR "enable-dylibs-to-override-cache", &enableStatBuf) == 0);
|
||||
bool devCacheExists = (dyld::my_stat(IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME DYLD_SHARED_CACHE_DEVELOPMENT_EXT, &devCacheStatBuf) == 0);
|
||||
bool optCacheExists = (dyld::my_stat(IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, &optCacheStatBuf) == 0);
|
||||
if ( !BootArgs::forceCustomerCache() && developmentDevice && ((enableFileExists && (enableStatBuf.st_size < ENABLE_DYLIBS_TO_OVERRIDE_CACHE_SIZE) && devCacheExists) || !optCacheExists) )
|
||||
strlcat(pathBuffer, DYLD_SHARED_CACHE_DEVELOPMENT_EXT, pathBufferSize);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
int openSharedCacheFile(const SharedCacheOptions& options, SharedCacheLoadInfo* results)
|
||||
{
|
||||
getCachePath(options, sizeof(results->path), results->path);
|
||||
return dyld::my_open(results->path, O_RDONLY, 0);
|
||||
}
|
||||
|
||||
static bool validMagic(const SharedCacheOptions& options, const DyldSharedCache* cache)
|
||||
{
|
||||
if ( strcmp(cache->header.magic, ARCH_CACHE_MAGIC) == 0 )
|
||||
return true;
|
||||
|
||||
#if __x86_64__
|
||||
if ( options.useHaswell ) {
|
||||
if ( strcmp(cache->header.magic, ARCH_CACHE_MAGIC_H) == 0 )
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool validPlatform(const SharedCacheOptions& options, const DyldSharedCache* cache)
|
||||
{
|
||||
// grandfather in old cache that does not have platform in header
|
||||
if ( cache->header.mappingOffset < 0xE0 )
|
||||
return true;
|
||||
|
||||
if ( cache->header.platform != (uint32_t)MachOFile::currentPlatform() )
|
||||
return false;
|
||||
|
||||
#if TARGET_OS_SIMULATOR
|
||||
if ( cache->header.simulator == 0 )
|
||||
return false;
|
||||
#else
|
||||
if ( cache->header.simulator != 0 )
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_SIMULATOR
|
||||
static void verboseSharedCacheMappings(const shared_file_mapping_np mappings[3])
|
||||
{
|
||||
for (int i=0; i < 3; ++i) {
|
||||
dyld::log(" 0x%08llX->0x%08llX init=%x, max=%x %s%s%s\n",
|
||||
mappings[i].sfm_address, mappings[i].sfm_address+mappings[i].sfm_size-1,
|
||||
mappings[i].sfm_init_prot, mappings[i].sfm_init_prot,
|
||||
((mappings[i].sfm_init_prot & VM_PROT_READ) ? "read " : ""),
|
||||
((mappings[i].sfm_init_prot & VM_PROT_WRITE) ? "write " : ""),
|
||||
((mappings[i].sfm_init_prot & VM_PROT_EXECUTE) ? "execute " : ""));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool preflightCacheFile(const SharedCacheOptions& options, SharedCacheLoadInfo* results, CacheInfo* info)
|
||||
{
|
||||
|
||||
// find and open shared cache file
|
||||
int fd = openSharedCacheFile(options, results);
|
||||
if ( fd == -1 ) {
|
||||
results->errorMessage = "shared cache file open() failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
struct stat cacheStatBuf;
|
||||
if ( dyld::my_stat(results->path, &cacheStatBuf) != 0 ) {
|
||||
results->errorMessage = "shared cache file stat() failed";
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
size_t cacheFileLength = (size_t)(cacheStatBuf.st_size);
|
||||
|
||||
// sanity check header and mappings
|
||||
uint8_t firstPage[0x4000];
|
||||
if ( ::pread(fd, firstPage, sizeof(firstPage), 0) != sizeof(firstPage) ) {
|
||||
results->errorMessage = "shared cache file pread() failed";
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
const DyldSharedCache* cache = (DyldSharedCache*)firstPage;
|
||||
if ( !validMagic(options, cache) ) {
|
||||
results->errorMessage = "shared cache file has wrong magic";
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
if ( !validPlatform(options, cache) ) {
|
||||
results->errorMessage = "shared cache file is for a different platform";
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
if ( (cache->header.mappingCount != 3) || (cache->header.mappingOffset > 0x138) ) {
|
||||
results->errorMessage = "shared cache file mappings are invalid";
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
const dyld_cache_mapping_info* const fileMappings = (dyld_cache_mapping_info*)&firstPage[cache->header.mappingOffset];
|
||||
if ( (fileMappings[0].fileOffset != 0)
|
||||
|| ((fileMappings[0].address + fileMappings[0].size) > fileMappings[1].address)
|
||||
|| ((fileMappings[1].address + fileMappings[1].size) > fileMappings[2].address)
|
||||
|| ((fileMappings[0].fileOffset + fileMappings[0].size) != fileMappings[1].fileOffset)
|
||||
|| ((fileMappings[1].fileOffset + fileMappings[1].size) != fileMappings[2].fileOffset)
|
||||
|| ((cache->header.codeSignatureOffset + cache->header.codeSignatureSize) != cacheFileLength)
|
||||
|| (fileMappings[0].maxProt != (VM_PROT_READ|VM_PROT_EXECUTE))
|
||||
|| (fileMappings[1].maxProt != (VM_PROT_READ|VM_PROT_WRITE))
|
||||
|| (fileMappings[2].maxProt != VM_PROT_READ) ) {
|
||||
results->errorMessage = "shared cache file mappings are invalid";
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( cache->header.mappingOffset >= 0xF8 ) {
|
||||
if ( (fileMappings[0].address != cache->header.sharedRegionStart) || ((fileMappings[2].address + fileMappings[2].size) > (cache->header.sharedRegionStart+cache->header.sharedRegionSize)) ) {
|
||||
results->errorMessage = "shared cache file mapping addressses invalid";
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( (fileMappings[0].address != SHARED_REGION_BASE) || ((fileMappings[2].address + fileMappings[2].size) > (SHARED_REGION_BASE+SHARED_REGION_SIZE)) ) {
|
||||
results->errorMessage = "shared cache file mapping addressses invalid";
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// register code signature of cache file
|
||||
fsignatures_t siginfo;
|
||||
siginfo.fs_file_start = 0; // cache always starts at beginning of file
|
||||
siginfo.fs_blob_start = (void*)cache->header.codeSignatureOffset;
|
||||
siginfo.fs_blob_size = (size_t)(cache->header.codeSignatureSize);
|
||||
int result = fcntl(fd, F_ADDFILESIGS_RETURN, &siginfo);
|
||||
if ( result == -1 ) {
|
||||
results->errorMessage = "code signature registration for shared cache failed";
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// <rdar://problem/23188073> validate code signature covers entire shared cache
|
||||
uint64_t codeSignedLength = siginfo.fs_file_start;
|
||||
if ( codeSignedLength < cache->header.codeSignatureOffset ) {
|
||||
results->errorMessage = "code signature does not cover entire shared cache file";
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
void* mappedData = ::mmap(NULL, sizeof(firstPage), PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);
|
||||
if ( mappedData == MAP_FAILED ) {
|
||||
results->errorMessage = "first page of shared cache not mmap()able";
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
if ( memcmp(mappedData, firstPage, sizeof(firstPage)) != 0 ) {
|
||||
results->errorMessage = "first page of mmap()ed shared cache not valid";
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
::munmap(mappedData, sizeof(firstPage));
|
||||
|
||||
// fill out results
|
||||
info->fd = fd;
|
||||
for (int i=0; i < 3; ++i) {
|
||||
info->mappings[i].sfm_address = fileMappings[i].address;
|
||||
info->mappings[i].sfm_size = fileMappings[i].size;
|
||||
info->mappings[i].sfm_file_offset = fileMappings[i].fileOffset;
|
||||
info->mappings[i].sfm_max_prot = fileMappings[i].maxProt;
|
||||
info->mappings[i].sfm_init_prot = fileMappings[i].initProt;
|
||||
}
|
||||
info->mappings[1].sfm_max_prot |= VM_PROT_SLIDE;
|
||||
info->mappings[1].sfm_init_prot |= VM_PROT_SLIDE;
|
||||
info->slideInfoAddressUnslid = fileMappings[2].address + cache->header.slideInfoOffset - fileMappings[2].fileOffset;
|
||||
info->slideInfoSize = (long)cache->header.slideInfoSize;
|
||||
if ( cache->header.mappingOffset >= 0xf8 ) {
|
||||
info->sharedRegionStart = cache->header.sharedRegionStart;
|
||||
info->sharedRegionSize = cache->header.sharedRegionSize;
|
||||
info->maxSlide = cache->header.maxSlide;
|
||||
}
|
||||
else {
|
||||
info->sharedRegionStart = SHARED_REGION_BASE;
|
||||
info->sharedRegionSize = SHARED_REGION_SIZE;
|
||||
info->maxSlide = SHARED_REGION_SIZE - (fileMappings[2].address + fileMappings[2].size - fileMappings[0].address);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if !TARGET_OS_SIMULATOR
|
||||
|
||||
// update all __DATA pages with slide info
|
||||
static bool rebaseDataPages(bool isVerbose, CacheInfo& info, SharedCacheLoadInfo* results)
|
||||
{
|
||||
uint64_t dataPagesStart = info.mappings[1].sfm_address;
|
||||
const dyld_cache_slide_info* slideInfo = nullptr;
|
||||
if ( info.slideInfoSize != 0 ) {
|
||||
slideInfo = (dyld_cache_slide_info*)(info.slideInfoAddressUnslid + results->slide);
|
||||
}
|
||||
const dyld_cache_slide_info* slideInfoHeader = (dyld_cache_slide_info*)slideInfo;
|
||||
if ( slideInfoHeader != nullptr ) {
|
||||
if ( slideInfoHeader->version == 2 ) {
|
||||
const dyld_cache_slide_info2* slideHeader = (dyld_cache_slide_info2*)slideInfo;
|
||||
const uint32_t page_size = slideHeader->page_size;
|
||||
const uint16_t* page_starts = (uint16_t*)((long)(slideInfo) + slideHeader->page_starts_offset);
|
||||
const uint16_t* page_extras = (uint16_t*)((long)(slideInfo) + slideHeader->page_extras_offset);
|
||||
for (int i=0; i < slideHeader->page_starts_count; ++i) {
|
||||
uint8_t* page = (uint8_t*)(long)(dataPagesStart + (page_size*i));
|
||||
uint16_t pageEntry = page_starts[i];
|
||||
//dyld::log("page[%d]: page_starts[i]=0x%04X\n", i, pageEntry);
|
||||
if ( pageEntry == DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE )
|
||||
continue;
|
||||
if ( pageEntry & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA ) {
|
||||
uint16_t chainIndex = (pageEntry & 0x3FFF);
|
||||
bool done = false;
|
||||
while ( !done ) {
|
||||
uint16_t pInfo = page_extras[chainIndex];
|
||||
uint16_t pageStartOffset = (pInfo & 0x3FFF)*4;
|
||||
//dyld::log(" chain[%d] pageOffset=0x%03X\n", chainIndex, pageStartOffset);
|
||||
rebaseChainV2(page, pageStartOffset, results->slide, slideHeader);
|
||||
done = (pInfo & DYLD_CACHE_SLIDE_PAGE_ATTR_END);
|
||||
++chainIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint32_t pageOffset = pageEntry * 4;
|
||||
//dyld::log(" start pageOffset=0x%03X\n", pageOffset);
|
||||
rebaseChainV2(page, pageOffset, results->slide, slideHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if __LP64__
|
||||
else if ( slideInfoHeader->version == 3 ) {
|
||||
const dyld_cache_slide_info3* slideHeader = (dyld_cache_slide_info3*)slideInfo;
|
||||
const uint32_t pageSize = slideHeader->page_size;
|
||||
for (int i=0; i < slideHeader->page_starts_count; ++i) {
|
||||
uint8_t* page = (uint8_t*)(dataPagesStart + (pageSize*i));
|
||||
uint64_t delta = slideHeader->page_starts[i];
|
||||
if ( delta == DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE )
|
||||
continue;
|
||||
delta = delta/sizeof(uint64_t); // initial offset is byte based
|
||||
dyld_cache_slide_pointer3* loc = (dyld_cache_slide_pointer3*)page;
|
||||
do {
|
||||
loc += delta;
|
||||
delta = loc->plain.offsetToNextPointer;
|
||||
if ( loc->auth.authenticated ) {
|
||||
#if __has_feature(ptrauth_calls)
|
||||
uint64_t target = info.sharedRegionStart + loc->auth.offsetFromSharedCacheBase + results->slide;
|
||||
MachOLoaded::ChainedFixupPointerOnDisk ptr;
|
||||
ptr.raw64 = *((uint64_t*)loc);
|
||||
loc->raw = ptr.arm64e.signPointer(loc, target);
|
||||
#else
|
||||
results->errorMessage = "invalid pointer kind in cache file";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
MachOLoaded::ChainedFixupPointerOnDisk ptr;
|
||||
ptr.raw64 = *((uint64_t*)loc);
|
||||
loc->raw = ptr.arm64e.unpackTarget() + results->slide;
|
||||
}
|
||||
} while (delta != 0);
|
||||
}
|
||||
}
|
||||
#else
|
||||
else if ( slideInfoHeader->version == 4 ) {
|
||||
const dyld_cache_slide_info4* slideHeader = (dyld_cache_slide_info4*)slideInfo;
|
||||
const uint32_t page_size = slideHeader->page_size;
|
||||
const uint16_t* page_starts = (uint16_t*)((long)(slideInfo) + slideHeader->page_starts_offset);
|
||||
const uint16_t* page_extras = (uint16_t*)((long)(slideInfo) + slideHeader->page_extras_offset);
|
||||
for (int i=0; i < slideHeader->page_starts_count; ++i) {
|
||||
uint8_t* page = (uint8_t*)(long)(dataPagesStart + (page_size*i));
|
||||
uint16_t pageEntry = page_starts[i];
|
||||
//dyld::log("page[%d]: page_starts[i]=0x%04X\n", i, pageEntry);
|
||||
if ( pageEntry == DYLD_CACHE_SLIDE4_PAGE_NO_REBASE )
|
||||
continue;
|
||||
if ( pageEntry & DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA ) {
|
||||
uint16_t chainIndex = (pageEntry & DYLD_CACHE_SLIDE4_PAGE_INDEX);
|
||||
bool done = false;
|
||||
while ( !done ) {
|
||||
uint16_t pInfo = page_extras[chainIndex];
|
||||
uint16_t pageStartOffset = (pInfo & DYLD_CACHE_SLIDE4_PAGE_INDEX)*4;
|
||||
//dyld::log(" chain[%d] pageOffset=0x%03X\n", chainIndex, pageStartOffset);
|
||||
rebaseChainV4(page, pageStartOffset, results->slide, slideHeader);
|
||||
done = (pInfo & DYLD_CACHE_SLIDE4_PAGE_EXTRA_END);
|
||||
++chainIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint32_t pageOffset = pageEntry * 4;
|
||||
//dyld::log(" start pageOffset=0x%03X\n", pageOffset);
|
||||
rebaseChainV4(page, pageOffset, results->slide, slideHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // LP64
|
||||
else {
|
||||
results->errorMessage = "invalid slide info in cache file";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool reuseExistingCache(const SharedCacheOptions& options, SharedCacheLoadInfo* results)
|
||||
{
|
||||
uint64_t cacheBaseAddress;
|
||||
#if __i386__
|
||||
if ( syscall(294, &cacheBaseAddress) == 0 ) {
|
||||
#else
|
||||
if ( __shared_region_check_np(&cacheBaseAddress) == 0 ) {
|
||||
#endif
|
||||
const DyldSharedCache* existingCache = (DyldSharedCache*)cacheBaseAddress;
|
||||
if ( validMagic(options, existingCache) ) {
|
||||
const dyld_cache_mapping_info* const fileMappings = (dyld_cache_mapping_info*)(cacheBaseAddress + existingCache->header.mappingOffset);
|
||||
results->loadAddress = existingCache;
|
||||
results->slide = (long)(cacheBaseAddress - fileMappings[0].address);
|
||||
// we don't know the path this cache was previously loaded from, assume default
|
||||
getCachePath(options, sizeof(results->path), results->path);
|
||||
if ( options.verbose ) {
|
||||
const shared_file_mapping_np* const mappings = (shared_file_mapping_np*)(cacheBaseAddress + existingCache->header.mappingOffset);
|
||||
dyld::log("re-using existing shared cache (%s):\n", results->path);
|
||||
shared_file_mapping_np slidMappings[3];
|
||||
for (int i=0; i < 3; ++i) {
|
||||
slidMappings[i] = mappings[i];
|
||||
slidMappings[i].sfm_address += results->slide;
|
||||
}
|
||||
verboseSharedCacheMappings(slidMappings);
|
||||
}
|
||||
}
|
||||
else {
|
||||
results->errorMessage = "existing shared cache in memory is not compatible";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static long pickCacheASLR(CacheInfo& info)
|
||||
{
|
||||
// choose new random slide
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
// <rdar://problem/20848977> change shared cache slide for 32-bit arm to always be 16k aligned
|
||||
long slide = ((arc4random() % info.maxSlide) & (-16384));
|
||||
#else
|
||||
long slide = ((arc4random() % info.maxSlide) & (-4096));
|
||||
#endif
|
||||
|
||||
// <rdar://problem/32031197> respect -disable_aslr boot-arg
|
||||
if ( BootArgs::contains("-disable_aslr") )
|
||||
slide = 0;
|
||||
|
||||
// update mappings
|
||||
for (uint32_t i=0; i < 3; ++i) {
|
||||
info.mappings[i].sfm_address += slide;
|
||||
}
|
||||
|
||||
return slide;
|
||||
}
|
||||
|
||||
static bool mapCacheSystemWide(const SharedCacheOptions& options, SharedCacheLoadInfo* results)
|
||||
{
|
||||
CacheInfo info;
|
||||
if ( !preflightCacheFile(options, results, &info) )
|
||||
return false;
|
||||
|
||||
const dyld_cache_slide_info2* slideInfo = nullptr;
|
||||
if ( info.slideInfoSize != 0 ) {
|
||||
results->slide = pickCacheASLR(info);
|
||||
slideInfo = (dyld_cache_slide_info2*)(info.slideInfoAddressUnslid + results->slide);
|
||||
}
|
||||
|
||||
int result = __shared_region_map_and_slide_np(info.fd, 3, info.mappings, results->slide, slideInfo, info.slideInfoSize);
|
||||
::close(info.fd);
|
||||
if ( result == 0 ) {
|
||||
results->loadAddress = (const DyldSharedCache*)(info.mappings[0].sfm_address);
|
||||
}
|
||||
else {
|
||||
// could be another process beat us to it
|
||||
if ( reuseExistingCache(options, results) )
|
||||
return true;
|
||||
// if cache does not exist, then really is an error
|
||||
if ( results->errorMessage == nullptr )
|
||||
results->errorMessage = "syscall to map cache into shared region failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( options.verbose ) {
|
||||
dyld::log("mapped dyld cache file system wide: %s\n", results->path);
|
||||
verboseSharedCacheMappings(info.mappings);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // TARGET_OS_SIMULATOR
|
||||
|
||||
static bool mapCachePrivate(const SharedCacheOptions& options, SharedCacheLoadInfo* results)
|
||||
{
|
||||
// open and validate cache file
|
||||
CacheInfo info;
|
||||
if ( !preflightCacheFile(options, results, &info) )
|
||||
return false;
|
||||
|
||||
// compute ALSR slide
|
||||
results->slide = 0;
|
||||
#if !TARGET_OS_SIMULATOR // simulator caches do not support sliding
|
||||
if ( info.slideInfoSize != 0 ) {
|
||||
results->slide = pickCacheASLR(info);
|
||||
}
|
||||
#endif
|
||||
results->loadAddress = (const DyldSharedCache*)(info.mappings[0].sfm_address);
|
||||
|
||||
// deallocate any existing system wide shared cache
|
||||
deallocateExistingSharedCache();
|
||||
|
||||
#if TARGET_OS_SIMULATOR && TARGET_OS_WATCH
|
||||
// <rdar://problem/50887685> watchOS 32-bit cache does not overlap macOS dyld cache address range
|
||||
// mmap() of a file needs a vm_allocation behind it, so make one
|
||||
vm_address_t loadAddress = 0x40000000;
|
||||
::vm_allocate(mach_task_self(), &loadAddress, 0x40000000, VM_FLAGS_FIXED);
|
||||
#endif
|
||||
|
||||
// map cache just for this process with mmap()
|
||||
for (int i=0; i < 3; ++i) {
|
||||
void* mmapAddress = (void*)(uintptr_t)(info.mappings[i].sfm_address);
|
||||
size_t size = (size_t)(info.mappings[i].sfm_size);
|
||||
//dyld::log("dyld: mapping address %p with size 0x%08lX\n", mmapAddress, size);
|
||||
int protection = 0;
|
||||
if ( info.mappings[i].sfm_init_prot & VM_PROT_EXECUTE )
|
||||
protection |= PROT_EXEC;
|
||||
if ( info.mappings[i].sfm_init_prot & VM_PROT_READ )
|
||||
protection |= PROT_READ;
|
||||
if ( info.mappings[i].sfm_init_prot & VM_PROT_WRITE )
|
||||
protection |= PROT_WRITE;
|
||||
off_t offset = info.mappings[i].sfm_file_offset;
|
||||
if ( ::mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, info.fd, offset) != mmapAddress ) {
|
||||
// failed to map some chunk of this shared cache file
|
||||
// clear shared region
|
||||
::mmap((void*)((long)SHARED_REGION_BASE), SHARED_REGION_SIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE| MAP_ANON, 0, 0);
|
||||
// return failure
|
||||
results->loadAddress = nullptr;
|
||||
results->errorMessage = "could not mmap() part of dyld cache";
|
||||
::close(info.fd);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
::close(info.fd);
|
||||
|
||||
#if TARGET_OS_SIMULATOR // simulator caches do not support sliding
|
||||
return true;
|
||||
#else
|
||||
bool success = rebaseDataPages(options.verbose, info, results);
|
||||
|
||||
if ( options.verbose ) {
|
||||
dyld::log("mapped dyld cache file private to process (%s):\n", results->path);
|
||||
verboseSharedCacheMappings(info.mappings);
|
||||
}
|
||||
return success;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool loadDyldCache(const SharedCacheOptions& options, SharedCacheLoadInfo* results)
|
||||
{
|
||||
results->loadAddress = 0;
|
||||
results->slide = 0;
|
||||
results->errorMessage = nullptr;
|
||||
|
||||
#if TARGET_OS_SIMULATOR
|
||||
// simulator only supports mmap()ing cache privately into process
|
||||
return mapCachePrivate(options, results);
|
||||
#else
|
||||
if ( options.forcePrivate ) {
|
||||
// mmap cache into this process only
|
||||
return mapCachePrivate(options, results);
|
||||
}
|
||||
else {
|
||||
// fast path: when cache is already mapped into shared region
|
||||
bool hasError = false;
|
||||
if ( reuseExistingCache(options, results) ) {
|
||||
hasError = (results->errorMessage != nullptr);
|
||||
} else {
|
||||
// slow path: this is first process to load cache
|
||||
hasError = mapCacheSystemWide(options, results);
|
||||
}
|
||||
return hasError;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool findInSharedCacheImage(const SharedCacheLoadInfo& loadInfo, const char* dylibPathToFind, SharedCacheFindDylibResults* results)
|
||||
{
|
||||
if ( loadInfo.loadAddress == nullptr )
|
||||
return false;
|
||||
|
||||
if ( loadInfo.loadAddress->header.formatVersion != dyld3::closure::kFormatVersion ) {
|
||||
// support for older cache with a different Image* format
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
uint64_t hash = 0;
|
||||
for (const char* s=dylibPathToFind; *s != '\0'; ++s)
|
||||
hash += hash*4 + *s;
|
||||
#endif
|
||||
const dyld_cache_image_info* const start = (dyld_cache_image_info*)((uint8_t*)loadInfo.loadAddress + loadInfo.loadAddress->header.imagesOffset);
|
||||
const dyld_cache_image_info* const end = &start[loadInfo.loadAddress->header.imagesCount];
|
||||
for (const dyld_cache_image_info* p = start; p != end; ++p) {
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
// on iOS, inode is used to hold hash of path
|
||||
if ( (p->modTime == 0) && (p->inode != hash) )
|
||||
continue;
|
||||
#endif
|
||||
const char* aPath = (char*)loadInfo.loadAddress + p->pathFileOffset;
|
||||
if ( strcmp(aPath, dylibPathToFind) == 0 ) {
|
||||
results->mhInCache = (const mach_header*)(p->address+loadInfo.slide);
|
||||
results->pathInCache = aPath;
|
||||
results->slideInCache = loadInfo.slide;
|
||||
results->image = nullptr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const dyld3::closure::ImageArray* images = loadInfo.loadAddress->cachedDylibsImageArray();
|
||||
results->image = nullptr;
|
||||
uint32_t imageIndex;
|
||||
if ( loadInfo.loadAddress->hasImagePath(dylibPathToFind, imageIndex) ) {
|
||||
results->image = images->imageForNum(imageIndex+1);
|
||||
}
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
else {
|
||||
// <rdar://problem/32740215> handle symlink to cached dylib
|
||||
if ( loadInfo.loadAddress->header.dylibsExpectedOnDisk ) {
|
||||
struct stat statBuf;
|
||||
if ( dyld::my_stat(dylibPathToFind, &statBuf) == 0 ) {
|
||||
// on macOS we store the inode and mtime of each dylib in the cache in the dyld_cache_image_info array
|
||||
const dyld_cache_image_info* const start = (dyld_cache_image_info*)((uint8_t*)loadInfo.loadAddress + loadInfo.loadAddress->header.imagesOffset);
|
||||
const dyld_cache_image_info* const end = &start[loadInfo.loadAddress->header.imagesCount];
|
||||
for (const dyld_cache_image_info* p = start; p != end; ++p) {
|
||||
if ( (p->inode == statBuf.st_ino) && (p->modTime == statBuf.st_mtime) ) {
|
||||
imageIndex = (uint32_t)(p - start);
|
||||
results->image = images->imageForNum(imageIndex+1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
char resolvedPath[PATH_MAX];
|
||||
if ( realpath(dylibPathToFind, resolvedPath) != nullptr ) {
|
||||
if ( loadInfo.loadAddress->hasImagePath(resolvedPath, imageIndex) ) {
|
||||
results->image = images->imageForNum(imageIndex+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if ( results->image == nullptr )
|
||||
return false;
|
||||
|
||||
results->mhInCache = (const mach_header*)((uintptr_t)loadInfo.loadAddress + results->image->cacheOffset());
|
||||
results->pathInCache = results->image->path();
|
||||
results->slideInCache = loadInfo.slide;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool pathIsInSharedCacheImage(const SharedCacheLoadInfo& loadInfo, const char* dylibPathToFind)
|
||||
{
|
||||
if ( (loadInfo.loadAddress == nullptr) )
|
||||
return false;
|
||||
|
||||
uint32_t imageIndex;
|
||||
return loadInfo.loadAddress->hasImagePath(dylibPathToFind, imageIndex);
|
||||
}
|
||||
|
||||
void deallocateExistingSharedCache()
|
||||
{
|
||||
#if TARGET_OS_SIMULATOR
|
||||
// dyld deallocated macOS shared cache before jumping into dyld_sim
|
||||
#else
|
||||
// <rdar://problem/5077374> remove the shared region sub-map
|
||||
uint64_t existingCacheAddress = 0;
|
||||
if ( __shared_region_check_np(&existingCacheAddress) == 0 ) {
|
||||
::mmap((void*)((long)SHARED_REGION_BASE), SHARED_REGION_SIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE| MAP_ANON, 0, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} // namespace dyld3
|
||||
|
70
src/dyld/dyld3/SharedCacheRuntime.h
Normal file
70
src/dyld/dyld3/SharedCacheRuntime.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef __DYLD_SHARED_CACHE_RUNTIME_H__
|
||||
#define __DYLD_SHARED_CACHE_RUNTIME_H__
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "DyldSharedCache.h"
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
struct SharedCacheOptions {
|
||||
const char* cacheDirOverride;
|
||||
bool forcePrivate;
|
||||
bool useHaswell;
|
||||
bool verbose;
|
||||
};
|
||||
|
||||
struct SharedCacheLoadInfo {
|
||||
const DyldSharedCache* loadAddress;
|
||||
long slide;
|
||||
const char* errorMessage;
|
||||
char path[256];
|
||||
};
|
||||
|
||||
bool loadDyldCache(const SharedCacheOptions& options, SharedCacheLoadInfo* results);
|
||||
|
||||
|
||||
struct SharedCacheFindDylibResults {
|
||||
const mach_header* mhInCache;
|
||||
const char* pathInCache;
|
||||
long slideInCache;
|
||||
const closure::Image* image;
|
||||
};
|
||||
|
||||
bool findInSharedCacheImage(const SharedCacheLoadInfo& loadInfo, const char* dylibPathToFind, SharedCacheFindDylibResults* results);
|
||||
|
||||
bool pathIsInSharedCacheImage(const SharedCacheLoadInfo& loadInfo, const char* dylibPathToFind);
|
||||
|
||||
void deallocateExistingSharedCache();
|
||||
|
||||
} // namespace dyld3
|
||||
|
||||
#endif // __DYLD_SHARED_CACHE_RUNTIME_H__
|
||||
|
||||
|
@ -25,7 +25,9 @@
|
||||
#define __START_GLUE_H__
|
||||
|
||||
// Implemented in start_glue.s
|
||||
extern "C" void start();
|
||||
// Declare 'start' as a character, so that we can index into it.
|
||||
// Avoid arithmetic on function pointers.
|
||||
extern "C" char start;
|
||||
|
||||
|
||||
// <rdar://problem/12792039> need 'start' to be one atom, but entry is in interior
|
30
src/dyld/dyld3/SupportedArchs.h
Normal file
30
src/dyld/dyld3/SupportedArchs.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
|
||||
*
|
||||
* Copyright (c) 2015 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#ifndef _DYLD_SUPPORTED_ARCHS_H_
|
||||
#define _DYLD_SUPPORTED_ARCHS_H_
|
||||
|
||||
|
||||
|
||||
#endif // _DYLD_SUPPORTED_ARCHS_H_
|
161
src/dyld/dyld3/Tracing.cpp
Normal file
161
src/dyld/dyld3/Tracing.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <assert.h>
|
||||
#include <mach/mach.h>
|
||||
#include <kern/kcdata.h>
|
||||
#include <mach-o/dyld_priv.h>
|
||||
#ifdef DARLING
|
||||
#define kdebug_trace(...)
|
||||
#define kdebug_is_enabled(...) false
|
||||
#endif
|
||||
#include "Loading.h"
|
||||
#include "Tracing.h"
|
||||
|
||||
// Workaround for header issues in rdar://49073930
|
||||
// #include <System/os/reason_private.h>
|
||||
extern "C" int
|
||||
os_fault_with_payload(uint32_t reason_namespace, uint64_t reason_code,
|
||||
void *payload, uint32_t payload_size, const char *reason_string,
|
||||
uint64_t reason_flags) __attribute__((cold));
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
VIS_HIDDEN
|
||||
void kdebug_trace_dyld_image(const uint32_t code,
|
||||
const char* imagePath,
|
||||
const uuid_t* uuid_bytes,
|
||||
const fsobj_id_t fsobjid,
|
||||
const fsid_t fsid,
|
||||
const mach_header* load_addr)
|
||||
{
|
||||
uint64_t id = kdebug_trace_string(code, 0, imagePath);
|
||||
#if __ARM_ARCH_7K__
|
||||
uint32_t *uuid = (uint32_t *)uuid_bytes;
|
||||
kdebug_trace(KDBG_CODE(DBG_DYLD, DBG_DYLD_UUID, code + 2), uuid[0],
|
||||
uuid[1], uuid[2], uuid[3]);
|
||||
kdebug_trace(KDBG_CODE(DBG_DYLD, DBG_DYLD_UUID, code + 3),
|
||||
(uint32_t)load_addr, fsid.val[0], fsid.val[1],
|
||||
fsobjid.fid_objno);
|
||||
kdebug_trace(KDBG_CODE(DBG_DYLD, DBG_DYLD_UUID, code + 4),
|
||||
fsobjid.fid_generation, id, 0, 0);
|
||||
#else /* __ARM_ARCH_7K__ */
|
||||
uint64_t *uuid = (uint64_t *)uuid_bytes;
|
||||
kdebug_trace(KDBG_CODE(DBG_DYLD, DBG_DYLD_UUID, code), uuid[0],
|
||||
uuid[1], (uint64_t)load_addr,
|
||||
(uint64_t)fsid.val[0] | ((uint64_t)fsid.val[1] << 32));
|
||||
kdebug_trace(KDBG_CODE(DBG_DYLD, DBG_DYLD_UUID, code + 1),
|
||||
(uint64_t)fsobjid.fid_objno |
|
||||
((uint64_t)fsobjid.fid_generation << 32),
|
||||
id, 0, 0);
|
||||
#endif /* !__ARM_ARCH_7K__ */
|
||||
kdebug_trace_string(code, id, nullptr);
|
||||
}
|
||||
|
||||
// FIXME
|
||||
// We get distinct copies of this in libdyld and dyld. Eventually we can fix it,
|
||||
// for now we will just offset the values.
|
||||
|
||||
#if BUILDING_DYLD
|
||||
static std::atomic<uint64_t> trace_pair_id(0);
|
||||
#else
|
||||
static std::atomic<uint64_t> trace_pair_id(1LL<<63);
|
||||
#endif
|
||||
|
||||
VIS_HIDDEN
|
||||
bool kdebug_trace_dyld_enabled(uint32_t code) {
|
||||
return kdebug_is_enabled(code);
|
||||
}
|
||||
|
||||
VIS_HIDDEN
|
||||
void kdebug_trace_dyld_marker(uint32_t code, kt_arg data1, kt_arg data2, kt_arg data3, kt_arg data4) {
|
||||
if (kdebug_is_enabled(code)) {
|
||||
data1.prepare(code);
|
||||
data2.prepare(code);
|
||||
data3.prepare(code);
|
||||
data4.prepare(code);
|
||||
kdebug_trace(code, data1.value(), data2.value(), data3.value(), data4.value());
|
||||
data4.destroy(code);
|
||||
data3.destroy(code);
|
||||
data2.destroy(code);
|
||||
data1.destroy(code);
|
||||
}
|
||||
}
|
||||
|
||||
VIS_HIDDEN
|
||||
uint64_t kdebug_trace_dyld_duration_start(uint32_t code, kt_arg data1, kt_arg data2, kt_arg data3) {
|
||||
uint64_t result = 0;
|
||||
if (kdebug_is_enabled(code)) {
|
||||
result = ++trace_pair_id;
|
||||
data1.prepare(code);
|
||||
data2.prepare(code);
|
||||
data3.prepare(code);
|
||||
kdebug_trace(code | DBG_FUNC_START, result, data1.value(), data2.value(), data3.value());
|
||||
data3.destroy(code);
|
||||
data2.destroy(code);
|
||||
data1.destroy(code);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
VIS_HIDDEN
|
||||
void kdebug_trace_dyld_duration_end(uint64_t trace_id, uint32_t code, kt_arg data1, kt_arg data2, kt_arg data3) {
|
||||
if (trace_id != 0 && kdebug_is_enabled(code)) {
|
||||
data1.prepare(code);
|
||||
data2.prepare(code);
|
||||
data3.prepare(code);
|
||||
kdebug_trace(code | DBG_FUNC_END, trace_id, data1.value(), data2.value(), data3.value());
|
||||
data3.destroy(code);
|
||||
data2.destroy(code);
|
||||
data1.destroy(code);
|
||||
}
|
||||
}
|
||||
|
||||
void ScopedTimer::startTimer() {
|
||||
current_trace_id = kdebug_trace_dyld_duration_start(code, data1, data2, data3);
|
||||
}
|
||||
|
||||
void ScopedTimer::endTimer() {
|
||||
kdebug_trace_dyld_duration_end(current_trace_id, code, data4, data5, data6);
|
||||
}
|
||||
|
||||
void syntheticBacktrace(const char *reason, bool enableExternally) {
|
||||
if (!enableExternally && !internalInstall()) { return; }
|
||||
|
||||
char payloadBuffer[EXIT_REASON_PAYLOAD_MAX_LEN];
|
||||
dyld_abort_payload* payload = (dyld_abort_payload*)payloadBuffer;
|
||||
payload->version = 1;
|
||||
payload->flags = 0;
|
||||
payload->targetDylibPathOffset = 0;
|
||||
payload->clientPathOffset = 0;
|
||||
payload->symbolOffset = 0;
|
||||
int payloadSize = sizeof(dyld_abort_payload);
|
||||
char truncMessage[EXIT_REASON_USER_DESC_MAX_LEN];
|
||||
strlcpy(truncMessage, reason, EXIT_REASON_USER_DESC_MAX_LEN);
|
||||
os_fault_with_payload(OS_REASON_DYLD, DYLD_EXIT_REASON_OTHER, payloadBuffer, payloadSize, truncMessage, 0);
|
||||
}
|
||||
|
||||
};
|
172
src/dyld/dyld3/Tracing.h
Normal file
172
src/dyld/dyld3/Tracing.h
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef Tracing_h
|
||||
#define Tracing_h
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <System/sys/kdebug.h>
|
||||
#include <System/sys/reason.h>
|
||||
|
||||
#ifdef DARLING
|
||||
#define kdebug_trace_string(...) ((uint64_t)-1)
|
||||
#endif
|
||||
|
||||
|
||||
#define DBG_DYLD_INTERNAL_SUBCLASS (7)
|
||||
#define DBG_DYLD_API_SUBCLASS (8)
|
||||
#define DBG_DYLD_DEBUGGING_SUBCLASS (9)
|
||||
|
||||
#define DBG_DYLD_TIMING_STATIC_INITIALIZER (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 0))
|
||||
#define DBG_DYLD_TIMING_LAUNCH_EXECUTABLE (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 1))
|
||||
#define DBG_DYLD_TIMING_MAP_IMAGE (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 2))
|
||||
#define DBG_DYLD_TIMING_APPLY_FIXUPS (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 3))
|
||||
#define DBG_DYLD_TIMING_ATTACH_CODESIGNATURE (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 4))
|
||||
#define DBG_DYLD_TIMING_BUILD_CLOSURE (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 5))
|
||||
#define DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 6))
|
||||
#define DBG_DYLD_TIMING_FUNC_FOR_REMOVE_IMAGE (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 7))
|
||||
#define DBG_DYLD_TIMING_OBJC_INIT (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 8))
|
||||
#define DBG_DYLD_TIMING_OBJC_MAP (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 9))
|
||||
#define DBG_DYLD_TIMING_APPLY_INTERPOSING (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 10))
|
||||
#define DBG_DYLD_GDB_IMAGE_NOTIFIER (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 11))
|
||||
#define DBG_DYLD_REMOTE_IMAGE_NOTIFIER (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 12))
|
||||
#define DBG_DYLD_TIMING_BOOTSTRAP_START (KDBG_CODE(DBG_DYLD, DBG_DYLD_INTERNAL_SUBCLASS, 13))
|
||||
|
||||
#define DBG_DYLD_TIMING_DLOPEN (KDBG_CODE(DBG_DYLD, DBG_DYLD_API_SUBCLASS, 0))
|
||||
#define DBG_DYLD_TIMING_DLOPEN_PREFLIGHT (KDBG_CODE(DBG_DYLD, DBG_DYLD_API_SUBCLASS, 1))
|
||||
#define DBG_DYLD_TIMING_DLCLOSE (KDBG_CODE(DBG_DYLD, DBG_DYLD_API_SUBCLASS, 2))
|
||||
#define DBG_DYLD_TIMING_DLSYM (KDBG_CODE(DBG_DYLD, DBG_DYLD_API_SUBCLASS, 3))
|
||||
#define DBG_DYLD_TIMING_DLADDR (KDBG_CODE(DBG_DYLD, DBG_DYLD_API_SUBCLASS, 4))
|
||||
|
||||
#define DBG_DYLD_DEBUGGING_VM_REMAP (KDBG_CODE(DBG_DYLD, DBG_DYLD_DEBUGGING_SUBCLASS, 0))
|
||||
#define DBG_DYLD_DEBUGGING_VM_UNMAP (KDBG_CODE(DBG_DYLD, DBG_DYLD_DEBUGGING_SUBCLASS, 1))
|
||||
#define DBG_DYLD_DEBUGGING_MAP_LOOP (KDBG_CODE(DBG_DYLD, DBG_DYLD_DEBUGGING_SUBCLASS, 2))
|
||||
#define DBG_DYLD_DEBUGGING_MARK (KDBG_CODE(DBG_DYLD, DBG_DYLD_DEBUGGING_SUBCLASS, 3))
|
||||
|
||||
|
||||
#define VIS_HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
enum class DyldTimingBuildClosure : uint64_t {
|
||||
ClosureBuildFailure = 0,
|
||||
LaunchClosure_Built = 1,
|
||||
DlopenClosure_UsedSharedCacheDylib = 2,
|
||||
DlopenClosure_UsedSharedCacheOther = 3,
|
||||
DlopenClosure_NoLoad = 4,
|
||||
DlopenClosure_Built = 5
|
||||
};
|
||||
|
||||
struct VIS_HIDDEN kt_arg {
|
||||
kt_arg(int value) : _value(value), _str(nullptr) {}
|
||||
kt_arg(uint64_t value) : _value(value), _str(nullptr) {}
|
||||
kt_arg(DyldTimingBuildClosure value) : _value((uint64_t)value), _str(nullptr) {}
|
||||
kt_arg(const char *value) : _value(0), _str(value) {}
|
||||
kt_arg(void *value) : _value((uint64_t)value), _str(nullptr) {}
|
||||
uint64_t value() const { return _value; }
|
||||
private:
|
||||
void prepare(uint32_t code) {
|
||||
if (_str) {
|
||||
_value = kdebug_trace_string(code, 0, _str);
|
||||
if (_value == (uint64_t)-1) _value = 0;
|
||||
}
|
||||
}
|
||||
void destroy(uint32_t code) {
|
||||
if (_str && _value) {
|
||||
kdebug_trace_string(code, _value, nullptr);
|
||||
}
|
||||
}
|
||||
friend class ScopedTimer;
|
||||
friend uint64_t kdebug_trace_dyld_duration_start(uint32_t code, kt_arg data1, kt_arg data2, kt_arg data3);
|
||||
friend void kdebug_trace_dyld_duration_end(uint64_t pair_id, uint32_t code, kt_arg data4, kt_arg data5, kt_arg data6);
|
||||
friend void kdebug_trace_dyld_marker(uint32_t code, kt_arg data1, kt_arg data2, kt_arg data3, kt_arg data4);
|
||||
uint64_t _value;
|
||||
const char* _str;
|
||||
};
|
||||
|
||||
class VIS_HIDDEN ScopedTimer {
|
||||
public:
|
||||
ScopedTimer(uint32_t code, kt_arg data1, kt_arg data2, kt_arg data3)
|
||||
: code(code), data1(data1), data2(data2), data3(data3), data4(0), data5(0), data6(0) {
|
||||
#if BUILDING_LIBDYLD || BUILDING_DYLD
|
||||
startTimer();
|
||||
#endif
|
||||
}
|
||||
|
||||
~ScopedTimer() {
|
||||
#if BUILDING_LIBDYLD || BUILDING_DYLD
|
||||
endTimer();
|
||||
#endif
|
||||
}
|
||||
|
||||
void setData4(kt_arg data) { data4 = data; }
|
||||
void setData5(kt_arg data) { data5 = data; }
|
||||
void setData6(kt_arg data) { data6 = data; }
|
||||
private:
|
||||
#if BUILDING_LIBDYLD || BUILDING_DYLD
|
||||
void startTimer();
|
||||
void endTimer();
|
||||
#endif
|
||||
|
||||
uint32_t code;
|
||||
kt_arg data1;
|
||||
kt_arg data2;
|
||||
kt_arg data3;
|
||||
kt_arg data4;
|
||||
kt_arg data5;
|
||||
kt_arg data6;
|
||||
uint64_t current_trace_id = 0;
|
||||
};
|
||||
|
||||
VIS_HIDDEN
|
||||
void kdebug_trace_dyld_image(const uint32_t code,
|
||||
const char* path,
|
||||
const uuid_t* uuid_bytes,
|
||||
const fsobj_id_t fsobjid,
|
||||
const fsid_t fsid,
|
||||
const mach_header* load_addr);
|
||||
|
||||
VIS_HIDDEN
|
||||
bool kdebug_trace_dyld_enabled(uint32_t code);
|
||||
|
||||
VIS_HIDDEN
|
||||
void kdebug_trace_dyld_marker(uint32_t code, kt_arg data1, kt_arg data2, kt_arg data3, kt_arg data4);
|
||||
|
||||
VIS_HIDDEN
|
||||
uint64_t kdebug_trace_dyld_duration_start(uint32_t code, kt_arg data1, kt_arg data2, kt_arg data3);
|
||||
|
||||
VIS_HIDDEN
|
||||
void kdebug_trace_dyld_duration_end(uint64_t trace_id, uint32_t code, kt_arg data4, kt_arg data5, kt_arg data6);
|
||||
|
||||
VIS_HIDDEN
|
||||
void syntheticBacktrace(const char *reason, bool enableExternally=false);
|
||||
|
||||
};
|
||||
#endif /* Tracing_h */
|
190
src/dyld/dyld3/libdyldEntryVector.cpp
Normal file
190
src/dyld/dyld3/libdyldEntryVector.cpp
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_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. 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_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <mach-o/dyld_priv.h>
|
||||
#include <mach-o/dyld_images.h>
|
||||
|
||||
#include "libdyldEntryVector.h"
|
||||
#include "AllImages.h"
|
||||
#include "Array.h"
|
||||
#include "Loading.h"
|
||||
#include "Logging.h"
|
||||
#include "PathOverrides.h"
|
||||
#include "StartGlue.h"
|
||||
#include "dyld_process_info_internal.h"
|
||||
|
||||
extern "C" char start;
|
||||
|
||||
VIS_HIDDEN const char** appleParams;
|
||||
|
||||
extern bool gUseDyld3;
|
||||
|
||||
namespace dyld3 {
|
||||
|
||||
|
||||
AllImages::ProgramVars sVars;
|
||||
static void (*sChildForkFunction)();
|
||||
|
||||
static const char* leafName(const char* argv0)
|
||||
{
|
||||
if ( argv0 == nullptr )
|
||||
return "";
|
||||
|
||||
if ( const char* lastSlash = strrchr(argv0, '/') )
|
||||
return lastSlash+1;
|
||||
else
|
||||
return argv0;
|
||||
}
|
||||
|
||||
static void entry_setVars(const mach_header* mainMH, int argc, const char* argv[], const char* envp[], const char* apple[])
|
||||
{
|
||||
NXArgc = argc;
|
||||
NXArgv = argv;
|
||||
environ = (char**)envp;
|
||||
appleParams = apple;
|
||||
__progname = leafName(argv[0]);
|
||||
|
||||
sVars.mh = mainMH;
|
||||
sVars.NXArgcPtr = &NXArgc;
|
||||
sVars.NXArgvPtr = &NXArgv;
|
||||
sVars.environPtr = (const char***)&environ;
|
||||
sVars.__prognamePtr = &__progname;
|
||||
gAllImages.setProgramVars(&sVars);
|
||||
|
||||
gUseDyld3 = true;
|
||||
|
||||
setLoggingFromEnvs(envp);
|
||||
}
|
||||
|
||||
static void entry_setHaltFunction(void (*func)(const char* message) __attribute__((noreturn)) )
|
||||
{
|
||||
setHaltFunction(func);
|
||||
}
|
||||
|
||||
static void entry_setLogFunction(void (*logFunction)(const char* format, va_list list))
|
||||
{
|
||||
setLoggingFunction(logFunction);
|
||||
}
|
||||
|
||||
static void entry_setOldAllImageInfo(dyld_all_image_infos* old)
|
||||
{
|
||||
gAllImages.setOldAllImageInfo(old);
|
||||
}
|
||||
|
||||
static void entry_setNotifyMonitoringDyldMain(void (*notifyMonitoringDyldMain)()) {
|
||||
#if !TARGET_OS_DRIVERKIT
|
||||
setNotifyMonitoringDyldMain(notifyMonitoringDyldMain);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void entry_setNotifyMonitoringDyld(void (*notifyMonitoringDyld)(bool unloading,unsigned imageCount,
|
||||
const struct mach_header* loadAddresses[],
|
||||
const char* imagePaths[])) {
|
||||
#if !TARGET_OS_DRIVERKIT
|
||||
setNotifyMonitoringDyld(notifyMonitoringDyld);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void entry_setInitialImageList(const closure::LaunchClosure* closure,
|
||||
const DyldSharedCache* dyldCacheLoadAddress, const char* dyldCachePath,
|
||||
const Array<LoadedImage>& initialImages, LoadedImage& libSystem)
|
||||
{
|
||||
gAllImages.init(closure, dyldCacheLoadAddress, dyldCachePath, initialImages);
|
||||
gAllImages.applyInterposingToDyldCache(closure);
|
||||
|
||||
// run initializer for libSytem.B.dylib
|
||||
// this calls back into _dyld_initializer which calls gAllIimages.addImages()
|
||||
gAllImages.runLibSystemInitializer(libSystem);
|
||||
|
||||
// now that malloc is available, parse DYLD_ env vars
|
||||
closure::gPathOverrides.setEnvVars((const char**)environ, gAllImages.mainExecutable(), gAllImages.mainExecutableImage()->path());
|
||||
}
|
||||
|
||||
static void entry_runInitialzersBottomUp(const mach_header* mainExecutableImageLoadAddress)
|
||||
{
|
||||
gAllImages.runStartupInitialzers();
|
||||
#if !TARGET_OS_DRIVERKIT
|
||||
gAllImages.notifyMonitorMain();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void entry_setChildForkFunction(void (*func)() )
|
||||
{
|
||||
sChildForkFunction = func;
|
||||
}
|
||||
|
||||
static void entry_setRestrictions(bool allowAtPaths, bool allowEnvPaths, bool allowFallbackPaths)
|
||||
{
|
||||
gAllImages.setRestrictions(allowAtPaths, allowEnvPaths);
|
||||
closure::gPathOverrides.setFallbackPathHandling(allowFallbackPaths ?
|
||||
dyld3::closure::PathOverrides::FallbackPathMode::classic :
|
||||
dyld3::closure::PathOverrides::FallbackPathMode::restricted);
|
||||
}
|
||||
|
||||
static void entry_setHasCacheOverrides(bool someCacheImageOverriden)
|
||||
{
|
||||
gAllImages.setHasCacheOverrides(someCacheImageOverriden);
|
||||
}
|
||||
|
||||
static_assert((closure::kFormatVersion & LibDyldEntryVector::kBinaryFormatVersionMask) == closure::kFormatVersion, "binary format version overflow");
|
||||
|
||||
const LibDyldEntryVector entryVectorForDyld = {
|
||||
LibDyldEntryVector::kCurrentVectorVersion,
|
||||
closure::kFormatVersion,
|
||||
&entry_setVars,
|
||||
&entry_setHaltFunction,
|
||||
&entry_setOldAllImageInfo,
|
||||
&entry_setInitialImageList,
|
||||
&entry_runInitialzersBottomUp,
|
||||
(__typeof(LibDyldEntryVector::startFunc))address_of_start,
|
||||
&entry_setChildForkFunction,
|
||||
&entry_setLogFunction,
|
||||
&entry_setRestrictions,
|
||||
&entry_setNotifyMonitoringDyldMain,
|
||||
&entry_setNotifyMonitoringDyld,
|
||||
&entry_setHasCacheOverrides
|
||||
};
|
||||
|
||||
VIS_HIDDEN void _dyld_atfork_prepare()
|
||||
{
|
||||
gAllImages.takeLockBeforeFork();
|
||||
}
|
||||
|
||||
VIS_HIDDEN void _dyld_atfork_parent()
|
||||
{
|
||||
gAllImages.releaseLockInForkParent();
|
||||
}
|
||||
|
||||
VIS_HIDDEN void _dyld_fork_child()
|
||||
{
|
||||
// Note the child fork function updates the data structures inside dyld
|
||||
(*sChildForkFunction)();
|
||||
|
||||
// And we then need to update the structures for dyld3 in libdyld
|
||||
gAllImages.resetLockInForkChild();
|
||||
}
|
||||
|
||||
|
||||
} // namespace dyld3
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user