Upgrade to dyld-733.6

This commit is contained in:
Lubos Dolezel 2020-04-17 22:43:57 +02:00
parent 0fdb4caa71
commit c14b6598b5
576 changed files with 283646 additions and 41318 deletions

View File

@ -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/")

View File

@ -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)
#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)
#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,56 +458,137 @@
#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.
*
* Platform names:
* macos, ios, tvos, watchos
*
* Examples:
* __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_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.
*
* Platform names:
* macos, ios, tvos, watchos
*
* Examples:
*
* __API_DEPRECATED("No longer supported", macos(10.4, 10.8))
* __API_DEPRECATED("No longer supported", macos(10.4, 10.8), ios(2.0, 3.0), watchos(2.0, 3.0), tvos(9.0, 10.0))
*
* __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_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.
*
* Example:
* __API_UNAVAILABLE(macos)
* __API_UNAVAILABLE(watchos, tvos)
*/
#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
/*
* API Introductions
*
* Use to specify the release that a particular API became available.
*
* Platform names:
* macos, ios, tvos, watchos
*
* Examples:
* __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))
* If SPI decorations have not been defined elsewhere, disable them.
*/
#define __API_AVAILABLE(...) __API_AVAILABLE_GET_MACRO(__VA_ARGS__,__API_AVAILABLE4, __API_AVAILABLE3, __API_AVAILABLE2, __API_AVAILABLE1)(__VA_ARGS__)
#ifndef __SPI_AVAILABLE
#define __SPI_AVAILABLE(...)
#endif
/*
* API Deprecations
*
* Use to specify the release that a particular API became unavailable.
*
* Platform names:
* macos, ios, tvos, watchos
*
* Examples:
*
* __API_DEPRECATED("No longer supported", macos(10.4, 10.8))
* __API_DEPRECATED("No longer supported", macos(10.4, 10.8), ios(2.0, 3.0), watchos(2.0, 3.0), tvos(9.0, 10.0))
*
* __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__)
#ifndef __SPI_DEPRECATED
#define __SPI_DEPRECATED(...)
#endif
/*
* API Unavailability
* Use to specify that an API is unavailable for a particular platform.
*
* Example:
* __API_UNAVAILABLE(macos)
* __API_UNAVAILABLE(watchos, tvos)
*/
#define __API_UNAVAILABLE(...) __API_UNAVAILABLE_GET_MACRO(__VA_ARGS__,__API_UNAVAILABLE3,__API_UNAVAILABLE2,__API_UNAVAILABLE1)(__VA_ARGS__)
#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

View File

@ -2,7 +2,7 @@
* Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
@ -11,10 +11,10 @@
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@ -22,7 +22,7 @@
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
@ -63,8 +63,8 @@
* @(#)types.h 8.3 (Berkeley) 1/5/94
*/
#ifndef _MACHTYPES_H_
#define _MACHTYPES_H_
#ifndef _MACHTYPES_H_
#define _MACHTYPES_H_
#ifndef __ASSEMBLER__
#include <i386/_types.h>
@ -78,15 +78,15 @@
#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;
typedef int64_t register_t;
#else
typedef int32_t register_t;
typedef int32_t register_t;
#endif
#include <sys/_types/_intptr_t.h>
@ -94,21 +94,21 @@ typedef int32_t register_t;
#if !defined(_ANSI_SOURCE) && (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
/* These types are used for reserving the largest possible size. */
typedef u_int64_t user_addr_t;
typedef u_int64_t user_size_t;
typedef int64_t user_ssize_t;
typedef int64_t user_long_t;
typedef u_int64_t user_ulong_t;
typedef int64_t user_time_t;
typedef int64_t user_off_t;
#define USER_ADDR_NULL ((user_addr_t) 0)
typedef u_int64_t user_addr_t;
typedef u_int64_t user_size_t;
typedef int64_t user_ssize_t;
typedef int64_t user_long_t;
typedef u_int64_t user_ulong_t;
typedef int64_t user_time_t;
typedef int64_t user_off_t;
#define USER_ADDR_NULL ((user_addr_t) 0)
#define CAST_USER_ADDR_T(a_ptr) ((user_addr_t)((uintptr_t)(a_ptr)))
#endif /* !_ANSI_SOURCE && (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
/* This defines the size of syscall arguments after copying into the kernel: */
typedef u_int64_t syscall_arg_t;
typedef u_int64_t syscall_arg_t;
#endif /* __ASSEMBLER__ */
#endif /* _MACHTYPES_H_ */
#endif /* _MACHTYPES_H_ */

View 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_ */

View 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_ */

File diff suppressed because it is too large Load Diff

View 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_ */

View File

@ -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

View File

@ -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
@ -132,26 +148,27 @@ typedef enum {
NSObjectFileImageAccess
} NSObjectFileImageReturnCode;
typedef struct __NSObjectFileImage* NSObjectFileImage;
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 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) __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);
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

View File

@ -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;
const struct dyld_image_info* infoArray;
#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")));

View File

@ -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) */

View 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__

View File

