| 1 | /* |
| 2 | * Copyright (c) 2006-2010 Apple Inc. All rights reserved. |
| 3 | * |
| 4 | * @APPLE_LICENSE_HEADER_START@ |
| 5 | * |
| 6 | * This file contains Original Code and/or Modifications of Original Code |
| 7 | * as defined in and that are subject to the Apple Public Source License |
| 8 | * Version 2.0 (the 'License'). You may not use this file except in |
| 9 | * compliance with the License. Please obtain a copy of the License at |
| 10 | * http://www.opensource.apple.com/apsl/ and read it before using this |
| 11 | * file. |
| 12 | * |
| 13 | * The Original Code and all software distributed under the License are |
| 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
| 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
| 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
| 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
| 18 | * Please see the License for the specific language governing rights and |
| 19 | * limitations under the License. |
| 20 | * |
| 21 | * @APPLE_LICENSE_HEADER_END@ |
| 22 | */ |
| 23 | #ifndef _DYLD_IMAGES_ |
| 24 | #define _DYLD_IMAGES_ |
| 25 | |
| 26 | #include <stdbool.h> |
| 27 | #include <uuid/uuid.h> |
| 28 | #include <TargetConditionals.h> |
| 29 | |
| 30 | #ifndef __OPEN_SOURCE__ |
| 31 | #if !0 |
| 32 | #include <unistd.h> |
| 33 | #include <mach/mach.h> |
| 34 | #endif |
| 35 | #endif |
| 36 | |
| 37 | #if defined(__cplusplus) && (BUILDING_LIBDYLD || BUILDING_DYLD) |
| 38 | #include <atomic> |
| 39 | #endif |
| 40 | |
| 41 | #ifdef __cplusplus |
| 42 | extern "C" { |
| 43 | #endif |
| 44 | |
| 45 | |
| 46 | |
| 47 | /* |
| 48 | *	Beginning in Mac OS X 10.4, this is how gdb discovers which mach-o images are loaded in a process. |
| 49 | * |
| 50 | *	gdb looks for the symbol "_dyld_all_image_infos" in dyld. It contains the fields below. |
| 51 | * |
| 52 | *	For a snashot of what images are currently loaded, the infoArray fields contain a pointer |
| 53 | *	to an array of all images. If infoArray is NULL, it means it is being modified, come back later. |
| 54 | * |
| 55 | *	To be notified of changes, gdb sets a break point on the address pointed to by the notificationn |
| 56 | *	field. The function it points to is called by dyld with an array of information about what images |
| 57 | *	have been added (dyld_image_adding) or are about to be removed (dyld_image_removing). |
| 58 | * |
| 59 | * The notification is called after infoArray is updated. This means that if gdb attaches to a process |
| 60 | * and infoArray is NULL, gdb can set a break point on notification and let the proccess continue to |
| 61 | * run until the break point. Then gdb can inspect the full infoArray. |
| 62 | * |
| 63 | * The dyldVersion field always points to a C string that contains the dyld version. For instance, |
| 64 | * in dyld-127.3, dyldVersion would contain a pointer to "127.3". |
| 65 | * |
| 66 | * The errorMessage and terminationFlags fields are normally zero. If dyld terminates a process |
| 67 | * (for instance because a required dylib or symbol is missing), then the errorMessage field will |
| 68 | * be set to point to a C string message buffer containing the reason dyld terminate the process. |
| 69 | * The low bit of the terminationFlags will be set if dyld terminated the process before any user |
| 70 | * code ran, in which case there is no need for the crash log to contain the backtrace. |
| 71 | * |
| 72 | * When dyld terminates a process because some required dylib or symbol cannot be bound, in |
| 73 | * addition to the errorMessage field, it now sets the errorKind field and the corresponding |
| 74 | * fields: errorClientOfDylibPath, errorTargetDylibPath, errorSymbol. |
| 75 | * |
| 76 | */ |
| 77 | |
| 78 | enum dyld_image_mode { dyld_image_adding=0, dyld_image_removing=1, dyld_image_info_change=2, dyld_image_dyld_moved=3 }; |
| 79 | |
| 80 | struct dyld_image_info { |
| 81 | 	const struct mach_header*	imageLoadAddress;	/* base address image is mapped into */ |
| 82 | 	const char*					imageFilePath;		/* path dyld used to load the image */ |
| 83 | 	uintptr_t					imageFileModDate;	/* time_t of image file */ |
| 84 | 													/* if stat().st_mtime of imageFilePath does not match imageFileModDate, */ |
| 85 | 													/* then file has been modified since dyld loaded it */ |
| 86 | }; |
| 87 | |
| 88 | struct dyld_uuid_info { |
| 89 | 	const struct mach_header*	imageLoadAddress;	/* base address image is mapped into */ |
| 90 | 	uuid_t						imageUUID;			/* UUID of image */ |
| 91 | }; |
| 92 | |
| 93 | #define DYLD_AOT_IMAGE_KEY_SIZE 32 |
| 94 | struct dyld_aot_image_info { |
| 95 | const struct mach_header* x86LoadAddress; |
| 96 | const struct mach_header* aotLoadAddress; |
| 97 | uint64_t aotImageSize; |
| 98 | uint8_t aotImageKey[DYLD_AOT_IMAGE_KEY_SIZE]; // uniquely identifying SHA-256 key for this aot |
| 99 | }; |
| 100 | |
| 101 | struct dyld_aot_shared_cache_info { |
| 102 | const uintptr_t cacheBaseAddress; |
| 103 | uuid_t cacheUUID; |
| 104 | }; |
| 105 | |
| 106 | typedef void (*dyld_image_notifier)(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]); |
| 107 | |
| 108 | /* for use in dyld_all_image_infos.errorKind field */ |
| 109 | enum {	dyld_error_kind_none=0, |
| 110 | 		dyld_error_kind_dylib_missing=1, |
| 111 | 		dyld_error_kind_dylib_wrong_arch=2, |
| 112 | 		dyld_error_kind_dylib_version=3, |
| 113 | 		dyld_error_kind_symbol_missing=4 |
| 114 | 	}; |
| 115 | |
| 116 | /* internal limit */ |
| 117 | #define DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT 8 |
| 118 | |
| 119 | // Must be aligned to support atomic updates |
| 120 | // Note sim cannot assume alignment until all host dylds are new enough |
| 121 | #if TARGET_OS_SIMULATOR |
| 122 | struct dyld_all_image_infos |
| 123 | #else |
| 124 | struct __attribute__((aligned(16))) dyld_all_image_infos |
| 125 | #endif |
| 126 | { |
| 127 | 	uint32_t						version;		/* 1 in Mac OS X 10.4 and 10.5 */ |
| 128 | 	uint32_t						infoArrayCount; |
| 129 | #if defined(__cplusplus) && (BUILDING_LIBDYLD || BUILDING_DYLD) |
| 130 | std::atomic<const struct dyld_image_info*>	infoArray; |
| 131 | #else |
| 132 | const struct dyld_image_info* infoArray; |
| 133 | #endif |
| 134 | 	dyld_image_notifier				notification;		 |
| 135 | 	bool							processDetachedFromSharedRegion; |
| 136 | 	/* the following fields are only in version 2 (Mac OS X 10.6, iPhoneOS 2.0) and later */ |
| 137 | 	bool							libSystemInitialized; |
| 138 | 	const struct mach_header*		dyldImageLoadAddress; |
| 139 | 	/* the following field is only in version 3 (Mac OS X 10.6, iPhoneOS 3.0) and later */ |
| 140 | 	void*							jitInfo; |
| 141 | 	/* the following fields are only in version 5 (Mac OS X 10.6, iPhoneOS 3.0) and later */ |
| 142 | 	const char*						dyldVersion; |
| 143 | 	const char*						errorMessage; |
| 144 | 	uintptr_t						terminationFlags; |
| 145 | 	/* the following field is only in version 6 (Mac OS X 10.6, iPhoneOS 3.1) and later */ |
| 146 | 	void*							coreSymbolicationShmPage; |
| 147 | 	/* the following field is only in version 7 (Mac OS X 10.6, iPhoneOS 3.1) and later */ |
| 148 | 	uintptr_t						systemOrderFlag; |
| 149 | 	/* the following field is only in version 8 (Mac OS X 10.7, iPhoneOS 3.1) and later */ |
| 150 | 	uintptr_t						uuidArrayCount; |
| 151 | 	const struct dyld_uuid_info*	uuidArray;		/* only images not in dyld shared cache */ |
| 152 | 	/* the following field is only in version 9 (Mac OS X 10.7, iOS 4.0) and later */ |
| 153 | 	struct dyld_all_image_infos*	dyldAllImageInfosAddress; |
| 154 | 	/* the following field is only in version 10 (Mac OS X 10.7, iOS 4.2) and later */ |
| 155 | 	uintptr_t						initialImageCount; |
| 156 | 	/* the following field is only in version 11 (Mac OS X 10.7, iOS 4.2) and later */ |
| 157 | 	uintptr_t						errorKind; |
| 158 | 	const char*						errorClientOfDylibPath; |
| 159 | 	const char*						errorTargetDylibPath; |
| 160 | 	const char*						errorSymbol; |
| 161 | 	/* the following field is only in version 12 (Mac OS X 10.7, iOS 4.3) and later */ |
| 162 | 	uintptr_t						sharedCacheSlide; |
| 163 | 	/* the following field is only in version 13 (Mac OS X 10.9, iOS 7.0) and later */ |
| 164 | 	uint8_t							sharedCacheUUID[16]; |
| 165 | 	/* the following field is only in version 15 (macOS 10.12, iOS 10.0) and later */ |
| 166 | 	uintptr_t						sharedCacheBaseAddress; |
| 167 | #if defined(__cplusplus) && (BUILDING_LIBDYLD || BUILDING_DYLD) |
| 168 | // We want this to be atomic in libdyld so that we can see updates when we map it shared |
| 169 | std::atomic<uint64_t> infoArrayChangeTimestamp; |
| 170 | #else |
| 171 | 	uint64_t						infoArrayChangeTimestamp; |
| 172 | #endif |
| 173 | 	const char*						dyldPath; |
| 174 | |
| 175 | mach_port_t notifyPorts[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT]; |
| 176 | |
| 177 | #if __LP64__ |
| 178 | 	uintptr_t						reserved[11-(DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT/2)]; |
| 179 | #else |
| 180 | 	uintptr_t						reserved[9-DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT]; |
| 181 | #endif |
| 182 | // The following fields were added in version 18 (previously they were reserved padding fields) |
| 183 | uint64_t sharedCacheFSID; |
| 184 | uint64_t sharedCacheFSObjID; |
| 185 | 	/* the following field is only in version 16 (macOS 10.13, iOS 11.0) and later */ |
| 186 | uintptr_t compact_dyld_image_info_addr; |
| 187 | size_t compact_dyld_image_info_size; |
| 188 | uint32_t platform; // FIXME: really a dyld_platform_t, but those aren't exposed here. |
| 189 | |
| 190 | /* the following field is only in version 17 (macOS 10.16) and later */ |
| 191 | uint32_t aotInfoCount; |
| 192 | const struct dyld_aot_image_info* aotInfoArray; |
| 193 | uint64_t aotInfoArrayChangeTimestamp; |
| 194 | uintptr_t aotSharedCacheBaseAddress; |
| 195 | uint8_t aotSharedCacheUUID[16]; |
| 196 | }; |
| 197 | |
| 198 | /* |
| 199 | * Beginning in Mac OS X 10.5, this is how gdb discovers where the shared cache is in a process. |
| 200 | * Images that are in the shared cache have their segments rearranged, so when using imageFilePath |
| 201 | * to load the file from disk, you have to know to adjust addresses based on how their segment |
| 202 | * was rearranged. |
| 203 | * |
| 204 | * gdb looks for the symbol "_dyld_shared_region_ranges" in dyld. |
| 205 | * |
| 206 | * It contains information the count of shared regions used by the process. The count is |
| 207 | * the number of start/length pairs. |
| 208 | */ |
| 209 | struct dyld_shared_cache_ranges { |
| 210 | 	uintptr_t					sharedRegionsCount;	/* how many ranges follow */ |
| 211 | 	struct { |
| 212 | 		uintptr_t	start; |
| 213 | 		uintptr_t	length; |
| 214 | 	}							ranges[4];			/* max regions */ |
| 215 | }; |
| 216 | extern struct dyld_shared_cache_ranges dyld_shared_cache_ranges __attribute__((visibility("hidden"))); |
| 217 | |
| 218 | |
| 219 | |
| 220 | #ifdef __cplusplus |
| 221 | } |
| 222 | #endif |
| 223 | |
| 224 | #endif /* _DYLD_IMAGES_ */ |