aboutsummaryrefslogtreecommitdiff
path: root/src/tools/mac
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/mac')
-rw-r--r--src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj4
-rw-r--r--src/tools/mac/dump_syms/dump_syms_tool.cc88
-rw-r--r--src/tools/mac/dump_syms/macho_dump.cc202
-rw-r--r--src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj4
-rw-r--r--src/tools/mac/upload_system_symbols/upload_system_symbols.go25
-rwxr-xr-xsrc/tools/mac/upload_system_symbols/upload_system_symbols.sh114
6 files changed, 207 insertions, 230 deletions
diff --git a/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj b/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj
index 5b644e24..c98b6ac5 100644
--- a/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj
+++ b/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj
@@ -1251,7 +1251,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 8B3102D411F0D60300FCF3E4 /* BreakpadDebug.xcconfig */;
buildSettings = {
- CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+ CLANG_CXX_LANGUAGE_STANDARD = "c++17";
HEADER_SEARCH_PATHS = (
../../..,
../../../common/mac/include/,
@@ -1264,7 +1264,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 8B3102D511F0D60300FCF3E4 /* BreakpadRelease.xcconfig */;
buildSettings = {
- CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+ CLANG_CXX_LANGUAGE_STANDARD = "c++17";
HEADER_SEARCH_PATHS = (
../../..,
../../../common/mac/include/,
diff --git a/src/tools/mac/dump_syms/dump_syms_tool.cc b/src/tools/mac/dump_syms/dump_syms_tool.cc
index 2e05cbf3..9fb8d13f 100644
--- a/src/tools/mac/dump_syms/dump_syms_tool.cc
+++ b/src/tools/mac/dump_syms/dump_syms_tool.cc
@@ -31,6 +31,10 @@
// dump_syms_tool.cc: Command line tool that uses the DumpSymbols class.
// TODO(waylonis): accept stdin
+#ifdef HAVE_CONFIG_H
+#include <config.h> // Must come first
+#endif
+
#include <mach-o/arch.h>
#include <unistd.h>
@@ -59,16 +63,20 @@ struct Options {
cfi(true),
handle_inter_cu_refs(true),
handle_inlines(false),
- enable_multiple(false) {}
+ enable_multiple(false),
+ module_name(),
+ prefer_extern_name(false) {}
string srcPath;
string dsymPath;
- const NXArchInfo *arch;
+ std::optional<ArchInfo> arch;
bool header_only;
bool cfi;
bool handle_inter_cu_refs;
bool handle_inlines;
bool enable_multiple;
+ string module_name;
+ bool prefer_extern_name;
};
static bool StackFrameEntryComparator(const Module::StackFrameEntry* a,
@@ -117,11 +125,12 @@ static void CopyCFIDataBetweenModules(Module* to_module,
}
static bool SetArchitecture(DumpSymbols& dump_symbols,
- const NXArchInfo* arch,
+ const ArchInfo& arch,
const std::string& filename) {
- if (!dump_symbols.SetArchitecture(arch->cputype, arch->cpusubtype)) {
+ if (!dump_symbols.SetArchitecture(arch)) {
fprintf(stderr, "%s: no architecture '%s' is present in file.\n",
- filename.c_str(), arch->name);
+ filename.c_str(),
+ GetNameFromCPUType(arch.cputype, arch.cpusubtype));
size_t available_size;
const SuperFatArch* available =
dump_symbols.AvailableArchitectures(&available_size);
@@ -131,14 +140,8 @@ static bool SetArchitecture(DumpSymbols& dump_symbols,
fprintf(stderr, "architectures present in the file are:\n");
for (size_t i = 0; i < available_size; i++) {
const SuperFatArch* arch = &available[i];
- const NXArchInfo* arch_info =
- google_breakpad::BreakpadGetArchInfoFromCpuType(arch->cputype,
- arch->cpusubtype);
- if (arch_info)
- fprintf(stderr, "%s (%s)\n", arch_info->name, arch_info->description);
- else
- fprintf(stderr, "unrecognized cpu type 0x%x, subtype 0x%x\n",
- arch->cputype, arch->cpusubtype);
+ fprintf(stderr, "%s\n",
+ GetNameFromCPUType(arch->cputype, arch->cpusubtype));
}
return false;
}
@@ -150,7 +153,8 @@ static bool Start(const Options& options) {
(options.handle_inlines ? INLINES : NO_DATA) |
(options.cfi ? CFI : NO_DATA) | SYMBOLS_AND_FILES;
DumpSymbols dump_symbols(symbol_data, options.handle_inter_cu_refs,
- options.enable_multiple);
+ options.enable_multiple, options.module_name,
+ options.prefer_extern_name);
// For x86_64 binaries, the CFI data is in the __TEXT,__eh_frame of the
// Mach-O file, which is not copied into the dSYM. Whereas in i386, the CFI
@@ -169,7 +173,7 @@ static bool Start(const Options& options) {
return false;
if (options.arch &&
- !SetArchitecture(dump_symbols, options.arch, primary_file)) {
+ !SetArchitecture(dump_symbols, *options.arch, primary_file)) {
return false;
}
@@ -189,7 +193,7 @@ static bool Start(const Options& options) {
return false;
if (options.arch &&
- !SetArchitecture(dump_symbols, options.arch, options.srcPath)) {
+ !SetArchitecture(dump_symbols, *options.arch, options.srcPath)) {
return false;
}
Module* cfi_module = NULL;
@@ -197,13 +201,38 @@ static bool Start(const Options& options) {
return false;
scoped_ptr<Module> scoped_cfi_module(cfi_module);
+ bool name_matches;
+ if (!options.module_name.empty()) {
+ // Ignore the basename of the dSYM and binary and use the passed-in module
+ // name.
+ name_matches = true;
+ } else {
+ name_matches = cfi_module->name() == module->name();
+ }
+
// Ensure that the modules are for the same debug code file.
- if (cfi_module->name() != module->name() ||
- cfi_module->os() != module->os() ||
+ if (!name_matches || cfi_module->os() != module->os() ||
cfi_module->architecture() != module->architecture() ||
cfi_module->identifier() != module->identifier()) {
fprintf(stderr, "Cannot generate a symbol file from split sources that do"
" not match.\n");
+ if (!name_matches) {
+ fprintf(stderr, "Name mismatch: binary=[%s], dSYM=[%s]\n",
+ cfi_module->name().c_str(), module->name().c_str());
+ }
+ if (cfi_module->os() != module->os()) {
+ fprintf(stderr, "OS mismatch: binary=[%s], dSYM=[%s]\n",
+ cfi_module->os().c_str(), module->os().c_str());
+ }
+ if (cfi_module->architecture() != module->architecture()) {
+ fprintf(stderr, "Architecture mismatch: binary=[%s], dSYM=[%s]\n",
+ cfi_module->architecture().c_str(),
+ module->architecture().c_str());
+ }
+ if (cfi_module->identifier() != module->identifier()) {
+ fprintf(stderr, "Identifier mismatch: binary=[%s], dSYM=[%s]\n",
+ cfi_module->identifier().c_str(), module->identifier().c_str());
+ }
return false;
}
@@ -216,8 +245,10 @@ static bool Start(const Options& options) {
//=============================================================================
static void Usage(int argc, const char *argv[]) {
fprintf(stderr, "Output a Breakpad symbol file from a Mach-o file.\n");
- fprintf(stderr, "Usage: %s [-a ARCHITECTURE] [-c] [-g dSYM path] "
- "<Mach-o file>\n", argv[0]);
+ fprintf(stderr,
+ "Usage: %s [-a ARCHITECTURE] [-c] [-g dSYM path] "
+ "[-n MODULE] [-x] <Mach-o file>\n",
+ argv[0]);
fprintf(stderr, "\t-i: Output module header information only.\n");
fprintf(stderr, "\t-a: Architecture type [default: native, or whatever is\n");
fprintf(stderr, "\t in the file, if it contains only one architecture]\n");
@@ -229,6 +260,12 @@ static void Usage(int argc, const char *argv[]) {
fprintf(stderr,
"\t-m: Enable writing the optional 'm' field on FUNC "
"and PUBLIC, denoting multiple symbols for the address.\n");
+ fprintf(stderr,
+ "\t-n: Use MODULE as the name of the module rather than \n"
+ "the basename of the Mach-O file/dSYM.\n");
+ fprintf(stderr,
+ "\t-x: Prefer the PUBLIC (extern) name over the FUNC if\n"
+ "they do not match.\n");
fprintf(stderr, "\t-h: Usage\n");
fprintf(stderr, "\t-?: Usage\n");
}
@@ -238,14 +275,13 @@ static void SetupOptions(int argc, const char *argv[], Options *options) {
extern int optind;
signed char ch;
- while ((ch = getopt(argc, (char* const*)argv, "ia:g:crdm?h")) != -1) {
+ while ((ch = getopt(argc, (char* const*)argv, "ia:g:crdm?hn:x")) != -1) {
switch (ch) {
case 'i':
options->header_only = true;
break;
case 'a': {
- const NXArchInfo *arch_info =
- google_breakpad::BreakpadGetArchInfoFromName(optarg);
+ std::optional<ArchInfo> arch_info = GetArchInfoFromName(optarg);
if (!arch_info) {
fprintf(stderr, "%s: Invalid architecture: %s\n", argv[0], optarg);
Usage(argc, argv);
@@ -269,6 +305,12 @@ static void SetupOptions(int argc, const char *argv[], Options *options) {
case 'm':
options->enable_multiple = true;
break;
+ case 'n':
+ options->module_name = optarg;
+ break;
+ case 'x':
+ options->prefer_extern_name = true;
+ break;
case '?':
case 'h':
Usage(argc, argv);
diff --git a/src/tools/mac/dump_syms/macho_dump.cc b/src/tools/mac/dump_syms/macho_dump.cc
deleted file mode 100644
index b724cc74..00000000
--- a/src/tools/mac/dump_syms/macho_dump.cc
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright 2010 Google LLC
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google LLC nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
-
-// macho_dump.cc: Dump the contents of a Mach-O file. This is mostly
-// a test program for the Mach_O::FatReader and Mach_O::Reader classes.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <mach-o/arch.h>
-#include <sys/mman.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include "common/byte_cursor.h"
-#include "common/mac/arch_utilities.h"
-#include "common/mac/macho_reader.h"
-#include "common/path_helper.h"
-
-using google_breakpad::ByteBuffer;
-using std::ostringstream;
-using std::string;
-using std::vector;
-
-namespace {
-namespace mach_o = google_breakpad::mach_o;
-
-string program_name;
-
-int check_syscall(int result, const char* operation, const char* filename) {
- if (result < 0) {
- fprintf(stderr, "%s: %s '%s': %s\n",
- program_name.c_str(), operation,
- filename, strerror(errno));
- exit(1);
- }
- return result;
-}
-
-class DumpSection: public mach_o::Reader::SectionHandler {
- public:
- DumpSection() : index_(0) { }
- bool HandleSection(const mach_o::Section& section) {
- printf(" section %d '%s' in segment '%s'\n"
- " address: 0x%llx\n"
- " alignment: 1 << %d B\n"
- " flags: %d\n"
- " size: %ld\n",
- index_++, section.section_name.c_str(), section.segment_name.c_str(),
- section.address, section.align,
- mach_o::SectionFlags(section.flags),
- section.contents.Size());
- return true;
- }
-
- private:
- int index_;
-};
-
-class DumpCommand: public mach_o::Reader::LoadCommandHandler {
- public:
- DumpCommand(mach_o::Reader* reader) : reader_(reader), index_(0) { }
- bool UnknownCommand(mach_o::LoadCommandType type,
- const ByteBuffer& contents) {
- printf(" load command %d: %d", index_++, type);
- return true;
- }
- bool SegmentCommand(const mach_o::Segment& segment) {
- printf(" load command %d: %s-bit segment '%s'\n"
- " address: 0x%llx\n"
- " memory size: 0x%llx\n"
- " maximum protection: 0x%x\n"
- " initial protection: 0x%x\n"
- " flags: %d\n"
- " section_list size: %ld B\n",
- index_++, (segment.bits_64 ? "64" : "32"), segment.name.c_str(),
- segment.vmaddr, segment.vmsize, segment.maxprot,
- segment.initprot, mach_o::SegmentFlags(segment.flags),
- segment.section_list.Size());
-
- DumpSection dump_section;
- return reader_->WalkSegmentSections(segment, &dump_section);
- }
- private:
- mach_o::Reader* reader_;
- int index_;
-};
-
-void DumpFile(const char* filename) {
- int fd = check_syscall(open(filename, O_RDONLY), "opening", filename);
- struct stat attributes;
- check_syscall(fstat(fd, &attributes),
- "getting file attributes for", filename);
- void* mapping = mmap(NULL, attributes.st_size, PROT_READ,
- MAP_PRIVATE, fd, 0);
- close(fd);
- check_syscall(mapping == (void*)-1 ? -1 : 0,
- "mapping contents of", filename);
-
- mach_o::FatReader::Reporter fat_reporter(filename);
- mach_o::FatReader fat_reader(&fat_reporter);
- if (!fat_reader.Read(reinterpret_cast<uint8_t*>(mapping),
- attributes.st_size)) {
- exit(1);
- }
- printf("filename: %s\n", filename);
- size_t object_files_size;
- const SuperFatArch* super_fat_object_files =
- fat_reader.object_files(&object_files_size);
- struct fat_arch* object_files;
- if (!super_fat_object_files->ConvertToFatArch(object_files)) {
- exit(1);
- }
- printf(" object file count: %ld\n", object_files_size);
- for (size_t i = 0; i < object_files_size; i++) {
- const struct fat_arch& file = object_files[i];
- const NXArchInfo* fat_arch_info =
- google_breakpad::BreakpadGetArchInfoFromCpuType(
- file.cputype, file.cpusubtype);
- printf("\n object file %ld:\n"
- " fat header:\n:"
- " CPU type: %s (%s)\n"
- " size: %d B\n"
- " alignment: 1<<%d B\n",
- i, fat_arch_info->name, fat_arch_info->description,
- file.size, file.align);
-
- ostringstream name;
- name << filename;
- if (object_files_size > 1)
- name << ", object file #" << i;
- ByteBuffer file_contents(reinterpret_cast<uint8_t*>(mapping)
- + file.offset, file.size);
- mach_o::Reader::Reporter reporter(name.str());
- mach_o::Reader reader(&reporter);
- if (!reader.Read(file_contents, file.cputype, file.cpusubtype)) {
- exit(1);
- }
-
- const NXArchInfo* macho_arch_info =
- NXGetArchInfoFromCpuType(reader.cpu_type(),
- reader.cpu_subtype());
- printf(" Mach-O header:\n"
- " word size: %s\n"
- " CPU type: %s (%s)\n"
- " File type: %d\n"
- " flags: %x\n",
- (reader.bits_64() ? "64 bits" : "32 bits"),
- macho_arch_info->name, macho_arch_info->description,
- reader.file_type(), reader.flags());
-
- DumpCommand dump_command(&reader);
- reader.WalkLoadCommands(&dump_command);
- }
- munmap(mapping, attributes.st_size);
-}
-
-} // namespace
-
-int main(int argc, char** argv) {
- program_name = google_breakpad::BaseName(argv[0]);
- if (argc == 1) {
- fprintf(stderr, "Usage: %s FILE ...\n"
- "Dump the contents of the Mach-O or fat binary files "
- "'FILE ...'.\n", program_name.c_str());
- }
- for (int i = 1; i < argc; i++) {
- DumpFile(argv[i]);
- }
-}
diff --git a/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj b/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
index 903c66f1..b1dd6a11 100644
--- a/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
+++ b/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
@@ -371,7 +371,7 @@
1DEB927508733DD40010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+ CLANG_CXX_LANGUAGE_STANDARD = "c++17";
GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H;
HEADER_SEARCH_PATHS = (
../../..,
@@ -385,7 +385,7 @@
1DEB927608733DD40010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+ CLANG_CXX_LANGUAGE_STANDARD = "c++17";
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
NDEBUG,
diff --git a/src/tools/mac/upload_system_symbols/upload_system_symbols.go b/src/tools/mac/upload_system_symbols/upload_system_symbols.go
index ba067276..f34c288a 100644
--- a/src/tools/mac/upload_system_symbols/upload_system_symbols.go
+++ b/src/tools/mac/upload_system_symbols/upload_system_symbols.go
@@ -163,6 +163,29 @@ func main() {
}
}
+// manglePath reduces an absolute filesystem path to a string suitable as the
+// base for a file name which encodes some of the original path. The result
+// concatenates the leading initial from each path component except the last to
+// the last path component; for example /System/Library/Frameworks/AppKit
+// becomes SLFAppKit.
+// Assumes ASCII.
+func manglePath(path string) string {
+ components := strings.Split(path, "/")
+ n := len(components)
+ builder := strings.Builder{}
+ for i, component := range components {
+ if len(component) == 0 {
+ continue
+ }
+ if i < n-1 {
+ builder.WriteString(component[:1])
+ } else {
+ builder.WriteString(component)
+ }
+ }
+ return builder.String()
+}
+
type WorkerPool struct {
wg sync.WaitGroup
}
@@ -296,7 +319,7 @@ func (dq *DumpQueue) worker() {
dumpSyms := path.Join(*breakpadTools, "dump_syms")
for req := range dq.queue {
- filebase := path.Join(dq.dumpPath, strings.Replace(req.path, "/", "_", -1))
+ filebase := path.Join(dq.dumpPath, manglePath(req.path))
symfile := fmt.Sprintf("%s_%s.sym", filebase, req.arch)
f, err := os.Create(symfile)
if err != nil {
diff --git a/src/tools/mac/upload_system_symbols/upload_system_symbols.sh b/src/tools/mac/upload_system_symbols/upload_system_symbols.sh
new file mode 100755
index 00000000..43fd98ed
--- /dev/null
+++ b/src/tools/mac/upload_system_symbols/upload_system_symbols.sh
@@ -0,0 +1,114 @@
+#!/bin/bash
+
+# Copyright 2023 Google LLC
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google LLC nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Finds the dyld_shared_cache on a system, extracts it, and dumps the symbols
+# in Breakpad format to the directory passed as the first argument
+# The script must be in the same directory as `dump_syms`,
+# `upload_system_symbols` and `dsc_extractor` binaries.
+# Exits with 0 if all supported architectures for this OS version were found and
+# dumped, and nonzero otherwise.
+
+set -ex
+
+if [[ $# -ne 1 ]]; then
+ echo "usage: $0 <destination_directory>" >& 2
+ exit 1
+fi
+
+destination_dir="$1"
+
+dir="$(dirname "$0")"
+dir="$(cd "${dir}"; pwd)"
+major_version=$(sw_vers -productVersion | cut -d . -f 1)
+if [[ "${major_version}" -lt 13 ]]; then
+ dsc_directory="/System/Library/dyld"
+else
+ dsc_directory="/System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld"
+fi
+
+working_dir=$(mktemp -d)
+mkdir "${destination_dir}"
+trap 'rm -rf "${working_dir}" "${destination_dir}"' EXIT
+
+architectures=(x86_64h)
+missing_architectures=()
+# macOS >= 13 on arm64 still has a x86_64 cache for Rosetta.
+if [[ "${major_version}" -lt 13 ]] || [[ $(uname -p) == "arm" ]]; then
+ architectures+=( x86_64 )
+fi
+if [[ "${major_version}" -ge 11 ]]; then
+ architectures+=( arm64e )
+fi
+
+for arch in "${architectures[@]}"; do
+ cache="${dsc_directory}/dyld_shared_cache_${arch}"
+ if [[ ! -f "${cache}" ]]; then
+ missing_architectures+=("${arch}")
+ continue
+ fi
+ "${dir}/dsc_extractor" \
+ "${cache}" \
+ "${working_dir}/${arch}"
+ "${dir}/upload_system_symbols" \
+ --breakpad-tools="${dir}" \
+ --system-root="${working_dir}/${arch}" \
+ --dump-to="${destination_dir}"
+done
+if [[ "${#missing_architectures[@]}" -eq "${#architectures[@]}" ]]; then
+ echo "Couldn't locate dyld_shared_cache for any architectures" >& 2
+ echo "in ${dsc_directory}. Exiting." >& 2
+ exit 1
+fi
+
+rm -rf "${working_dir}"
+# We have results now, so let's keep `destination_dir`.
+trap '' EXIT
+
+"${dir}/upload_system_symbols" \
+ --breakpad-tools="${dir}" \
+ --system-root=/ \
+ --dump-to="${destination_dir}"
+
+set +x
+echo
+echo "Dumped!"
+echo "To upload, run:"
+echo
+echo "'${dir}/upload_system_symbols'" \\
+echo " --breakpad-tools='${dir}'" \\
+echo " --api-key=<YOUR API KEY>" \\
+echo " --upload-from='${destination_dir}'"
+
+if [[ "${#missing_architectures[@]}" -gt 0 ]]; then
+ echo "dyld_shared_cache not found for architecture(s):" >& 2
+ echo " " "${missing_architectures[@]}" >& 2
+ echo "You'll need to get symbols for them elsewhere." >& 2
+ exit 1
+fi