@ -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 */
/* ... */
};
@ -1148,9 +1193,11 @@ 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_FUNCTION_STARTS, LC_DATA_IN_CODE,
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
@ -1282,18 +1372,18 @@ struct dyld_info_command {
* the exported symbol information for the string so far.
* If there is no exported symbol, the node starts with a zero byte.
* If there is exported info, it follows the length.
*
* First is a uleb128 containing flags. Normally, it is followed by
*
* First is a uleb128 containing flags. Normally, it is followed by
* a uleb128 encoded offset which is location of the content named
* by the symbol from the mach_header for the image. If the flags
* is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is
* a uleb128 encoded library ordinal, then a zero terminated
* UTF8 string. If the string is zero length, then the symbol
* is re-export from the specified dylib with the same name.
* If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following
* the flags is two uleb128s: the stub offset and the resolver offset.
* The stub is used by non-lazy pointers. The resolver is used
* by lazy pointers and must be called to get the actual address to use.
* If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following
* the flags is two uleb128s: the stub offset and the resolver offset.
* The stub is used by non-lazy pointers. The resolver is used
* by lazy pointers and must be called to get the actual address to use.
*
* After the optional exported symbol information is a byte of
* how many edges (0-255) that this node has leaving it,
@ -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_ */

View File

@ -1,4 +1,4 @@
module MachO [system] {
module MachO [system] [extern_c] {
export *
module arch {

View File

@ -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" {

View File

@ -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 */

View File

@ -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,

View 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_ */

View File

@ -1,8 +1,8 @@
/*
* Copyright (c) 2000-2010 Apple Computer, Inc. All rights reserved.
* Copyright (c) 2000-2018 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
@ -11,10 +11,10 @@
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@ -22,34 +22,34 @@
* 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@
*/
/*
* @OSF_COPYRIGHT@
*/
/*
/*
* Mach Operating System
* Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
* All Rights Reserved.
*
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
*
* Carnegie Mellon requests users of this software to return to
*
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
@ -70,7 +70,7 @@
*
*/
#ifndef _MACH_MACH_TYPES_H_
#ifndef _MACH_MACH_TYPES_H_
#define _MACH_MACH_TYPES_H_
#include <stdint.h>
@ -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,51 +108,56 @@
#include <mach/vm_types.h>
#include <mach/vm_region.h>
#include <mach/kmod.h>
#include <mach/dyld_kernel.h>
/*
* If we are not in the kernel, then these will all be represented by
* ports at user-space.
*/
typedef mach_port_t task_t;
typedef mach_port_t task_name_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 ipc_space_t;
typedef mach_port_t coalition_t;
typedef mach_port_t host_t;
typedef mach_port_t host_priv_t;
typedef mach_port_t host_security_t;
typedef mach_port_t processor_t;
typedef mach_port_t processor_set_t;
typedef mach_port_t processor_set_control_t;
typedef mach_port_t semaphore_t;
typedef mach_port_t lock_set_t;
typedef mach_port_t ledger_t;
typedef mach_port_t alarm_t;
typedef mach_port_t clock_serv_t;
typedef mach_port_t clock_ctrl_t;
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;
typedef mach_port_t host_security_t;
typedef mach_port_t processor_t;
typedef mach_port_t processor_set_t;
typedef mach_port_t processor_set_control_t;
typedef mach_port_t semaphore_t;
typedef mach_port_t lock_set_t;
typedef mach_port_t ledger_t;
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
* out as unique types at one point in history. So we list
* them here for compatibility.
*/
typedef processor_set_t processor_set_name_t;
typedef processor_set_t processor_set_name_t;
/*
* These types are just hard-coded as ports
*/
typedef mach_port_t clock_reply_t;
typedef mach_port_t bootstrap_t;
typedef mach_port_t mem_entry_name_port_t;
typedef mach_port_t exception_handler_t;
typedef exception_handler_t *exception_handler_array_t;
typedef mach_port_t vm_task_entry_t;
typedef mach_port_t io_master_t;
typedef mach_port_t UNDServerRef;
typedef mach_port_t clock_reply_t;
typedef mach_port_t bootstrap_t;
typedef mach_port_t mem_entry_name_port_t;
typedef mach_port_t exception_handler_t;
typedef exception_handler_t *exception_handler_array_t;
typedef mach_port_t vm_task_entry_t;
typedef mach_port_t io_master_t;
typedef mach_port_t UNDServerRef;
/*
* Mig doesn't translate the components of an array.
@ -160,13 +166,13 @@ typedef mach_port_t UNDServerRef;
* are not completely accurate at the moment for other kernel
* components.
*/
typedef task_t *task_array_t;
typedef thread_t *thread_array_t;
typedef processor_set_t *processor_set_array_t;
typedef processor_set_t *processor_set_name_array_t;
typedef processor_t *processor_array_t;
typedef thread_act_t *thread_act_array_t;
typedef ledger_t *ledger_array_t;
typedef task_t *task_array_t;
typedef thread_t *thread_array_t;
typedef processor_set_t *processor_set_array_t;
typedef processor_set_t *processor_set_name_array_t;
typedef processor_t *processor_array_t;
typedef thread_act_t *thread_act_array_t;
typedef ledger_t *ledger_array_t;
/*
* However the real mach_types got declared, we also have to declare
@ -174,66 +180,71 @@ typedef ledger_t *ledger_array_t;
* had declared the user interfaces at one point. Someday these should
* go away.
*/
typedef task_t task_port_t;
typedef task_array_t task_port_array_t;
typedef thread_t thread_port_t;
typedef thread_array_t thread_port_array_t;
typedef ipc_space_t ipc_space_port_t;
typedef host_t host_name_t;
typedef host_t host_name_port_t;
typedef processor_set_t processor_set_port_t;
typedef processor_set_t processor_set_name_port_t;
typedef processor_set_array_t processor_set_name_port_array_t;
typedef processor_set_t processor_set_control_port_t;
typedef processor_t processor_port_t;
typedef processor_array_t processor_port_array_t;
typedef thread_act_t thread_act_port_t;
typedef thread_act_array_t thread_act_port_array_t;
typedef semaphore_t semaphore_port_t;
typedef lock_set_t lock_set_port_t;
typedef ledger_t ledger_port_t;
typedef ledger_array_t ledger_port_array_t;
typedef alarm_t alarm_port_t;
typedef clock_serv_t clock_serv_port_t;
typedef clock_ctrl_t clock_ctrl_port_t;
typedef exception_handler_t exception_port_t;
typedef task_t task_port_t;
typedef task_array_t task_port_array_t;
typedef thread_t thread_port_t;
typedef thread_array_t thread_port_array_t;
typedef ipc_space_t ipc_space_port_t;
typedef host_t host_name_t;
typedef host_t host_name_port_t;
typedef processor_set_t processor_set_port_t;
typedef processor_set_t processor_set_name_port_t;
typedef processor_set_array_t processor_set_name_port_array_t;
typedef processor_set_t processor_set_control_port_t;
typedef processor_t processor_port_t;
typedef processor_array_t processor_port_array_t;
typedef thread_act_t thread_act_port_t;
typedef thread_act_array_t thread_act_port_array_t;
typedef semaphore_t semaphore_port_t;
typedef lock_set_t lock_set_port_t;
typedef ledger_t ledger_port_t;
typedef ledger_array_t ledger_port_array_t;
typedef alarm_t alarm_port_t;
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 THREAD_NULL ((thread_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 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 PROCESSOR_SET_NULL ((processor_set_t) 0)
#define PROCESSOR_NULL ((processor_t) 0)
#define SEMAPHORE_NULL ((semaphore_t) 0)
#define LOCK_SET_NULL ((lock_set_t) 0)
#define LEDGER_NULL ((ledger_t) 0)
#define ALARM_NULL ((alarm_t) 0)
#define CLOCK_NULL ((clock_t) 0)
#define UND_SERVER_NULL ((UNDServerRef) 0)
#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 PROCESSOR_SET_NULL ((processor_set_t) 0)
#define PROCESSOR_NULL ((processor_t) 0)
#define SEMAPHORE_NULL ((semaphore_t) 0)
#define LOCK_SET_NULL ((lock_set_t) 0)
#define LEDGER_NULL ((ledger_t) 0)
#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;
#define LEDGER_ITEM_INFINITY ((ledger_item_t) (~0))
typedef natural_t ledger_item_t;
#define LEDGER_ITEM_INFINITY ((ledger_item_t) (~0))
typedef int64_t ledger_amount_t;
typedef int64_t ledger_amount_t;
#define LEDGER_LIMIT_INFINITY ((ledger_amount_t)((1ULL << 63) - 1))
typedef mach_vm_offset_t *emulation_vector_t;
typedef char *user_subsystem_t;
typedef mach_vm_offset_t *emulation_vector_t;
typedef char *user_subsystem_t;
typedef char *labelstr_t;
typedef char *labelstr_t;
/*
* Backwards compatibility, for those programs written
* before mach/{std,mach}_types.{defs,h} were set up.
*/
#include <mach/std_types.h>
#endif /* _MACH_MACH_TYPES_H_ */
#endif /* _MACH_MACH_TYPES_H_ */

View 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) */

View File

@ -1,8 +1,8 @@
/*
* Copyright (c) 2000-2009 Apple Inc. All rights reserved.
* Copyright (c) 2000-2019 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
@ -11,10 +11,10 @@
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@ -22,34 +22,34 @@
* 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@
*/
/*
* @OSF_COPYRIGHT@
*/
/*
/*
* Mach Operating System
* Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
* All Rights Reserved.
*
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
*
* Carnegie Mellon requests users of this software to return to
*
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
@ -63,8 +63,8 @@
*
*/
#ifndef _MACH_VM_STATISTICS_H_
#define _MACH_VM_STATISTICS_H_
#ifndef _MACH_VM_STATISTICS_H_
#define _MACH_VM_STATISTICS_H_
#include <mach/machine/vm_types.h>
@ -73,31 +73,31 @@
* vm_statistics
*
* History:
* rev0 - original structure.
* rev1 - added purgable info (purgable_count and purges).
* rev2 - added speculative_count.
* rev0 - original structure.
* rev1 - added purgable info (purgable_count and purges).
* rev2 - added speculative_count.
*
* Note: you cannot add any new fields to this structure. Add them below in
* vm_statistics64.
* vm_statistics64.
*/
struct vm_statistics {
natural_t free_count; /* # of pages free */
natural_t active_count; /* # of pages active */
natural_t inactive_count; /* # of pages inactive */
natural_t wire_count; /* # of pages wired down */
natural_t zero_fill_count; /* # of zero fill pages */
natural_t reactivations; /* # of pages reactivated */
natural_t pageins; /* # of pageins */
natural_t pageouts; /* # of pageouts */
natural_t faults; /* # of faults */
natural_t cow_faults; /* # of copy-on-writes */
natural_t lookups; /* object cache lookups */
natural_t hits; /* object cache hits */
natural_t free_count; /* # of pages free */
natural_t active_count; /* # of pages active */
natural_t inactive_count; /* # of pages inactive */
natural_t wire_count; /* # of pages wired down */
natural_t zero_fill_count; /* # of zero fill pages */
natural_t reactivations; /* # of pages reactivated */
natural_t pageins; /* # of pageins */
natural_t pageouts; /* # of pageouts */
natural_t faults; /* # of faults */
natural_t cow_faults; /* # of copy-on-writes */
natural_t lookups; /* object cache lookups */
natural_t hits; /* object cache hits */
/* added for rev1 */
natural_t purgeable_count; /* # of pages purgeable */
natural_t purges; /* # of pages purged */
natural_t purgeable_count; /* # of pages purgeable */
natural_t purges; /* # of pages purged */
/* added for rev2 */
/*
@ -106,23 +106,23 @@ struct vm_statistics {
* used to hold data that was read speculatively from disk but
* haven't actually been used by anyone so far.
*/
natural_t speculative_count; /* # of pages speculative */
natural_t speculative_count; /* # of pages speculative */
};
/* Used by all architectures */
typedef struct vm_statistics *vm_statistics_t;
typedef struct vm_statistics vm_statistics_data_t;
typedef struct vm_statistics *vm_statistics_t;
typedef struct vm_statistics vm_statistics_data_t;
/*
/*
* vm_statistics64
*
* History:
* rev0 - original structure.
* rev1 - added purgable info (purgable_count and purges).
* rev2 - added speculative_count.
* rev0 - original structure.
* rev1 - added purgable info (purgable_count and purges).
* rev2 - added speculative_count.
* ----
* rev3 - changed name to vm_statistics64.
* changed some fields in structure to 64-bit on
* rev3 - changed name to vm_statistics64.
* changed some fields in structure to 64-bit on
* arm, i386 and x86_64 architectures.
* rev4 - require 64-bit alignment for efficient access
* in the kernel. No change to reported data.
@ -130,44 +130,44 @@ typedef struct vm_statistics vm_statistics_data_t;
*/
struct vm_statistics64 {
natural_t free_count; /* # of pages free */
natural_t active_count; /* # of pages active */
natural_t inactive_count; /* # of pages inactive */
natural_t wire_count; /* # of pages wired down */
uint64_t zero_fill_count; /* # of zero fill pages */
uint64_t reactivations; /* # of pages reactivated */
uint64_t pageins; /* # of pageins */
uint64_t pageouts; /* # of pageouts */
uint64_t faults; /* # of faults */
uint64_t cow_faults; /* # of copy-on-writes */
uint64_t lookups; /* object cache lookups */
uint64_t hits; /* object cache hits */
uint64_t purges; /* # of pages purged */
natural_t purgeable_count; /* # of pages purgeable */
natural_t free_count; /* # of pages free */
natural_t active_count; /* # of pages active */
natural_t inactive_count; /* # of pages inactive */
natural_t wire_count; /* # of pages wired down */
uint64_t zero_fill_count; /* # of zero fill pages */
uint64_t reactivations; /* # of pages reactivated */
uint64_t pageins; /* # of pageins */
uint64_t pageouts; /* # of pageouts */
uint64_t faults; /* # of faults */
uint64_t cow_faults; /* # of copy-on-writes */
uint64_t lookups; /* object cache lookups */
uint64_t hits; /* object cache hits */
uint64_t purges; /* # of pages purged */
natural_t purgeable_count; /* # of pages purgeable */
/*
* NB: speculative pages are already accounted for in "free_count",
* so "speculative_count" is the number of "free" pages that are
* used to hold data that was read speculatively from disk but
* haven't actually been used by anyone so far.
*/
natural_t speculative_count; /* # of pages speculative */
natural_t speculative_count; /* # of pages speculative */
/* added for rev1 */
uint64_t decompressions; /* # of pages decompressed */
uint64_t compressions; /* # of pages compressed */
uint64_t swapins; /* # of pages swapped in (via compression segments) */
uint64_t swapouts; /* # of pages swapped out (via compression segments) */
natural_t compressor_page_count; /* # of pages used by the compressed pager to hold all the compressed data */
natural_t throttled_count; /* # of pages throttled */
natural_t external_page_count; /* # of pages that are file-backed (non-swap) */
natural_t internal_page_count; /* # of pages that are anonymous */
uint64_t total_uncompressed_pages_in_compressor; /* # of pages (uncompressed) held within the compressor. */
uint64_t decompressions; /* # of pages decompressed */
uint64_t compressions; /* # of pages compressed */
uint64_t swapins; /* # of pages swapped in (via compression segments) */
uint64_t swapouts; /* # of pages swapped out (via compression segments) */
natural_t compressor_page_count; /* # of pages used by the compressed pager to hold all the compressed data */
natural_t throttled_count; /* # of pages throttled */
natural_t external_page_count; /* # of pages that are file-backed (non-swap) */
natural_t internal_page_count; /* # of pages that are anonymous */
uint64_t total_uncompressed_pages_in_compressor; /* # of pages (uncompressed) held within the compressor. */
} __attribute__((aligned(8)));
typedef struct vm_statistics64 *vm_statistics64_t;
typedef struct vm_statistics64 vm_statistics64_data_t;
typedef struct vm_statistics64 *vm_statistics64_t;
typedef struct vm_statistics64 vm_statistics64_data_t;
/*
/*
* VM_STATISTICS_TRUNCATE_TO_32_BIT
*
* This is used by host_statistics() to truncate and peg the 64-bit in-kernel values from
@ -175,31 +175,31 @@ typedef struct vm_statistics64 vm_statistics64_data_t;
*/
#define VM_STATISTICS_TRUNCATE_TO_32_BIT(value) ((uint32_t)(((value) > UINT32_MAX ) ? UINT32_MAX : (value)))
/*
/*
* vm_extmod_statistics
*
* Structure to record modifications to a task by an
* external agent.
*
* History:
* rev0 - original structure.
* rev0 - original structure.
*/
struct vm_extmod_statistics {
int64_t task_for_pid_count; /* # of times task port was looked up */
int64_t task_for_pid_caller_count; /* # of times this task called task_for_pid */
int64_t thread_creation_count; /* # of threads created in task */
int64_t thread_creation_caller_count; /* # of threads created by task */
int64_t thread_set_state_count; /* # of register state sets in task */
int64_t thread_set_state_caller_count; /* # of register state sets by task */
int64_t task_for_pid_count; /* # of times task port was looked up */
int64_t task_for_pid_caller_count; /* # of times this task called task_for_pid */
int64_t thread_creation_count; /* # of threads created in task */
int64_t thread_creation_caller_count; /* # of threads created by task */
int64_t thread_set_state_count; /* # of register state sets in task */
int64_t thread_set_state_caller_count; /* # of register state sets by task */
} __attribute__((aligned(8)));
typedef struct vm_extmod_statistics *vm_extmod_statistics_t;
typedef struct vm_extmod_statistics vm_extmod_statistics_data_t;
typedef struct vm_purgeable_stat {
uint64_t count;
uint64_t size;
uint64_t count;
uint64_t size;
}vm_purgeable_stat_t;
struct vm_purgeable_info {
@ -208,7 +208,7 @@ struct vm_purgeable_info {
vm_purgeable_stat_t lifo_data[8];
};
typedef struct vm_purgeable_info *vm_purgeable_info_t;
typedef struct vm_purgeable_info *vm_purgeable_info_t;
/* included for the vm_map_page_query call */
@ -218,25 +218,30 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
#define VM_PAGE_QUERY_PAGE_DIRTY 0x8
#define VM_PAGE_QUERY_PAGE_PAGED_OUT 0x10
#define VM_PAGE_QUERY_PAGE_COPIED 0x20
#define VM_PAGE_QUERY_PAGE_SPECULATIVE 0x40
#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_SPECULATIVE 0x40
#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
/*
* VM allocation flags:
*
*
* VM_FLAGS_FIXED
* (really the absence of VM_FLAGS_ANYWHERE)
* (really the absence of VM_FLAGS_ANYWHERE)
* Allocate new VM region at the specified virtual address, if possible.
*
*
* VM_FLAGS_ANYWHERE
* Allocate new VM region anywhere it would fit in the address space.
*
* 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,48 +257,87 @@ 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_NO_CACHE 0x0010
#define VM_FLAGS_OVERWRITE 0x4000 /* delete any existing mappings first */
#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
* 3 bits that specify whether large pages should be used instead of
* base pages (!=0), as well as the requested page size.
*/
#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_ALIAS_MASK 0xFF000000
#define VM_GET_FLAGS_ALIAS(flags, alias) \
(alias) = ((flags) & VM_FLAGS_ALIAS_MASK) >> 24
#define VM_SET_FLAGS_ALIAS(flags, alias) \
(flags) = (((flags) & ~VM_FLAGS_ALIAS_MASK) | \
(((alias) & ~VM_FLAGS_ALIAS_MASK) << 24))
#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
#define VM_SET_FLAGS_ALIAS(flags, alias) \
(flags) = (((flags) & ~VM_FLAGS_ALIAS_MASK) | \
(((alias) & ~VM_FLAGS_ALIAS_MASK) << 24))
/* These are the flags that we accept from user-space */
#define VM_FLAGS_USER_ALLOCATE (VM_FLAGS_FIXED | \
VM_FLAGS_ANYWHERE | \
VM_FLAGS_PURGABLE | \
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_DATA_ADDR)
#define VM_FLAGS_USER_REMAP (VM_FLAGS_FIXED | \
VM_FLAGS_ANYWHERE | \
VM_FLAGS_OVERWRITE| \
VM_FLAGS_RETURN_DATA_ADDR)
#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_RESILIENT_CODESIGN | \
VM_FLAGS_RESILIENT_MEDIA)
#define VM_FLAGS_SUPERPAGE_SHIFT 16
#define SUPERPAGE_NONE 0 /* no superpages, if all bits are 0 */
#define SUPERPAGE_SIZE_ANY 1
#define SUPERPAGE_NONE 0 /* no superpages, if all bits are 0 */
#define SUPERPAGE_SIZE_ANY 1
#define VM_FLAGS_SUPERPAGE_NONE (SUPERPAGE_NONE << VM_FLAGS_SUPERPAGE_SHIFT)
#define VM_FLAGS_SUPERPAGE_SIZE_ANY (SUPERPAGE_SIZE_ANY << VM_FLAGS_SUPERPAGE_SHIFT)
#define SUPERPAGE_SIZE_2MB 2
#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,18 +351,19 @@ 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
#define VM_MEMORY_IOKIT 21
#define VM_MEMORY_STACK 30
#define VM_MEMORY_GUARD 31
#define VM_MEMORY_SHARED_PMAP 32
#define VM_MEMORY_SHARED_PMAP 32
/* memory containing a dylib */
#define VM_MEMORY_DYLIB 33
#define VM_MEMORY_DYLIB 33
#define VM_MEMORY_OBJC_DISPATCHERS 34
/* Was a nested pmap (VM_MEMORY_SHARED_PMAP) which has now been unnested */
#define VM_MEMORY_UNSHARED_PMAP 35
#define VM_MEMORY_UNSHARED_PMAP 35
// Placeholders for now -- as we analyze the libraries and find how they
@ -337,16 +382,19 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
#define VM_MEMORY_TCMALLOC 53
/* private raster data (i.e. layers, some images, QGL allocator) */
#define VM_MEMORY_COREGRAPHICS_DATA 54
#define VM_MEMORY_COREGRAPHICS_DATA 54
/* shared image and font caches */
#define VM_MEMORY_COREGRAPHICS_SHARED 55
#define VM_MEMORY_COREGRAPHICS_SHARED 55
/* Memory used for virtual framebuffers, shadowing buffers, etc... */
#define VM_MEMORY_COREGRAPHICS_FRAMEBUFFERS 56
#define VM_MEMORY_COREGRAPHICS_FRAMEBUFFERS 56
/* Window backing stores, custom shadow data, and compressed backing stores */
#define VM_MEMORY_COREGRAPHICS_BACKINGSTORES 57
#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
@ -378,13 +427,13 @@ typedef struct vm_purgeable_info *vm_purgeable_info_t;
#define VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS 69
/* ImageIO memory */
#define VM_MEMORY_IMAGEIO 70
#define VM_MEMORY_IMAGEIO 70
/* CoreProfile memory */
#define VM_MEMORY_COREPROFILE 71
#define VM_MEMORY_COREPROFILE 71
/* assetsd / MobileSlideShow memory */
#define VM_MEMORY_ASSETSD 72
#define VM_MEMORY_ASSETSD 72
/* libsystem_kernel os_once_alloc */
#define VM_MEMORY_OS_ALLOC_ONCE 73
@ -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_ */
#endif /* _MACH_VM_STATISTICS_H_ */

View File

@ -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,66 +21,145 @@
#ifndef __OS_AVAILABILITY__
#define __OS_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>
/*
Macros for defining which versions/platform a given symbol can be used.
@see http://clang.llvm.org/docs/AttributeReference.html#availability
*/
#if defined(__has_feature) && defined(__has_attribute)
#if __has_attribute(availability)
/*
* API Introductions
*
* Use to specify the release that a particular API became available.
*
* Platform names:
* macos, ios, tvos, watchos
*
* Examples:
* 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))
*/
#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.
*
* Platform names:
* macos, ios, tvos, watchos
*
* Examples:
*
* API_DEPRECATED("No longer supported", macos(10.4, 10.8))
* API_DEPRECATED("No longer supported", macos(10.4, 10.8), ios(2.0, 3.0), watchos(2.0, 3.0), tvos(9.0, 10.0))
*
* 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_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.
*
* Example:
* API_UNAVAILABLE(macos)
* API_UNAVAILABLE(watchos, tvos)
*/
#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
/*
* API Introductions
*
* Use to specify the release that a particular API became available.
*
* Platform names:
* macos, ios, tvos, watchos
*
* Examples:
* 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))
* If SPI decorations have not been defined elsewhere, disable them.
*/
#define API_AVAILABLE(...) __API_AVAILABLE_GET_MACRO(__VA_ARGS__,__API_AVAILABLE4, __API_AVAILABLE3, __API_AVAILABLE2, __API_AVAILABLE1)(__VA_ARGS__)
#ifndef SPI_AVAILABLE
#define SPI_AVAILABLE(...)
#endif
/*
* Stub for SPI_AVAILABLE
*/
#define SPI_AVAILABLE(...)
#ifndef SPI_DEPRECATED
#define SPI_DEPRECATED(...)
#endif
/*
* API Deprecations
*
* Use to specify the release that a particular API became unavailable.
*
* Platform names:
* macos, ios, tvos, watchos
*
* Examples:
*
* API_DEPRECATED("No longer supported", macos(10.4, 10.8))
* API_DEPRECATED("No longer supported", macos(10.4, 10.8), ios(2.0, 3.0), watchos(2.0, 3.0), tvos(9.0, 10.0))
*
* 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__)
/*
* API Unavailability
* Use to specify that an API is unavailable for a particular platform.
*
* Example:
* API_UNAVAILABLE(macos)
* API_UNAVAILABLE(watchos, tvos)
*/
#define API_UNAVAILABLE(...) __API_UNAVAILABLE_GET_MACRO(__VA_ARGS__,__API_UNAVAILABLE3,__API_UNAVAILABLE2,__API_UNAVAILABLE1)(__VA_ARGS__)
#ifndef SPI_DEPRECATED_WITH_REPLACEMENT
#define SPI_DEPRECATED_WITH_REPLACEMENT(...)
#endif
#endif /* __OS_AVAILABILITY__ */

View 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 */

View 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 */

View 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 */

View 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 */

View File

@ -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 {

View File

@ -1,8 +1,8 @@
/*
* 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@
*
*
* 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
@ -11,10 +11,10 @@
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@ -22,7 +22,7 @@
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
@ -73,7 +73,7 @@
* [TYM] posix_typed_mem_open()
*/
#ifndef _SYS_MMAN_H_
#ifndef _SYS_MMAN_H_
#define _SYS_MMAN_H_
#include <sys/appleapiopts.h>
@ -92,127 +92,156 @@
/*
* Protections are chosen from these bits, or-ed together
*/
#define PROT_NONE 0x00 /* [MC2] no permissions */
#define PROT_READ 0x01 /* [MC2] pages can be read */
#define PROT_WRITE 0x02 /* [MC2] pages can be written */
#define PROT_EXEC 0x04 /* [MC2] pages can be executed */
#define PROT_NONE 0x00 /* [MC2] no permissions */
#define PROT_READ 0x01 /* [MC2] pages can be read */
#define PROT_WRITE 0x02 /* [MC2] pages can be written */
#define PROT_EXEC 0x04 /* [MC2] pages can be executed */
/*
* Flags contain sharing type and options.
* Sharing types; choose one.
*/
#define MAP_SHARED 0x0001 /* [MF|SHM] share changes */
#define MAP_PRIVATE 0x0002 /* [MF|SHM] changes are private */
#define MAP_SHARED 0x0001 /* [MF|SHM] share changes */
#define MAP_PRIVATE 0x0002 /* [MF|SHM] changes are private */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define MAP_COPY MAP_PRIVATE /* Obsolete */
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define MAP_COPY MAP_PRIVATE /* Obsolete */
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
/*
* Other flags
*/
#define MAP_FIXED 0x0010 /* [MF|SHM] interpret addr exactly */
#define MAP_FIXED 0x0010 /* [MF|SHM] interpret addr exactly */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define MAP_RENAME 0x0020 /* Sun: rename private pages to file */
#define MAP_NORESERVE 0x0040 /* Sun: don't reserve needed swap area */
#define MAP_RESERVED0080 0x0080 /* previously unimplemented MAP_INHERIT */
#define MAP_NOEXTEND 0x0100 /* for MAP_FILE, don't change file size */
#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 */
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define MAP_RENAME 0x0020 /* Sun: rename private pages to file */
#define MAP_NORESERVE 0x0040 /* Sun: don't reserve needed swap area */
#define MAP_RESERVED0080 0x0080 /* previously unimplemented MAP_INHERIT */
#define MAP_NOEXTEND 0x0100 /* for MAP_FILE, don't change file size */
#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) */
/*
* Process memory locking
*/
#define MCL_CURRENT 0x0001 /* [ML] Lock only current memory */
#define MCL_FUTURE 0x0002 /* [ML] Lock all future memory as well */
#define MCL_CURRENT 0x0001 /* [ML] Lock only current memory */
#define MCL_FUTURE 0x0002 /* [ML] Lock all future memory as well */
/*
* Error return from mmap()
*/
#define MAP_FAILED ((void *)-1) /* [MF|SHM] mmap failed */
#define MAP_FAILED ((void *)-1) /* [MF|SHM] mmap failed */
/*
* msync() flags
*/
#define MS_ASYNC 0x0001 /* [MF|SIO] return immediately */
#define MS_INVALIDATE 0x0002 /* [MF|SIO] invalidate all cached data */
#define MS_SYNC 0x0010 /* [MF|SIO] msync synchronously */
#define MS_ASYNC 0x0001 /* [MF|SIO] return immediately */
#define MS_INVALIDATE 0x0002 /* [MF|SIO] invalidate all cached data */
#define MS_SYNC 0x0010 /* [MF|SIO] msync synchronously */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#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) */
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
/*
* Advice to madvise
*/
#define POSIX_MADV_NORMAL 0 /* [MC1] no further special treatment */
#define POSIX_MADV_RANDOM 1 /* [MC1] expect random page refs */
#define POSIX_MADV_SEQUENTIAL 2 /* [MC1] expect sequential page refs */
#define POSIX_MADV_WILLNEED 3 /* [MC1] will need these pages */
#define POSIX_MADV_DONTNEED 4 /* [MC1] dont need these pages */
#define POSIX_MADV_NORMAL 0 /* [MC1] no further special treatment */
#define POSIX_MADV_RANDOM 1 /* [MC1] expect random page refs */
#define POSIX_MADV_SEQUENTIAL 2 /* [MC1] expect sequential page refs */
#define POSIX_MADV_WILLNEED 3 /* [MC1] will need these pages */
#define POSIX_MADV_DONTNEED 4 /* [MC1] dont need these pages */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define MADV_NORMAL POSIX_MADV_NORMAL
#define MADV_RANDOM POSIX_MADV_RANDOM
#define MADV_SEQUENTIAL POSIX_MADV_SEQUENTIAL
#define MADV_WILLNEED POSIX_MADV_WILLNEED
#define MADV_DONTNEED POSIX_MADV_DONTNEED
#define MADV_FREE 5 /* pages unneeded, discard contents */
#define MADV_ZERO_WIRED_PAGES 6 /* zero the wired pages that have not been unwired before the entry is deleted */
#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_NORMAL POSIX_MADV_NORMAL
#define MADV_RANDOM POSIX_MADV_RANDOM
#define MADV_SEQUENTIAL POSIX_MADV_SEQUENTIAL
#define MADV_WILLNEED POSIX_MADV_WILLNEED
#define MADV_DONTNEED POSIX_MADV_DONTNEED
#define MADV_FREE 5 /* pages unneeded, discard contents */
#define MADV_ZERO_WIRED_PAGES 6 /* zero the wired pages that have not been unwired before the entry is deleted */
#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
*/
#define MINCORE_INCORE 0x1 /* Page is incore */
#define MINCORE_REFERENCED 0x2 /* Page has been referenced by us */
#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 */
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define MINCORE_INCORE 0x1 /* Page is incore */
#define MINCORE_REFERENCED 0x2 /* Page has been referenced by us */
#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) */
__BEGIN_DECLS
/* [ML] */
int mlockall(int);
int munlockall(void);
int mlockall(int);
int munlockall(void);
/* [MR] */
int mlock(const void *, size_t);
int mlock(const void *, size_t);
#ifndef _MMAP
#define _MMAP
#define _MMAP
/* [MC3]*/
void * mmap(void *, size_t, int, int, int, off_t) __DARWIN_ALIAS(mmap);
void * mmap(void *, size_t, int, int, int, off_t) __DARWIN_ALIAS(mmap);
#endif
/* [MPR] */
int mprotect(void *, size_t, int) __DARWIN_ALIAS(mprotect);
int mprotect(void *, size_t, int) __DARWIN_ALIAS(mprotect);
/* [MF|SIO] */
int msync(void *, size_t, int) __DARWIN_ALIAS_C(msync);
int msync(void *, size_t, int) __DARWIN_ALIAS_C(msync);
/* [MR] */
int munlock(const void *, size_t);
int munlock(const void *, size_t);
/* [MC3]*/
int munmap(void *, size_t) __DARWIN_ALIAS(munmap);
int munmap(void *, size_t) __DARWIN_ALIAS(munmap);
/* [SHM] */
int shm_open(const char *, int, ...);
int shm_unlink(const char *);
int shm_open(const char *, int, ...);
int shm_unlink(const char *);
/* [ADV] */
int posix_madvise(void *, size_t, int);
int posix_madvise(void *, size_t, int);
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
int madvise(void *, size_t, int);
int mincore(const void *, size_t, char *);
int minherit(void *, size_t, int);
int madvise(void *, size_t, int);
int mincore(const void *, size_t, char *);
int minherit(void *, size_t, int);
#endif

View File

@ -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
View 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

View File

@ -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
View 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

View File

@ -0,0 +1,2 @@
CODE_SIGN_ENTITLEMENTS[sdk=embedded*] = dyld3/closured/closured_entitlements.plist

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View 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.

View File

@ -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)

View 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.
.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View 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 = {}

View 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)`

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

241
src/dyld/dyld3/APIs.h Normal file
View 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__

View 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

File diff suppressed because it is too large Load Diff

278
src/dyld/dyld3/AllImages.h Normal file
View 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
View 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 */

View 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
View 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

File diff suppressed because it is too large Load Diff

957
src/dyld/dyld3/Closure.h Normal file
View 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

File diff suppressed because it is too large Load Diff

View 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 */

View 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 */

View 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;
}

View 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 */

View 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;
}

View 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 */

View 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

View 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 */

View 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

View 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

View File

@ -42,28 +42,36 @@ 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,
CS_HASH_SIZE_SHA256_TRUNCATED = 20,
CSSLOT_CODEDIRECTORY = 0,
CSSLOT_INFOSLOT = 1,
CSSLOT_REQUIREMENTS = 2,
CSSLOT_RESOURCEDIR = 3,
CSSLOT_APPLICATION = 4,
CSSLOT_ENTITLEMENTS = 5,
CSSLOT_CMS_SIGNATURE = 0x10000,
CSSLOT_CODEDIRECTORY = 0,
CSSLOT_INFOSLOT = 1,
CSSLOT_REQUIREMENTS = 2,
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
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 {

View 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

View 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
View 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__

View 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__

View 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
View 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
View 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
View 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
View 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
View 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__

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

273
src/dyld/dyld3/MachOFile.h Normal file
View 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 */

File diff suppressed because it is too large Load Diff

View 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
View 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 */

View 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

View 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__

View 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

View 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__

View File

@ -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

View 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
View 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
View 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 */

View 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