Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | /* * Copyright (c) 2021 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_UTILS_H_ #define _MACH_O_UTILS_H_ #include <stddef.h> #include <stdint.h> #include <stdbool.h> #include <mach-o/loader.h> #include <Availability.h> #include <TargetConditionals.h> #if __cplusplus extern "C" { #endif /*! * @function macho_cpu_type_for_arch_name * * @abstract * Converts an architecture name into a cpu type/subtype pair. * * @param archName * An architecture name (e.g "arm64e" or "x86_64"). * * @param type * A pointer to where to store the cpu type of the given name. * * @param subtype * A pointer to where to store the cpu subtype of the given name. * * @return * If the archName is known, returns true and fills in the type/subtype. * If the archName is unknown, returns false. */ extern bool macho_cpu_type_for_arch_name(const char* _Nonnull archName, cpu_type_t* _Nonnull type, cpu_subtype_t* _Nonnull subtype) __API_AVAILABLE(macos(13.0), ios(16.0), tvos(16.0), watchos(8.0)); /*! * @function macho_arch_name_for_cpu_type * * @abstract * Converts a cpu type/subtype pair into the architecture name. * * @param type * The cpu type from <machine/machine.h> (e.g CPU_TYPE_ARM64) * * @param subtype * The cpu subtype from <machine/machine.h> (e.g CPU_SUBTYPE_ARM64E) * * @return * Returns a static c-string which is the name for the cpu type/subtype (e.g. "arm64e"). * If the cpu type/subtype is unknown, NULL will be returned. * The string returned is static and does not need to be deallocated. */ extern const char* _Nullable macho_arch_name_for_cpu_type(cpu_type_t type, cpu_subtype_t subtype) __API_AVAILABLE(macos(13.0), ios(16.0), tvos(16.0), watchos(8.0)); /*! * @function macho_arch_name_for_mach_header * * @abstract * Returns the architecture name from the cpu type/subtype in a mach_header. * This is a convenience wrapper around macho_arch_name_for_cpu_type(). * * @param mh * A pointer to the header of a mach-o file. * If NULL is passed, the architecture name of the main executable will be returned. * * @return * Returns a static c-string which is the name for architecture of the mach-o file (e.g. "arm64e"). * If the architecture is unknown, NULL will be returned. * The string returned is static and does not need to be deallocated. */ extern const char* _Nullable macho_arch_name_for_mach_header(const struct mach_header* _Nullable mh) __API_AVAILABLE(macos(13.0), ios(16.0), tvos(16.0), watchos(8.0)); #ifdef __BLOCKS__ #if __has_attribute(noescape) #define __MACHO_NOESCAPE __attribute__((__noescape__)) #else #define __MACHO_NOESCAPE #endif /*! * @function macho_for_each_slice * * @abstract * Temporarily maps a mach-o or universal file and iterates the slices. * If the file is mach-o, the block is called once with the mach-o file mapped. * If the file is universal (aka fat), the block is called once per slice in the order in the header. * If the path does not exist or does, but is not a mach-o file, the block is never called. * * @param path * The path to the file to inspect. * * @param callback * A block to call once per slice. * Can be NULL. In which case the return value tells you if the file is mach-o or fat. * The slice pointer is only valid during the block invocation. * To stop iterating the slices, set *stop to true. * * @return * Returns zero on success, otherwise it returns an errno value. * Common returned errors: * ENOENT - path does not exist * EACCES - path exists put caller does not have permission to access it * EFTYPE - path exists but it is not a mach-o or fat file * EBADMACHO - path is a mach-o file, but it is malformed */ extern int macho_for_each_slice(const char* _Nonnull path, void (^ _Nullable callback)(const struct mach_header* _Nonnull slice, uint64_t sliceFileOffset, size_t size, bool* _Nonnull stop) __MACHO_NOESCAPE) __API_AVAILABLE(macos(13.0), ios(16.0), tvos(16.0), watchos(8.0)); /*! * @function macho_for_each_slice_in_fd * * @abstract * Temporarily maps a mach-o or universal file and iterates the slices. * If the fd is to a mach-o, the block is called once with the mach-o file mapped. * If the fd is to a universal (aka fat), the block is called once per slice in the order in the header. * If the fd is closed or not mmap()able, the block is never called. * * @param fd * An open file descriptor to a mmap()able file. * * @param callback * A block to call once per slice. * Can be NULL. In which case the return value tells you if the file is mach-o or fat. * The slice pointer is only valid during the block invocation. * To stop iterating the slices, set *stop to true. * * @return * Returns zero on success, otherwise it returns an errno value. * Common returned errors: * EFTYPE - fd content is not a mach-o or fat file * EBADMACHO - fd content is a mach-o file, but it is malformed */ extern int macho_for_each_slice_in_fd(int fd, void (^ _Nullable callback)(const struct mach_header* _Nonnull slice, uint64_t sliceFileOffset, size_t size, bool* _Nonnull stop)__MACHO_NOESCAPE) __API_AVAILABLE(macos(13.0), ios(16.0), tvos(16.0), watchos(8.0)); /*! * @function macho_best_slice * * @abstract * Examines a mach-o or universal file to find the slice that would be loaded. That is, for dylib/bundles, which * slice dyld would load. For main executables, which slice the kernel would use. * In simulator processes, only other simulator main executables will be considered loadable. * If the file is mach-o and is the right arch and platform to load, the block is called once with the mach-o file mapped. * If the file is universal (aka fat) file, the best slice is found and the block is called once with the mapped slice. * If the file is universal (aka fat) file, but none of the slices are loadable, the callback is not called, and EBADARCH is returned. * If the path does not exist or does but is not a mach-o or universal file, the block is never called, and an error is returned. * * @param path * The path to the file to inspect. * * @param callback * A block to call once with the best slice. * Can be NULL. In which case the return value tells you if there was a loadable slice * The slice pointer is only valid during the block invocation. * * @return * Returns zero on success (meaning there is a best slice), otherwise it returns an errno value. * Common returned errors: * ENOENT - path does not exist * EACCES - path exists put caller does not have permission to access it * EFTYPE - path exists but it is not a mach-o or fat file * EBADARCH - path exists and is mach-o or fat, but none of the slices are loadable * EBADMACHO - path is a mach-o file, but it is malformed */ extern int macho_best_slice(const char* _Nonnull path, void (^ _Nullable bestSlice)(const struct mach_header* _Nonnull slice, uint64_t sliceFileOffset, size_t sliceSize)__MACHO_NOESCAPE) __API_AVAILABLE(macos(13.0), ios(16.0), tvos(16.0), watchos(8.0)); /*! * @function macho_best_slice_in_fd * * @abstract * Examines a mach-o or universal file to find the slice that would be loaded. That is, for dylib/bundles, which * slice dyld would load. For main executables, which slice the kernel would use. * In simulator processes, only other simulator main executables will be considered loadable. * If the fd is to a mach-o and is the right arch and platform to load, the block is call once with the mach-o file mapped. * If the fd is to a universal (aka fat) file, the best slice is found and the block is called once with the mapped slice. * If the fd is closed or not mmap()able, the block is never called. * * @param fd * An open file descriptor to a mmap()able file. * * @param callback * A block to call once with the best slice. * Can be NULL. In which case the return value tells you if there was a loadable slice * The slice pointer is only valid during the block invocation. * * @return * Returns zero on success (meaning there is a best slice), otherwise it returns an errno value. * Common returned errors: * EFTYPE - fd content is not a mach-o or fat file * EBADMACHO - fd content is a mach-o file, but it is malformed * EBADARCH - fd content is a mach-o or fat, but none of the slices are loadable */ extern int macho_best_slice_in_fd(int fd, void (^ _Nullable bestSlice)(const struct mach_header* _Nonnull slice, uint64_t sliceFileOffset, size_t sliceSize)__MACHO_NOESCAPE) __API_AVAILABLE(macos(13.0), ios(16.0), tvos(16.0), watchos(8.0)); #endif // __BLOCKS__ #if __cplusplus } #endif #endif // _MACH_O_UTILS_H_ |