diff --git a/.github/workflows/create.yml b/.github/workflows/create.yml new file mode 100644 index 0000000000..310df07d58 --- /dev/null +++ b/.github/workflows/create.yml @@ -0,0 +1,133 @@ +name: Create SDK + +on: + workflow_dispatch: + inputs: + ipsw_device: + description: 'The device ID to download the IPSW for, e.g. "iPhone11,2"' + required: true + type: string + ipsw_version: + description: 'The version to download the IPSW for, e.g. "16.5"' + required: true + type: string + dsc_basename: + description: 'The basename for the dyld_shared_cache in the IPSW' + required: true + type: string + default: 'dyld_shared_cache_arm64e' + xcode_version: + description: 'Xcode version, e.g. "14.4". Primarily used for the base SDK' + required: true + type: string + xcrun_sdk_name: + description: 'The value to pass to "xcrun --sdk", e.g. "iphoneos"' + required: true + type: string + default: 'iphoneos' + full_sdk_name: + description: 'The full name of the output SDK, e.g. "iPhoneOS16.5"' + required: true + type: string + +jobs: + create: + # https://github.com/actions/runner-images/blob/main/images/macos + runs-on: macos-14 + # needed to be able to push to the repo + permissions: + contents: write + + steps: + - name: Clone repo + uses: actions/checkout@v4 + + - name: Clone tbd + uses: actions/checkout@v4 + with: + repository: leptos-null/tbd + ref: f0ae164d76b7bb802bbdf8ef758cc5637fac0fa1 # pinned, leptos/source-platform + path: tbd + + - name: Build tbd + run: | + cd tbd + make bin/tbd + + - name: Install blacktop/ipsw + run: brew install blacktop/tap/ipsw + + - name: Install aria2 + run: brew install aria2 + + - name: Patch SDK + id: patch-sdk + env: + DEVELOPER_DIR: /Applications/Xcode_${{ inputs.xcode_version }}.app + run: | + # use absolute path since we `cd` later + TBD_TOOL_PATH="$(pwd)/tbd/bin/tbd" + SDK_OUTPUT_PATH="$(pwd)/${{ inputs.full_sdk_name }}.sdk" + + DSC_BASENAME="${{ inputs.dsc_basename }}" + XC_SDK_NAME="${{ inputs.xcrun_sdk_name }}" + + cd tools/ + PLATFORM_PATH="$(xcrun --sdk "${XC_SDK_NAME}" --show-sdk-platform-path)" + BASE_SDK_PATH="$(xcrun --sdk "${XC_SDK_NAME}" --show-sdk-path)" + + SYMBOLS_DIR="$(mktemp -d -t symbols)" + IPSW_DOWNLOAD_DIR="$(mktemp -d -t ipsw)" + IPSW_EXTRACTION_DIR="$(mktemp -d -t ipsw)" + + # `--dyld` is a convenient parameter for us, however it only supports iOS 16+ + IPSW_DOWNLOAD_URL="$(ipsw download ipsw --urls --version "${{ inputs.ipsw_version }}" --device "${{ inputs.ipsw_device }}")" + echo "Downloading ${IPSW_DOWNLOAD_URL}" + aria2c --dir "${IPSW_DOWNLOAD_DIR}" "${IPSW_DOWNLOAD_URL}" + + unzip -d "${IPSW_EXTRACTION_DIR}" "${IPSW_DOWNLOAD_DIR}"/*.ipsw "*.dmg" + # remove to save space + rm "${IPSW_DOWNLOAD_DIR}"/*.ipsw + + for DMG_FILE in "${IPSW_EXTRACTION_DIR}"/*.dmg; do + # new mount root for each dmg so we don't have to + # worry about how we iterate over the mount root + DMG_MOUNT_ROOT="$(mktemp -d -t dmg)" + # some of the dmgs can't be mounted - not sure why + hdiutil attach "${DMG_FILE}" -mountroot "${DMG_MOUNT_ROOT}" || true + for MOUNT_VOL in "${DMG_MOUNT_ROOT}"/*; do + DYLD_CACHE_PATH="${MOUNT_VOL}/System/Library/Caches/com.apple.dyld/${DSC_BASENAME}" + if [ -e "${DYLD_CACHE_PATH}" ]; then + break 2 # break out of DMG_FILE loop + fi + # here becuase we didn't find the dyld shared cache (didn't break) + unset DYLD_CACHE_PATH + hdiutil detach "${MOUNT_VOL}" || true # this fails occasionally - just ignore + done + done + + echo "Found dyld_shared_cache: ${DYLD_CACHE_PATH}" + + if [ -z "${DYLD_CACHE_PATH}" ]; then + echo "Failed to find ${DSC_BASENAME} in IPSW" + exit 1 + fi + + ./create_patched_sdk_image.sh "${DYLD_CACHE_PATH}" "${SDK_OUTPUT_PATH}" "${BASE_SDK_PATH}" "${PLATFORM_PATH}" "${TBD_TOOL_PATH}" + + echo "sdk-path=${SDK_OUTPUT_PATH}" >> "${GITHUB_OUTPUT}" + + - name: Create branch + run: | + # thanks to https://github.com/actions/checkout/discussions/479 + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + + SDK_NAME="${{ inputs.full_sdk_name }}" + BRANCH_NAME="bot/${SDK_NAME}" + + git switch -c "${BRANCH_NAME}" + git add "${{ steps.patch-sdk.outputs.sdk-path }}" + + git commit -m "Add ${SDK_NAME} SDK" + git push --set-upstream origin "${BRANCH_NAME}" diff --git a/README.md b/README.md index 085b978842..00cee62129 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,4 @@ This repository contains patched iOS SDKs containing private symbols. These were To use with Theos, [download this repo](https://github.com/theos/sdks/archive/master.zip), extract, and copy whichever SDKs you desire into `$THEOS/sdks/`. -Generated using [create_patched_sdk.sh](create_patched_sdk.sh) and inoahdev’s [tbd v2.2](https://github.com/inoahdev/tbd/releases/tag/2.2) using binaries retrieved from iOS Device Support directory. +Generated using [create_patched_sdk.sh](tools/create_patched_sdk.sh) and inoahdev’s [tbd v2.2](https://github.com/inoahdev/tbd/releases/tag/2.2) using binaries retrieved from iOS Device Support directory or extracted from an IPSW. diff --git a/create_generic_symlinks.sh b/create_generic_symlinks.sh deleted file mode 100755 index 936ec76ede..0000000000 --- a/create_generic_symlinks.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash - -usage() { - echo "Usage: $0 -D " -} - -info() { - echo "$0: $1" -} - -# Accept 'D' flag -while getopts ":D:" flag; do - case "$flag" in - # Assign the arg associated with -D to $sdk_dir - D) sdk_dir="$OPTARG" ;; - *) usage - exit 1 - ;; - esac -done - -# No args passed -if [[ $OPTIND -eq 1 ]]; then - usage - exit 1 -fi - -# Get sdks in provided dir -IFS=$'\n' -sdks=($(find "$sdk_dir" -type d -name \*.sdk | sort -uV)) -unset IFS - -# Get unique prefixes -prefixes=() -for i in "${sdks[@]}"; do - name="$(basename "$i")" - prefix="${name%%[0-9]*}" - - # Check if prefixes array contains the prefix or not - if ! [[ ${prefixes[*]} =~ $prefix ]]; then - prefixes+=("$prefix") - fi -done - -# Get sdks for each prefix -for prefix in "${prefixes[@]}"; do - relevant_sdks=() - for sdk in "${sdks[@]}"; do - if [[ $sdk =~ $prefix ]]; then - relevant_sdks+=("$sdk") - fi - done - - # Latest sdk (e.g., iPhoneOS14.5.sdk) - latest=${relevant_sdks[${#relevant_sdks[@]}-1]} - - # Generic platform sdk (e.g., iPhoneOS.sdk) - platform="$sdk_dir/$prefix.sdk" - ln -sfn "$latest" "$platform" - - info "The '$platform' symlink has been created and it points to '$latest'." -done diff --git a/create_patched_sdk.py b/create_patched_sdk.py deleted file mode 100755 index 922b3bbcb4..0000000000 --- a/create_patched_sdk.py +++ /dev/null @@ -1,517 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import os -from pathlib import Path -import shutil -import subprocess -import sys - -ARCHS = [ "armv7", "armv7s", "arm64", "arm64e" ] -DIRS = [ "System/Library/Frameworks", "System/Library/PrivateFrameworks" ] -TARGETS = [ "armv7-ios", "armv7s-ios", "arm64-ios", "arm64e-ios" ] -VERSION = "v3" - -PATH_OPTIONS = [ "-p", "--macho", "-r", "all", "--ignore-clients", "--ignore-undefineds", "--allow-private-objc-symbols", "--ignore-missing-exports" ] -WRITE_OPTIONS = [ "-o", "--preserve-subdirs", "--replace-path-extension" ] - -TBD_PATH = Path("/usr/local/bin/tbd") -TBD_DOWNLOAD_URL = "https://github.com/inoahdev/tbd/releases" -XCODE_PATH = Path("/Applications/Xcode.app") - -def should_use_archs(version): - return version != "v4" - -def convert_binary_to_string(binary): - bstring = str(binary) - - # We remove the first 2 characters as they're used to - # indicate the old binary format of the data. - # - # We also remove the newline character at the end of - # the string. - - string = bstring[2:len(bstring) - 3] - return string - -def get_list_from_option(tbd_path, option): - output = subprocess.check_output([tbd_path, option]) - return convert_binary_to_string(output).split('\\n') - -def copyDirectory(dest, src): - try: - shutil.copytree(src, dest) - # Directories are the same - except shutil.Error as e: - print('Directory not copied. Error: %s' % e) - return False - - # Any error saying that the directory doesn't exist - except OSError as e: - print('Directory not copied. Error: %s' % e) - return False - - return True - -def removeDirectory(dir): - try: - shutil.rmtree(dir) - # Directories are the same - except shutil.Error as e: - print('Directory not removed. Error: %s' % e) - return False - - # Any error saying that the directory doesn't exist - except OSError as e: - print('Directory not removed. Error: %s' % e) - return False - - return True - -def main(argv): - theos_path_env = os.environ.get("THEOS") - if theos_path_env is None: - print("The path of environment-variable $THEOS doesn't exist.") - print("Please run 'export THEOS=' before running this program") - - exit(1) - - theos_path = Path(theos_path_env) - if not theos_path.exists() or not theos_path.is_dir(): - print("No directory exists at path of environment-variable $THEOS") - exit(1) - - output_path = theos_path / "sdks" - parser = argparse.ArgumentParser(description="Apple Platform SDK Generator Python Script", add_help=True) - - parser.add_argument("-a", "--archs", nargs='+', help="A list of archs to replace ones in SDK", required=False) - parser.add_argument("--dirs", help='A list of dirs to recurse while parsing inside SDK', default=DIRS, nargs='+', required=False) - parser.add_argument("--ignore-warnings", help="Ignore any warnings from tbd", action='store_true', default=False, required=False) - parser.add_argument("--ignore-requests", help="Ignore any requests from tbd", action='store_true', default=False, required=False) - parser.add_argument("--keep-archs", help="Don't replace archs in SDK with either internal or provided archs", action='store_true', default=False, required=False) - parser.add_argument("--keep-targets", help="Don't replace targets in SDK with either internal or provided targets", action='store_true', default=False, required=False) - parser.add_argument("-o", "--output-path", help='Path to write SDK', required=False) - parser.add_argument("--no-overwrite", help="Don't overwrite any existing SDKs", action='store_true', default=False, required=False) - parser.add_argument("-t", "--targets", help='A list of targets to replace ones in SDK', nargs='+', required=False) - parser.add_argument("--tbd-path", help=f'Path to local tbd-installation. tbd can be downloaded at {TBD_DOWNLOAD_URL}', required=False) - parser.add_argument("--use-simulator", help='Use iOS Simulator binaries instead of the default DeviceSupport binaries', action='store_true', default=False, required=False) - parser.add_argument('-v', "--version", help=f'Set version of the .tbd format. Default version is {VERSION}', required=False) - parser.add_argument('-x', "--xcode-path", help=f'Path to Xcode-Installation. Default location is {XCODE_PATH}', required=False) - - args = parser.parse_args() - tbd_path_string = TBD_PATH - - if args.tbd_path is not None: - tbd_path_string = args.tbd_path - - tbd_path = Path(tbd_path_string) - if not tbd_path.exists(): - print(f"tbd was not found at location {tbd_path}") - print("Please provide a path to your local tbd install with option --tbd-path") - print(f"tbd can be downloaded at {TBD_DOWNLOAD_URL}") - - exit(1) - - if not tbd_path.is_file(): - print("Your tbd path is not a path to a file") - print(f"A tbd executable file was expected at {tbd_path}") - - exit(1) - - if not os.access(tbd_path.as_posix(), os.X_OK): - print("Your tbd file is not executable") - print(f"Please run 'chmod +x {tbd_path}'") - - exit(1) - - did_provide_output_path = args.output_path is not None - if did_provide_output_path: - output_path = Path(args.output_path) - - output_path.mkdir(mode=0o666, parents=False, exist_ok=True) - - did_provide_archs = args.archs is not None - did_provide_targets = args.targets is not None - - if args.keep_archs and did_provide_archs: - print("Error: Both --keep-archs and --replace-archs were provided") - exit(1) - - if args.keep_targets and did_provide_targets: - print("Error: Both --keep-targets and --replace-targets were provided") - exit(1) - - if did_provide_archs and did_provide_targets: - print("Error: Both --replace-archs and --replace-targets were provided") - exit(1) - - did_provide_version = args.version is not None - version = VERSION - - if did_provide_version: - version = args.version - valid_versions = get_list_from_option(tbd_path.as_posix(), "--list-tbd-versions") - - if version not in valid_versions: - valid_versions_print_list = ', '.join(valid_versions) - - print(f"tbd-version {version} doesn't exist") - print(f"Valid Versions: {valid_versions_print_list}") - - exit(1) - - if did_provide_targets and should_use_archs(version): - print("Error: --replace-targets has been provided while tbd-version is not tbd-version v4.") - print(" Please provide version tbd-version v4 (with options: -v v4)") - - exit(1) - - archs = ARCHS - targets = TARGETS - - if did_provide_archs or did_provide_targets: - valid_archs = get_list_from_option(tbd_path.as_posix(), "--list-architectures") - - if did_provide_archs: - archs = args.archs - should_exit = False - should_print_arch_list = False - - for arch in archs: - if arch in valid_archs: - continue - - print(f"Architecture '{arch}' doesn't exist") - - should_exit = True - should_print_arch_list = True - - if should_exit: - if should_print_arch_list: - print(f"\nValid Archs:") - print(', '.join(valid_archs)) - - exit(1) - - if did_provide_targets: - valid_platforms = get_list_from_option(tbd_path.as_posix(), "--list-platforms") - - should_exit = False - should_print_arch_list = False - should_print_platform_list = False - targets = args.targets - - for target in targets: - components = target.split('-') - if len(components) != 2: - print(f"Target '{target}' is invalid") - should_exit = True - - arch, platform = components - if not arch and not platform: - print(f"Target '{target}' is missing an arch and a platform") - - should_print_arch_list = True - should_print_platform_list = True - - should_exit = True - continue - - if not arch: - print(f"Target '{target}' is missing an arch") - - should_print_arch_list = True - should_exit = True - elif arch not in valid_archs: - print(f"Architecture '{arch}' doesn't exist") - - should_print_arch_list = True - should_exit = True - - if not platform: - print(f"Target '{target}' is missing a platform") - - should_print_platform_list = True - should_exit = True - elif platform not in valid_platforms: - print(f"Platform '{platform}' doesn't exist") - - should_print_platform_list = True - should_exit = True - - if should_exit: - if should_print_arch_list: - print("\nValid Archs:") - print(', '.join(valid_archs)) - - if should_print_platform_list: - print("\nValid Platforms:") - print(', '.join(valid_platforms)) - - exit(1) - - xcode_path = XCODE_PATH - did_provide_xcode_path = args.xcode_path is not None - - if did_provide_xcode_path: - xcode_path = Path(args.xcode_path) - - if not xcode_path.exists(): - print(f"No Xcode installation was found at {xcode_path}") - print("Please provide a path to your local Xcode installation") - - exit(1) - - if not xcode_path.is_dir(): - print("Your Xcode Application Path does not point to a directory") - print(f"The Xcode Application Path Directory was expected at {xcode_path}") - - exit(1) - - xcode_developer_path = xcode_path / "Contents" / "Developer" - if not xcode_developer_path.exists(): - print("Your Xcode installation is missing its developer directory") - print(f"The developer directory is supposed to exist at {xcode_developer_path}") - - exit(1) - - xcode_sdk_dir_path = xcode_developer_path / "Platforms" / "iPhoneOS.platform" / "Developer" / "SDKs" - if not xcode_sdk_dir_path.exists(): - print("Your Xcode installation is missing its iOS SDKs directory") - print(f"The sdks directory should be at {xcode_sdk_dir_path}") - print("The iOS SDK from Xcode is needed as a baseline which we add onto") - - exit(1) - - xcode_default_sdk_path = xcode_sdk_dir_path / "iPhoneOS.sdk" - if not xcode_sdk_dir_path.exists(): - print("Your Xcode installation is missing its default iOS SDK.") - print(f"The default SDK should be at {xcode_default_sdk_path}") - print("The iOS SDK from Xcode is needed as a baseline which we add onto") - - exit(1) - - # Recurse to find the SDK that points to xcode_default_sdk_path - - xcode_sdk_version = '' - for dir in xcode_sdk_dir_path.glob("iPhoneOS*.sdk/"): - if dir.name == "iPhoneOS.sdk": - continue - - resolved_dir = dir.resolve() - if resolved_dir != xcode_default_sdk_path: - continue - - xcode_sdk_real_name = dir.stem # Use .stem instead of .name to remove the ".sdk" - xcode_sdk_version = xcode_sdk_real_name[8:] # We remove the 'iPhoneOS' prefix from the sdk name - - break - - if not xcode_sdk_version: - print("No SDK pointing to the default SDK was found") - print("The default sdk exists at path {xcode_default_sdk_path}") - - exit(1) - - parsed_atleast_one = False - xcode_device_support_path = Path.home() / "Library" / "Developer" / "Xcode" / "iOS DeviceSupport" - tbd_argv = [ tbd_path.as_posix() ] - - if xcode_device_support_path.exists() and xcode_device_support_path.is_dir() and not args.use_simulator: - for symbols_path in xcode_device_support_path.iterdir(): - if not symbols_path.is_dir(): - continue - - # symbols_filename should be the same as the iOS Version, and a build - # in the format of "12.4 (16G77)" - # - # Because iOS Versions use '.', we can't use `symbols_path.stem`, which - # takes out the path-extension, by finding a dot. - - symbols_filename = symbols_path.name - symbols_filename_split = symbols_filename.split() - - if len(symbols_filename_split) != 2: - continue - - symbols_ios_version = symbols_filename_split[0] - symbols_ios_build = symbols_filename_split[1] - symbols_dir_path = xcode_device_support_path / symbols_filename - - if not symbols_dir_path.exists(): - print("Warning: Symbols directory does not exist. Skipping") - print(f"iOS Version {symbols_ios_version}, Build: {symbols_ios_build}") - - continue - - symbols_path = symbols_dir_path / "Symbols" / "System" - if not symbols_path.exists(): - print("Warning: The Symbols directory does not contain a System directory. Skipping") - print(f"iOS Version {symbols_ios_version}, Build: {symbols_ios_build}") - - continue - - sdk_write_path = output_path / f"iPhoneOS{symbols_ios_version}.sdk" - if sdk_write_path.exists(): - if args.no_overwrite: - print(f"Warning: SDK for iOS {symbols_ios_version} already exists. Skipping") - print(f"SDK for iOS {symbols_ios_version} is at {sdk_write_path}") - - continue - - if not sdk_write_path.is_dir(): - print(f"Warning: A non-directory exists at write-path for SDK for iOS {symbols_ios_version}. Skipping") - print(f"SDK for iOS {symbols_ios_version} is at {sdk_write_path}") - - continue - - if not removeDirectory(sdk_write_path): - continue - - if xcode_sdk_version != symbols_ios_version: - print(f"Warning: The official iOS SDK for iOS Version {xcode_sdk_version} will be used as the base for the newly-created SDK for iOS Version {symbols_ios_version}") - - if not copyDirectory(sdk_write_path, xcode_default_sdk_path): - removeDirectory(sdk_write_path) - continue - - dirs_that_exist = [] - use_archs = should_use_archs(version) - - for dir in args.dirs: - path_from_components = Path(*Path(dir).parts[1:]) # "[1:]" Removes the "System" path-component - dir_path = symbols_path / path_from_components.as_posix() - - if not dir_path.exists(): - continue - - tbd_argv += PATH_OPTIONS - if args.ignore_requests: - tbd_argv.append("--ignore-requests") - - if args.ignore_warnings: - tbd_argv.append("--ignore-warnings") - - tbd_argv.append("-v") - tbd_argv.append(version) - - if not args.keep_targets and not use_archs: - tbd_argv.append("--replace-targets") - tbd_argv += targets - elif not args.keep_archs and use_archs: - tbd_argv.append("--replace-archs") - tbd_argv += archs - - dirs_that_exist.append(dir) - tbd_argv.append(dir_path.as_posix()) - - if not dirs_that_exist: - continue - - for dir in args.dirs: - if not dir in dirs_that_exist: - continue - - tbd_argv += WRITE_OPTIONS - if args.no_overwrite: - tbd_argv.append("--no-overwrite") - - dir_write_path = sdk_write_path / dir - tbd_argv.append(dir_write_path.as_posix()) - - ret = subprocess.call(tbd_argv, stdout=None, stderr=subprocess.DEVNULL) - if ret == 0: - parsed_atleast_one = True - - if args.use_simulator or parsed_atleast_one == False: - if not args.use_simulator: - print("No SDKs were successfully created from DeviceSupport binaries. Falling back to Simulator Binaries") - - simulator_path = xcode_developer_path / "Platforms" / "iPhoneOS.platform" / "Library" / "Developer" / "CoreSimulator" / "Profiles" / "Runtimes" / "iOS.simruntime" / "Contents" / "Resources" / "RuntimeRoot" - if not simulator_path.exists(): - simulator_path = xcode_developer_path / "Platforms" / "iPhoneOS.platform" / "Developer" / "Library" / "CoreSimulator" / "Profiles" / "Runtimes" / "iOS.simruntime" / "Contents" / "Resources" / "RuntimeRoot" - if not simulator_path.exists(): - print("The iOS Simulator RuntimeRoot directory does not exist. Please install a simulator.") - exit(1) - - simulator_version_path = simulator_path / "System" / "Library" / "CoreServices" / "SystemVersion.plist" - if not simulator_path.exists(): - print("The iOS Simulator RuntimeRoot directory does not have a SystemVersion.plist file. Please re-install the simulator") - print(f"The iOS Simulator RuntimeRoot directory's SystemVersion.plist file should be at {simulator_version_path}") - - exit(1) - - if not simulator_version_path.is_file(): - print("The iOS Simulator RuntimeRoot directory's SystemVersion.plist is not a file. Please re-install the simulator") - print(f"The iOS Simulator RuntimeRoot directory's SystemVersion.plist is at {simulator_version_path}") - - exit(1) - - simulator_version = convert_binary_to_string(subprocess.check_output([ "/usr/bin/defaults", "read", simulator_version_path, "ProductVersion" ])) - if xcode_sdk_version != simulator_version: - print(f"Warning: The official iOS SDK for iOS Version {xcode_sdk_version} will be used as the base for the newly-created SDK for iOS Version {simulator_version}") - - sdk_write_path = output_path / f"iPhoneOS{simulator_version}.sdk" - sdk_write_path_exists = sdk_write_path.exists() - - if not sdk_write_path_exists or not args.no_overwrite: - # If sdk write-path exists, we have to remove it so copyDirectory() can work - if sdk_write_path_exists: - removeDirectory(sdk_write_path) - - if copyDirectory(sdk_write_path, xcode_default_sdk_path): - dirs_that_exist = [] - use_archs = should_use_archs(version) - - for dir in args.dirs: - dir_path = simulator_path / dir - if not dir_path.exists(): - continue - - tbd_argv += PATH_OPTIONS - if args.ignore_requests: - tbd_argv.append("--ignore-requests") - - if args.ignore_warnings: - tbd_argv.append("--ignore-warnings") - - tbd_argv.append("-v") - tbd_argv.append(version) - - if not args.keep_targets and not use_archs: - tbd_argv.append("--replace-targets") - tbd_argv += targets - elif not args.keep_archs and use_archs: - tbd_argv.append("--replace-archs") - tbd_argv += archs - - dirs_that_exist.append(dir) - tbd_argv.append(dir_path.as_posix()) - - if dirs_that_exist: - for dir in args.dirs: - if not dir in dirs_that_exist: - continue - - tbd_argv += WRITE_OPTIONS - if args.no_overwrite: - tbd_argv.append("--no-overwrite") - - dir_write_path = sdk_write_path / dir - tbd_argv.append(dir_write_path.as_posix()) - - ret = subprocess.call(tbd_argv, stdout=None, stderr=subprocess.DEVNULL) - if ret == 0: - parsed_atleast_one = True - - else: - removeDirectory(sdk_write_path) - else: - print(f"SDK for iOS {simulator_version} already exists") - - if not parsed_atleast_one: - print("No new SDKs were created from either the Device Support binaries or from the simulator runtime binaries") - exit(1) - -if __name__ == "__main__": - main(sys.argv) diff --git a/create_patched_sdk.sh b/create_patched_sdk.sh deleted file mode 100755 index 2aada11e17..0000000000 --- a/create_patched_sdk.sh +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/env bash - -print_usage() { -cat << EOF -Usage: $(basename $0) {use_simulator} {sdks_output_path} {no_overwrite} {no_warnings} {tbd_tool} {xcode_installation_path} {sdk_platform} -Options: - - use_simulator (bool) - Dump binaries from simulator runtime as opposed to DeviceSupport files - - sdks_output_path (str) - Directory to install SDK to (default: '\$THEOS/sdks') - - no_overwrite (bool) - Disable overwrite of existing dumped binaries (default: 0) - - no_warnings (bool) - Disable 'tbd' warnings (default: 0) - - tbd_tool (str) - Path to 'tbd' tool from inoahdev (default: 'tbd') - - xcode_installation_path (str) - Path to target Xcode version (default: currently selected Xcode.app) - - sdk_platform (str) - Target platform for patched SDK (default: 'iOS'; alternatively 'tvOS') -Note: {} options are optional to provide, and can be ignored with a '-' -EOF -} - -ignored() { - if [[ $1 == "-" ]]; then - return 0 - else - return 1 - fi -} - -if [[ $# -lt 1 ]] || [[ $1 == "-h" ]] || [[ $1 == "--help" ]]; then - print_usage - exit 0 -fi - -sdk_platform="$7" -if [[ $# -lt 7 ]] || ignored $sdk_platform; then - echo "No sdk_platform provided. Defaulting to iOS." - sdk_platform="iOS" -elif [[ $(echo $sdk_platform | tr '[A-Z]' '[a-z]') == ios ]]; then - sdk_platform="iOS" -elif [[ $(echo $sdk_platform | tr '[A-Z]' '[a-z]') == tvos ]]; then - sdk_platform="tvOS" -else - echo "Unsupported sdk_platform provided. Please choose either 'iOS' or 'tvOS'." - exit 1 -fi - -sdks_output_path="$2" -if [[ $# -lt 2 ]] || ignored $sdks_output_path; then - if [[ -z $THEOS ]]; then - printf 'No Theos installation found. Please either install Theos or provide a path to an sdks directory\n\n' - print_usage - exit 1 - fi - sdks_output_path="$THEOS/sdks" -fi - -if ! [[ -d $sdks_output_path ]]; then - mkdir -p "$sdks_output_path" -fi - -# tbd info -tbd_version="v3" -if [[ $sdk_platform == iOS ]]; then - archs_option=("--replace-archs" armv7 armv7s arm64 arm64e) -else - archs_option=("--replace-archs" arm64 arm64e) -fi - -tbd_options=("--ignore-clients" "--ignore-undefineds" "--allow-private-objc-symbols" "--ignore-missing-exports") -write_options=("--preserve-subdirs" "--replace-path-extension") - -no_overwrite="--no-overwrite" -if [[ $# -gt 2 ]] && ! ignored $3; then - no_overwrite="" -fi - -no_warnings="" -tbd_tool="$5" -if [[ $# -gt 3 ]] && ! ignored $4; then - no_warnings="--ignore-warnings" -fi - -if [[ $# -lt 5 ]] || ignored $tbd_tool; then - tbd_tool="tbd" - if ! [[ -x $(which $tbd_tool) ]]; then - printf 'No installation of tbd found. Please install the latest release of tbd from here; https://github.com/inoahdev/tbd/releases or provide a path to a tbd installation\n\n' - print_usage - exit 1 - fi -else - if ! [[ -x $(which $tbd_tool) ]]; then - echo "Provided tbd-tool ($tbd_tool) doesn't exist or isn't executable" - exit 1 - fi -fi - -use_simulator="$1" -if [[ $# -lt 1 ]]; then - use_simulator="-" -fi - -xcode_developer_path="$6/Contents/Developer" -if [[ $# -lt 6 ]] || [[ -z $6 ]] || ignored $6; then - xcode_developer_path=$(xcode-select -p) -fi - -if [[ -z $xcode_developer_path ]]; then - printf 'No Xcode installation found. Please either install Xcode or provide a path to an Xcode installation\n\n' - print_usage - exit 1 -fi - -if [[ $sdk_platform == iOS ]]; then - xcode_sim_runtime_path="$xcode_developer_path/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot" - if ! [[ -d $xcode_sim_runtime_path ]]; then - xcode_sim_runtime_path="$xcode_developer_path/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot" - fi - xcode_plat_sdks_path="$xcode_developer_path/Platforms/iPhoneOS.platform/Developer/SDKs" - xcode_default_sdk_path="$xcode_plat_sdks_path/iPhoneOS.sdk" -else - xcode_sim_runtime_path="$xcode_developer_path/Platforms/AppleTVOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/tvOS.simruntime/Contents/Resources/RuntimeRoot" - if ! [[ -d $xcode_sim_runtime_path ]]; then - xcode_sim_runtime_path="$xcode_developer_path/Platforms/AppleTVOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/tvOS.simruntime/Contents/Resources/RuntimeRoot" - fi - xcode_plat_sdks_path="$xcode_developer_path/Platforms/AppleTVOS.platform/Developer/SDKs" - xcode_default_sdk_path="$xcode_plat_sdks_path/AppleTVOS.sdk" -fi - -preferred_xcode_sdk_path="" -for xcode_sdk_path in "$xcode_plat_sdks_path/"*; do - xcode_sdk_real=$(readlink -f "$xcode_sdk_path") - - if [[ $xcode_sdk_real == $xcode_default_sdk_path ]]; then - preferred_xcode_sdk_path=$xcode_sdk_path - fi -done - -if [[ -z $preferred_xcode_sdk_path ]]; then - echo 'Failed to find sdk for simulator runtime' - exit 1 -fi - -preferred_xcode_sdk_name=$(basename $preferred_xcode_sdk_path) - -if [[ $sdk_platform == iOS ]]; then - xcode_sdk_version=${preferred_xcode_sdk_name:8} # Remove 'iPhoneOS' in front of sdk name -else - xcode_sdk_version=${preferred_xcode_sdk_name:9} # Remove 'AppleTVOS' in front of sdk name -fi -xcode_sdk_version=${xcode_sdk_version%????} # Remove '.sdk' at back of sdk name - -sdks_output_path_single_sdk_path="" - -device_support_dir="$HOME/Library/Developer/Xcode/$sdk_platform DeviceSupport/" -if [[ -d $device_support_dir ]] && ignored $use_simulator; then - for symbols_path in "$device_support_dir"*; do - if ! [[ -d $symbols_path ]]; then - continue - fi - - os_version="$(basename "$symbols_path" | grep -o "\d\+\(\.\d\+\)\{1,2\}")" - if [[ $sdk_platform == ios ]]; then - sdk_name=$(printf "iPhoneOS%s.sdk" "$os_version") - else - sdk_name=$(printf "AppleTVOS%s.sdk" "$os_version") - fi - - symbols_actual_path="$symbols_path/Symbols/System" - if ! [[ -d $symbols_actual_path ]]; then - echo "Symbols for $sdk_platform $os_version don't exist" - continue - fi - - sdks_output_path_single_sdk_path="$sdks_output_path/$sdk_name" - if [[ -d $sdks_output_path_single_sdk_path ]]; then - echo "SDK for $sdk_platform $os_version already exists" - continue - fi - - echo "Creating SDK for $sdk_platform $os_version ..." - - if [[ $xcode_sdk_version != $os_version ]]; then - echo "Warning: $sdk_platform $xcode_sdk_version Xcode SDK will be used as a base for sdk for $sdk_platform $os_version" - fi - - mkdir -p "$sdks_output_path_single_sdk_path" - cp -R "$xcode_default_sdk_path/"* "$sdks_output_path_single_sdk_path" - - "$tbd_tool" \ - -p $no_warnings "${tbd_options[@]}" "${archs_option[@]}" -v "$tbd_version" -r all "$symbols_actual_path" \ - -o "${write_options[@]}" $no_overwrite "$sdks_output_path_single_sdk_path/System" - - if [[ $? -ne 0 ]]; then - echo "Failed to create tbds from Symbols directory for $sdk_platform $os_version" - fi - done -else - if ignored $use_simulator; then - echo 'No DeviceSupport binaries found, falling back to dumping from simulator runtime binaries' - fi - - sdks_output_path_single_sdk_path="$sdks_output_path/$preferred_xcode_sdk_name" - if [[ -d $sdks_output_path_single_sdk_path ]]; then - echo "SDK for $sdk_platform $xcode_sdk_version already exists" - exit 1 - fi - - echo "Creating sdk for $sdk_platform $xcode_sdk_version ..." - - mkdir -p "$sdks_output_path_single_sdk_path" - cp -R "$xcode_default_sdk_path/"* "$sdks_output_path_single_sdk_path" - - parse_paths=("-p" $no_warnings "${tbd_options[@]}" "${archs_option[@]}" -v "$tbd_version" "-r" "all" "$xcode_sim_runtime_path/Developer" - "-p" $no_warnings "${tbd_options[@]}" "${archs_option[@]}" -v "$tbd_version" "-r" "all" "$xcode_sim_runtime_path/System" - "-p" $no_warnings "${tbd_options[@]}" "${archs_option[@]}" -v "$tbd_version" "-r" "all" "$xcode_sim_runtime_path/Library") - - write_paths=("-o" "${write_options[@]}" $no_overwrite "$sdks_output_path_single_sdk_path/Developer" - "-o" "${write_options[@]}" $no_overwrite "$sdks_output_path_single_sdk_path/System" - "-o" "${write_options[@]}" $no_overwrite "$sdks_output_path_single_sdk_path/Library") - - "$tbd_tool" "${parse_paths[@]}" "${write_paths[@]}" - - - if [[ $? -ne 0 ]]; then - echo "Failed to create tbds from simulator runtime for $sdk_platform $xcode_sdk_version" - fi -fi diff --git a/tools/create_patched_sdk.sh b/tools/create_patched_sdk.sh new file mode 100755 index 0000000000..c4f36bb7a8 --- /dev/null +++ b/tools/create_patched_sdk.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +if [ "${1}" == "-h" ] || [ "${1}" == "--help" ]; then + echo "Usage: ${0} " + exit 0 +fi + +if [ $# -ne 4 ]; then + exit 1 +fi + +SYMBOLS_PATH="${1}" +if [ -z "${SYMBOLS_PATH}" ]; then + exit 1 +fi + +SDK_OUTPUT_PATH="${2}" +if [ -z "${SDK_OUTPUT_PATH}" ]; then + exit 1 +fi + +BASE_SDK_PATH="${3}" +if [ -z "${BASE_SDK_PATH}" ]; then + exit 1 +fi + +TBD_TOOL_PATH="${4}" +if [ -z "${TBD_TOOL_PATH}" ]; then + exit 1 +fi + +# tbd info +TBD_OUTPUT_VERSION="v3" + +archs_option=("--replace-archs" armv7 armv7s arm64 arm64e) +tbd_options=("--ignore-clients" "--ignore-undefineds" "--allow-private-objc-symbols" "--ignore-missing-exports") +write_options=("--preserve-subdirs" "--replace-path-extension") + +# trailing slash is important since often the BASE_SDK_PATH is a symlink to a real SDK +cp -a "${BASE_SDK_PATH}/" "${SDK_OUTPUT_PATH}" + +"${TBD_TOOL_PATH}" \ + -p "${tbd_options[@]}" "${archs_option[@]}" -v "${TBD_OUTPUT_VERSION}" -r all "${SYMBOLS_PATH}" \ + -o "${write_options[@]}" "${SDK_OUTPUT_PATH}" diff --git a/tools/create_patched_sdk_image.sh b/tools/create_patched_sdk_image.sh new file mode 100755 index 0000000000..7202241d96 --- /dev/null +++ b/tools/create_patched_sdk_image.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +if [ "${1}" == "-h" ] || [ "${1}" == "--help" ]; then + echo "Usage: ${0} " + exit 0 +fi + +if [ $# -ne 5 ]; then + exit 1 +fi + +DYLD_CACHE_PATH="${1}" +if [ -z "${DYLD_CACHE_PATH}" ]; then + exit 1 +fi + +SDK_OUTPUT_PATH="${2}" +if [ -z "${SDK_OUTPUT_PATH}" ]; then + exit 1 +fi + +BASE_SDK_PATH="${3}" +if [ -z "${BASE_SDK_PATH}" ]; then + exit 1 +fi + +PLATFORM_PATH="${4}" +# PLATFORM_PATH is allowed to be empty for macOS + +TBD_TOOL_PATH="${5}" +if [ -z "${TBD_TOOL_PATH}" ]; then + exit 1 +fi + +SYMBOLS_DIR="$(mktemp -d -t symbols)" + +make dsc_extractor_client + +./dsc_extractor_client "${PLATFORM_PATH}/usr/lib/dsc_extractor.bundle" "${DYLD_CACHE_PATH}" "${SYMBOLS_DIR}" + +./create_patched_sdk.sh "${SYMBOLS_DIR}" "${SDK_OUTPUT_PATH}" "${BASE_SDK_PATH}" "${TBD_TOOL_PATH}" diff --git a/tools/dsc_extractor_client.c b/tools/dsc_extractor_client.c new file mode 100644 index 0000000000..d00cd3bec6 --- /dev/null +++ b/tools/dsc_extractor_client.c @@ -0,0 +1,36 @@ +// modified from Apple's dyld +// https://github.com/apple-oss-distributions/dyld/blob/18d3cb0/other-tools/dsc_extractor.cpp#L1080-L1111 + +#include +#include +#include + +typedef int (*extractor_proc)(const char *shared_cache_file_path, const char *extraction_root_path, void (^progress)(unsigned current, unsigned total)); + +int main(int argc, const char *argv[]) { + if (argc != 4) { + fprintf(stderr, "usage: %s \n", argv[0]); + return 1; + } + + void *const handle = dlopen(argv[1], RTLD_LAZY); + if (handle == NULL) { + fprintf(stderr, "dsc_extractor.bundle could not be loaded\n"); + return 1; + } + + extractor_proc const proc = (extractor_proc)dlsym(handle, "dyld_shared_cache_extract_dylibs_progress"); + if (proc == NULL) { + fprintf(stderr, "%s did not have dyld_shared_cache_extract_dylibs_progress symbol\n", argv[1]); + return 1; + } + + int result = proc(argv[2], argv[3], ^(unsigned current, unsigned total) { + unsigned const c = current + 1; + printf(" %u/%u%c", c, total, (c == total) ? '\n' : '\r'); + fflush(stdout); // since '\r' won't flush automatically + }); + dlclose(handle); + + return result; +}