Move dead submodules in-tree

Signed-off-by: swurl <swurl@swurl.xyz>
This commit is contained in:
swurl 2025-05-31 02:33:02 -04:00
parent c0cceff365
commit 6c655321e6
Signed by: crueter
GPG key ID: A5A7629F109C8FD1
4081 changed files with 1185566 additions and 45 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,340 @@
// -*- mode: c++ -*-
// Copyright 2011 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.
// 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>
#include <algorithm>
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
#include "common/mac/dump_syms.h"
#include "common/mac/arch_utilities.h"
#include "common/mac/macho_utilities.h"
#include "common/scoped_ptr.h"
using google_breakpad::DumpSymbols;
using google_breakpad::Module;
using google_breakpad::scoped_ptr;
using std::vector;
struct Options {
Options()
: srcPath(),
dsymPath(),
arch(),
header_only(false),
cfi(true),
handle_inter_cu_refs(true),
handle_inlines(false),
enable_multiple(false),
module_name(),
prefer_extern_name(false) {}
string srcPath;
string dsymPath;
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,
const Module::StackFrameEntry* b) {
return a->address < b->address;
}
// Copy the CFI data from |from_module| into |to_module|, for any non-
// overlapping ranges.
static void CopyCFIDataBetweenModules(Module* to_module,
const Module* from_module) {
typedef vector<Module::StackFrameEntry*>::const_iterator Iterator;
// Get the CFI data from both the source and destination modules and ensure
// it is sorted by start address.
vector<Module::StackFrameEntry*> from_data;
from_module->GetStackFrameEntries(&from_data);
std::sort(from_data.begin(), from_data.end(), &StackFrameEntryComparator);
vector<Module::StackFrameEntry*> to_data;
to_module->GetStackFrameEntries(&to_data);
std::sort(to_data.begin(), to_data.end(), &StackFrameEntryComparator);
Iterator to_it = to_data.begin();
for (Iterator it = from_data.begin(); it != from_data.end(); ++it) {
Module::StackFrameEntry* from_entry = *it;
Module::Address from_entry_end = from_entry->address + from_entry->size;
// Find the first CFI record in the |to_module| that does not have an
// address less than the entry to be copied.
while (to_it != to_data.end()) {
if (from_entry->address > (*to_it)->address)
++to_it;
else
break;
}
// If the entry does not overlap, then it is safe to copy to |to_module|.
if (to_it == to_data.end() || (from_entry->address < (*to_it)->address &&
from_entry_end < (*to_it)->address)) {
to_module->AddStackFrameEntry(
std::make_unique<Module::StackFrameEntry>(*from_entry));
}
}
}
static bool SetArchitecture(DumpSymbols& dump_symbols,
const ArchInfo& arch,
const std::string& filename) {
if (!dump_symbols.SetArchitecture(arch)) {
fprintf(stderr, "%s: no architecture '%s' is present in file.\n",
filename.c_str(),
GetNameFromCPUType(arch.cputype, arch.cpusubtype));
size_t available_size;
const SuperFatArch* available =
dump_symbols.AvailableArchitectures(&available_size);
if (available_size == 1)
fprintf(stderr, "the file's architecture is: ");
else
fprintf(stderr, "architectures present in the file are:\n");
for (size_t i = 0; i < available_size; i++) {
const SuperFatArch* arch = &available[i];
fprintf(stderr, "%s\n",
GetNameFromCPUType(arch->cputype, arch->cpusubtype));
}
return false;
}
return true;
}
static bool Start(const Options& options) {
SymbolData symbol_data =
(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.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
// data is in the __DWARF,__debug_frame section, which is moved into the
// dSYM. Therefore, to get x86_64 CFI data, dump_syms needs to look at both
// the dSYM and the Mach-O file. If both paths are present and CFI was
// requested, then consider the Module as "split" and dump all the debug data
// from the primary debug info file, the dSYM, and then dump additional CFI
// data from the source Mach-O file.
bool split_module =
!options.dsymPath.empty() && !options.srcPath.empty() && options.cfi;
const string& primary_file =
split_module ? options.dsymPath : options.srcPath;
if (!dump_symbols.Read(primary_file))
return false;
if (options.arch &&
!SetArchitecture(dump_symbols, *options.arch, primary_file)) {
return false;
}
if (options.header_only)
return dump_symbols.WriteSymbolFileHeader(std::cout);
// Read the primary file into a Breakpad Module.
Module* module = NULL;
if (!dump_symbols.ReadSymbolData(&module))
return false;
scoped_ptr<Module> scoped_module(module);
// If this is a split module, read the secondary Mach-O file, from which the
// CFI data will be extracted.
if (split_module && primary_file == options.dsymPath) {
if (!dump_symbols.Read(options.srcPath))
return false;
if (options.arch &&
!SetArchitecture(dump_symbols, *options.arch, options.srcPath)) {
return false;
}
Module* cfi_module = NULL;
if (!dump_symbols.ReadSymbolData(&cfi_module))
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 (!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;
}
CopyCFIDataBetweenModules(module, cfi_module);
}
return module->Write(std::cout, symbol_data);
}
//=============================================================================
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] "
"[-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");
fprintf(stderr, "\t-g: Debug symbol file (dSYM) to dump in addition to the "
"Mach-o file\n");
fprintf(stderr, "\t-c: Do not generate CFI section\n");
fprintf(stderr, "\t-r: Do not handle inter-compilation unit references\n");
fprintf(stderr, "\t-d: Generate INLINE and INLINE_ORIGIN records\n");
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");
}
//=============================================================================
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?hn:x")) != -1) {
switch (ch) {
case 'i':
options->header_only = true;
break;
case 'a': {
std::optional<ArchInfo> arch_info = GetArchInfoFromName(optarg);
if (!arch_info) {
fprintf(stderr, "%s: Invalid architecture: %s\n", argv[0], optarg);
Usage(argc, argv);
exit(1);
}
options->arch = arch_info;
break;
}
case 'g':
options->dsymPath = optarg;
break;
case 'c':
options->cfi = false;
break;
case 'r':
options->handle_inter_cu_refs = false;
break;
case 'd':
options->handle_inlines = true;
break;
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);
exit(0);
break;
}
}
if ((argc - optind) != 1) {
fprintf(stderr, "Must specify Mach-o file\n");
Usage(argc, argv);
exit(1);
}
options->srcPath = argv[optind];
}
//=============================================================================
int main (int argc, const char * argv[]) {
Options options;
bool result;
SetupOptions(argc, argv, &options);
result = Start(options);
return !result;
}

View file

@ -0,0 +1,474 @@
// Copyright 2006 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.
// symupload.mm: Upload a symbol file to a HTTP server. The upload is sent as
// a multipart/form-data POST request with the following parameters:
// code_file: the basename of the module, e.g. "app"
// debug_file: the basename of the debugging file, e.g. "app"
// debug_identifier: the debug file's identifier, usually consisting of
// the guid and age embedded in the pdb, e.g.
// "11111111BBBB3333DDDD555555555555F"
// os: the operating system that the module was built for
// cpu: the CPU that the module was built for (x86 or ppc)
// symbol_file: the contents of the breakpad-format symbol file
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <Foundation/Foundation.h>
#include "HTTPMultipartUpload.h"
#include "HTTPPutRequest.h"
#include "SymbolCollectorClient.h"
#include "common/mac/dump_syms.h"
using google_breakpad::DumpSymbols;
NSString* const kBreakpadSymbolType = @"BREAKPAD";
NSString* const kMachOSymbolType = @"MACHO";
NSString* const kDSYMSymbolType = @"DSYM";
typedef enum { kSymUploadProtocolV1, kSymUploadProtocolV2 } SymUploadProtocol;
typedef enum {
kResultSuccess = 0,
kResultFailure = 1,
kResultAlreadyExists = 2
} Result;
typedef struct {
NSString* symbolsPath;
NSString* uploadURLStr;
SymUploadProtocol symUploadProtocol;
NSString* apiKey;
BOOL force;
Result result;
NSString* type;
NSString* codeFile;
NSString* debugID;
NSString* productName;
} Options;
//=============================================================================
static NSArray* ModuleDataForSymbolFile(NSString* file) {
NSFileHandle* fh = [NSFileHandle fileHandleForReadingAtPath:file];
NSData* data = [fh readDataOfLength:1024];
NSString* str = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSScanner* scanner = [NSScanner scannerWithString:str];
NSString* line;
NSMutableArray* parts = nil;
const int MODULE_ID_INDEX = 3;
if ([scanner scanUpToString:@"\n" intoString:&line]) {
parts = [[NSMutableArray alloc] init];
NSScanner* moduleInfoScanner = [NSScanner scannerWithString:line];
NSString* moduleInfo;
// Get everything BEFORE the module name. None of these properties
// can have spaces.
for (int i = 0; i <= MODULE_ID_INDEX; i++) {
[moduleInfoScanner scanUpToString:@" " intoString:&moduleInfo];
[parts addObject:moduleInfo];
}
// Now get the module name. This can have a space so we scan to
// the end of the line.
[moduleInfoScanner scanUpToString:@"\n" intoString:&moduleInfo];
[parts addObject:moduleInfo];
}
[str release];
return parts;
}
//=============================================================================
static void StartSymUploadProtocolV1(Options* options,
NSString* OS,
NSString* CPU,
NSString* debugID,
NSString* debugFile) {
NSURL* url = [NSURL URLWithString:options->uploadURLStr];
HTTPMultipartUpload* ul = [[HTTPMultipartUpload alloc] initWithURL:url];
NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
// Add parameters
[parameters setObject:debugID forKey:@"debug_identifier"];
[parameters setObject:OS forKey:@"os"];
[parameters setObject:CPU forKey:@"cpu"];
[parameters setObject:debugFile forKey:@"debug_file"];
[parameters setObject:debugFile forKey:@"code_file"];
[ul setParameters:parameters];
NSArray* keys = [parameters allKeys];
int count = [keys count];
for (int i = 0; i < count; ++i) {
NSString* key = [keys objectAtIndex:i];
NSString* value = [parameters objectForKey:key];
fprintf(stdout, "'%s' = '%s'\n", [key UTF8String], [value UTF8String]);
}
// Add file
[ul addFileAtPath:options->symbolsPath name:@"symbol_file"];
// Send it
NSError* error = nil;
NSData* data = [ul send:&error];
NSString* result = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
int status = [[ul response] statusCode];
fprintf(stdout, "Send: %s\n",
error ? [[error description] UTF8String] : "No Error");
fprintf(stdout, "Response: %d\n", status);
fprintf(stdout, "Result: %lu bytes\n%s\n", (unsigned long)[data length],
[result UTF8String]);
[result release];
[ul release];
options->result = (!error && status == 200) ? kResultSuccess : kResultFailure;
}
//=============================================================================
static void StartSymUploadProtocolV2(Options* options,
NSString* debugID,
NSString* debugFile) {
options->result = kResultFailure;
// Only check status of BREAKPAD symbols, because the v2 protocol doesn't
// (yet) have a way to check status of other symbol types.
if (!options->force && [options->type isEqualToString:kBreakpadSymbolType]) {
SymbolStatus symbolStatus =
[SymbolCollectorClient checkSymbolStatusOnServer:options->uploadURLStr
withAPIKey:options->apiKey
withDebugFile:debugFile
withDebugID:debugID];
if (symbolStatus == SymbolStatusFound) {
fprintf(stdout, "Symbol file already exists, upload aborted."
" Use \"-f\" to overwrite.\n");
options->result = kResultAlreadyExists;
return;
} else if (symbolStatus == SymbolStatusUnknown) {
fprintf(stdout, "Failed to get check for existing symbol.\n");
return;
}
}
UploadURLResponse* URLResponse =
[SymbolCollectorClient createUploadURLOnServer:options->uploadURLStr
withAPIKey:options->apiKey];
if (URLResponse == nil) {
return;
}
NSURL* uploadURL = [NSURL URLWithString:[URLResponse uploadURL]];
HTTPPutRequest* putRequest = [[HTTPPutRequest alloc] initWithURL:uploadURL];
[putRequest setFile:options->symbolsPath];
NSError* error = nil;
NSData* data = [putRequest send:&error];
NSString* result = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
int responseCode = [[putRequest response] statusCode];
[putRequest release];
if (error || responseCode != 200) {
fprintf(stdout, "Failed to upload symbol file.\n");
fprintf(stdout, "Response code: %d\n", responseCode);
fprintf(stdout, "Response:\n");
fprintf(stdout, "%s\n", [result UTF8String]);
return;
}
CompleteUploadResult completeUploadResult =
[SymbolCollectorClient completeUploadOnServer:options->uploadURLStr
withAPIKey:options->apiKey
withUploadKey:[URLResponse uploadKey]
withDebugFile:debugFile
withDebugID:debugID
withType:options->type
withProductName:options->productName];
[URLResponse release];
if (completeUploadResult == CompleteUploadResultError) {
fprintf(stdout, "Failed to complete upload.\n");
return;
} else if (completeUploadResult == CompleteUploadResultDuplicateData) {
fprintf(stdout, "Uploaded file checksum matched existing file checksum,"
" no change necessary.\n");
} else {
fprintf(stdout, "Successfully sent the symbol file.\n");
}
options->result = kResultSuccess;
}
//=============================================================================
static void Start(Options* options) {
// If non-BREAKPAD upload special-case.
if (![options->type isEqualToString:kBreakpadSymbolType]) {
StartSymUploadProtocolV2(options, options->debugID, options->codeFile);
return;
}
NSArray* moduleParts = ModuleDataForSymbolFile(options->symbolsPath);
// MODULE <os> <cpu> <uuid> <module-name>
// 0 1 2 3 4
NSString* OS = [moduleParts objectAtIndex:1];
NSString* CPU = [moduleParts objectAtIndex:2];
NSMutableString* debugID =
[NSMutableString stringWithString:[moduleParts objectAtIndex:3]];
[debugID replaceOccurrencesOfString:@"-"
withString:@""
options:0
range:NSMakeRange(0, [debugID length])];
NSString* debugFile = [moduleParts objectAtIndex:4];
if (options->symUploadProtocol == kSymUploadProtocolV1) {
StartSymUploadProtocolV1(options, OS, CPU, debugID, debugFile);
} else if (options->symUploadProtocol == kSymUploadProtocolV2) {
StartSymUploadProtocolV2(options, debugID, debugFile);
}
}
//=============================================================================
static void Usage(int argc, const char* argv[]) {
fprintf(stderr, "Submit symbol information.\n");
fprintf(stderr, "Usage: %s [options] <symbol-file> <upload-URL>\n", argv[0]);
fprintf(stderr, "<symbol-file> should be created by using the dump_syms "
"tool.\n");
fprintf(stderr, "<upload-URL> is the destination for the upload.\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, "\t-p <protocol>: protocol to use for upload, accepts "
"[\"sym-upload-v1\", \"sym-upload-v2\"]. Default is "
"\"sym-upload-v1\".\n");
fprintf(stderr, "\t-k <api-key>: secret for authentication with upload "
"server. [Only in sym-upload-v2 protocol mode]\n");
fprintf(stderr, "\t-f: Overwrite symbol file on server if already present. "
"[Only in sym-upload-v2 protocol mode]\n");
fprintf(
stderr,
"\t-t: <symbol-type> Explicitly set symbol upload type ("
"default is 'breakpad').\n"
"\t One of ['breakpad', 'elf', 'pe', 'macho', 'debug_only', 'dwp', "
"'dsym', 'pdb'].\n"
"\t Note: When this flag is set to anything other than 'breakpad', then "
"the '-c' and '-i' flags must also be set.\n");
fprintf(stderr, "\t-c: <code-file> Explicitly set 'code_file' for symbol "
"upload (basename of executable).\n");
fprintf(stderr, "\t-i: <debug-id> Explicitly set 'debug_id' for symbol "
"upload (typically build ID of executable). The debug-id for "
"symbol-types 'dsym' and 'macho' will be determined "
"automatically. \n");
fprintf(stderr, "\t-n: <product-name> Optionally set 'product_name' for "
"symbol upload\n");
fprintf(stderr, "\t-h: Usage\n");
fprintf(stderr, "\t-?: Usage\n");
fprintf(stderr, "\n");
fprintf(stderr, "Exit codes:\n");
fprintf(stderr, "\t%d: Success\n", kResultSuccess);
fprintf(stderr, "\t%d: Failure\n", kResultFailure);
fprintf(stderr,
"\t%d: Symbol file already exists on server (and -f was not "
"specified).\n",
kResultAlreadyExists);
fprintf(stderr,
"\t [This exit code will only be returned by the sym-upload-v2 "
"protocol.\n");
fprintf(stderr,
"\t The sym-upload-v1 protocol can return either Success or "
"Failure\n");
fprintf(stderr, "\t in this case, and the action taken by the server is "
"unspecified.]\n");
fprintf(stderr, "\n");
fprintf(stderr, "Examples:\n");
fprintf(stderr, " With 'sym-upload-v1':\n");
fprintf(stderr, " %s path/to/symbol_file http://myuploadserver\n",
argv[0]);
fprintf(stderr, " With 'sym-upload-v2':\n");
fprintf(stderr, " [Defaulting to symbol type 'BREAKPAD']\n");
fprintf(stderr,
" %s -p sym-upload-v2 -k mysecret123! "
"path/to/symbol_file http://myuploadserver\n",
argv[0]);
fprintf(stderr, " [Explicitly set symbol type to 'macho']\n");
fprintf(stderr,
" %s -p sym-upload-v2 -k mysecret123! -t macho "
"-c app -i 11111111BBBB3333DDDD555555555555F "
"path/to/symbol_file http://myuploadserver\n",
argv[0]);
}
//=============================================================================
static void SetupOptions(int argc, const char* argv[], Options* options) {
// Set default options values.
options->symUploadProtocol = kSymUploadProtocolV1;
options->apiKey = nil;
options->type = kBreakpadSymbolType;
options->codeFile = nil;
options->debugID = nil;
options->force = NO;
options->productName = nil;
extern int optind;
int ch;
while ((ch = getopt(argc, (char* const*)argv, "p:k:t:c:i:n:hf?")) != -1) {
switch (ch) {
case 'p':
if (strcmp(optarg, "sym-upload-v2") == 0) {
options->symUploadProtocol = kSymUploadProtocolV2;
break;
} else if (strcmp(optarg, "sym-upload-v1") == 0) {
// This is already the default but leave in case that changes.
options->symUploadProtocol = kSymUploadProtocolV1;
break;
}
Usage(argc, argv);
exit(0);
break;
case 'k':
options->apiKey = [NSString stringWithCString:optarg
encoding:NSASCIIStringEncoding];
break;
case 't': {
// This is really an enum, so treat as upper-case for consistency with
// enum naming convention on server-side.
options->type = [[NSString stringWithCString:optarg
encoding:NSASCIIStringEncoding]
uppercaseString];
break;
}
case 'c':
options->codeFile = [NSString stringWithCString:optarg
encoding:NSASCIIStringEncoding];
break;
case 'i':
options->debugID = [NSString stringWithCString:optarg
encoding:NSASCIIStringEncoding];
break;
case 'n':
options->productName =
[NSString stringWithCString:optarg
encoding:NSASCIIStringEncoding];
break;
case 'f':
options->force = YES;
break;
default:
Usage(argc, argv);
exit(0);
break;
}
}
if ((argc - optind) != 2) {
fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]);
Usage(argc, argv);
exit(1);
}
int fd = open(argv[optind], O_RDONLY);
if (fd < 0) {
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
exit(1);
}
struct stat statbuf;
if (fstat(fd, &statbuf) < 0) {
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
close(fd);
exit(1);
}
close(fd);
if (!S_ISREG(statbuf.st_mode)) {
fprintf(stderr, "%s: %s: not a regular file\n", argv[0], argv[optind]);
exit(1);
}
bool isBreakpadUpload = [options->type isEqualToString:kBreakpadSymbolType];
bool hasCodeFile = options->codeFile != nil;
bool hasDebugID = options->debugID != nil;
if (isBreakpadUpload && (hasCodeFile || hasDebugID)) {
fprintf(stderr, "\n");
fprintf(stderr,
"%s: -c and -i should only be specified for non-breakpad "
"symbol upload types.\n",
argv[0]);
fprintf(stderr, "\n");
Usage(argc, argv);
exit(1);
}
if (!isBreakpadUpload && hasCodeFile && !hasDebugID &&
([options->type isEqualToString:kMachOSymbolType] ||
[options->type isEqualToString:kDSYMSymbolType])) {
DumpSymbols dump_symbols(SYMBOLS_AND_FILES | INLINES, false);
if (dump_symbols.Read(argv[optind])) {
std::string identifier = dump_symbols.Identifier();
if (identifier.empty()) {
fprintf(stderr, "\n");
fprintf(stderr,
"%s: Unable to determine debug-id. Please specify with '-i'.\n",
argv[0]);
fprintf(stderr, "\n");
Usage(argc, argv);
exit(1);
}
options->debugID = [NSString stringWithUTF8String:identifier.c_str()];
hasDebugID = true;
}
}
if (!isBreakpadUpload && (!hasCodeFile || !hasDebugID)) {
fprintf(stderr, "\n");
fprintf(stderr,
"%s: -c and -i must be specified for non-breakpad "
"symbol upload types.\n",
argv[0]);
fprintf(stderr, "\n");
Usage(argc, argv);
exit(1);
}
options->symbolsPath = [NSString stringWithUTF8String:argv[optind]];
options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]];
}
//=============================================================================
int main(int argc, const char* argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
Options options;
bzero(&options, sizeof(Options));
SetupOptions(argc, argv, &options);
Start(&options);
[pool release];
return options.result;
}

View file

@ -0,0 +1,466 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 45;
objects = {
/* Begin PBXBuildFile section */
5B6060BD222716FC0015F0A0 /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060BC222716FC0015F0A0 /* HTTPRequest.m */; };
5B6060C02227201B0015F0A0 /* HTTPPutRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */; };
5B6060C7222735E50015F0A0 /* HTTPGetRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */; };
5B6060CA2227374E0015F0A0 /* HTTPSimplePostRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */; };
5B6060D022273BDA0015F0A0 /* SymbolCollectorClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */; };
5B97447524D0AA5F000C71F5 /* encoding_util.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B97447424D0AA5F000C71F5 /* encoding_util.m */; };
8B31022C11F0CEBD00FCF3E4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
8DD76F9A0486AA7600D96B5E /* symupload.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* symupload.mm */; settings = {ATTRIBUTES = (); }; };
8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
930DA19225ED543A008558E3 /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA19025ED543A008558E3 /* dump_syms.cc */; };
930DA22C25ED55A9008558E3 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA21F25ED55A8008558E3 /* module.cc */; };
930DA22D25ED55A9008558E3 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22325ED55A8008558E3 /* dwarf_cfi_to_module.cc */; };
930DA22E25ED55A9008558E3 /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22525ED55A8008558E3 /* stabs_to_module.cc */; };
930DA22F25ED55A9008558E3 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22625ED55A9008558E3 /* language.cc */; };
930DA23125ED55A9008558E3 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22A25ED55A9008558E3 /* dwarf_line_to_module.cc */; };
930DA23225ED55A9008558E3 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22B25ED55A9008558E3 /* dwarf_cu_to_module.cc */; };
930DA23725ED55B6008558E3 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23625ED55B6008558E3 /* stabs_reader.cc */; };
930DA24225ED55BF008558E3 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23A25ED55BF008558E3 /* macho_id.cc */; };
930DA24325ED55BF008558E3 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23C25ED55BF008558E3 /* macho_utilities.cc */; };
930DA24425ED55BF008558E3 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23F25ED55BF008558E3 /* macho_reader.cc */; };
930DA24525ED55BF008558E3 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA24125ED55BF008558E3 /* macho_walker.cc */; };
930DA25C25ED56DB008558E3 /* dwarf_range_list_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA24D25ED56DB008558E3 /* dwarf_range_list_handler.cc */; };
930DA25D25ED56DB008558E3 /* cfi_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA24E25ED56DB008558E3 /* cfi_assembler.cc */; };
930DA25E25ED56DB008558E3 /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25225ED56DB008558E3 /* elf_reader.cc */; };
930DA25F25ED56DB008558E3 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */; };
930DA26025ED56DB008558E3 /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25625ED56DB008558E3 /* dwarf2reader.cc */; };
930DA26125ED56DB008558E3 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25925ED56DB008558E3 /* bytereader.cc */; };
930DA26925ED56FF008558E3 /* test_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA26825ED56FF008558E3 /* test_assembler.cc */; };
930DA26E25ED571F008558E3 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA26D25ED571F008558E3 /* arch_utilities.cc */; };
930DA27825ED572D008558E3 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA27125ED572C008558E3 /* path_helper.cc */; };
930DA27925ED572D008558E3 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA27525ED572C008558E3 /* file_id.cc */; };
930DA27A25ED572D008558E3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA27725ED572D008558E3 /* md5.cc */; };
9BC1D49E0B37427A00F2A2B4 /* minidump_upload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD836000B0544BA0055103E /* minidump_upload.m */; };
9BD8336A0B03E4080055103E /* HTTPMultipartUpload.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */; };
9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */; };
9BD836180B0549F70055103E /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
8DD76F9E0486AA7600D96B5E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
9BD8336A0B03E4080055103E /* HTTPMultipartUpload.h in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
08FB7796FE84155DC02AAC07 /* symupload.mm */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.objcpp; path = symupload.mm; sourceTree = "<group>"; tabWidth = 2; };
08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
5B6060BB222716FC0015F0A0 /* HTTPRequest.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPRequest.h; path = ../../../common/mac/HTTPRequest.h; sourceTree = "<group>"; tabWidth = 2; };
5B6060BC222716FC0015F0A0 /* HTTPRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPRequest.m; path = ../../../common/mac/HTTPRequest.m; sourceTree = "<group>"; tabWidth = 2; };
5B6060BE2227201B0015F0A0 /* HTTPPutRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HTTPPutRequest.h; path = ../../../common/mac/HTTPPutRequest.h; sourceTree = "<group>"; };
5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPPutRequest.m; path = ../../../common/mac/HTTPPutRequest.m; sourceTree = "<group>"; tabWidth = 2; };
5B6060C22227303A0015F0A0 /* encoding_util.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = encoding_util.h; path = ../../../common/mac/encoding_util.h; sourceTree = "<group>"; tabWidth = 2; };
5B6060C5222735E50015F0A0 /* HTTPGetRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HTTPGetRequest.h; path = ../../../common/mac/HTTPGetRequest.h; sourceTree = "<group>"; };
5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = HTTPGetRequest.m; path = ../../../common/mac/HTTPGetRequest.m; sourceTree = "<group>"; };
5B6060C82227374E0015F0A0 /* HTTPSimplePostRequest.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPSimplePostRequest.h; path = ../../../common/mac/HTTPSimplePostRequest.h; sourceTree = "<group>"; tabWidth = 2; };
5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPSimplePostRequest.m; path = ../../../common/mac/HTTPSimplePostRequest.m; sourceTree = "<group>"; tabWidth = 2; };
5B6060CE22273BDA0015F0A0 /* SymbolCollectorClient.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SymbolCollectorClient.h; path = ../../../common/mac/SymbolCollectorClient.h; sourceTree = "<group>"; tabWidth = 2; };
5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = SymbolCollectorClient.m; path = ../../../common/mac/SymbolCollectorClient.m; sourceTree = "<group>"; tabWidth = 2; };
5B97447424D0AA5F000C71F5 /* encoding_util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = encoding_util.m; path = ../../../common/mac/encoding_util.m; sourceTree = "<group>"; };
8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; };
8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; };
8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; };
8DD76FA10486AA7600D96B5E /* symupload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = symupload; sourceTree = BUILT_PRODUCTS_DIR; };
930DA19025ED543A008558E3 /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = "<group>"; };
930DA19125ED543A008558E3 /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = "<group>"; };
930DA21F25ED55A8008558E3 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = "<group>"; };
930DA22025ED55A8008558E3 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = "<group>"; };
930DA22125ED55A8008558E3 /* dwarf_cfi_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cfi_to_module.h; path = ../../../common/dwarf_cfi_to_module.h; sourceTree = "<group>"; };
930DA22225ED55A8008558E3 /* dwarf_cu_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cu_to_module.h; path = ../../../common/dwarf_cu_to_module.h; sourceTree = "<group>"; };
930DA22325ED55A8008558E3 /* dwarf_cfi_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module.cc; path = ../../../common/dwarf_cfi_to_module.cc; sourceTree = "<group>"; };
930DA22425ED55A8008558E3 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = "<group>"; };
930DA22525ED55A8008558E3 /* stabs_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module.cc; path = ../../../common/stabs_to_module.cc; sourceTree = "<group>"; };
930DA22625ED55A9008558E3 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = "<group>"; };
930DA22725ED55A9008558E3 /* dwarf_line_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_line_to_module.h; path = ../../../common/dwarf_line_to_module.h; sourceTree = "<group>"; };
930DA22825ED55A9008558E3 /* stabs_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_to_module.h; path = ../../../common/stabs_to_module.h; sourceTree = "<group>"; };
930DA22A25ED55A9008558E3 /* dwarf_line_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module.cc; path = ../../../common/dwarf_line_to_module.cc; sourceTree = "<group>"; };
930DA22B25ED55A9008558E3 /* dwarf_cu_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module.cc; path = ../../../common/dwarf_cu_to_module.cc; sourceTree = "<group>"; };
930DA23525ED55B6008558E3 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = "<group>"; };
930DA23625ED55B6008558E3 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = "<group>"; };
930DA23A25ED55BF008558E3 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = "<group>"; };
930DA23B25ED55BF008558E3 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = "<group>"; };
930DA23C25ED55BF008558E3 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = "<group>"; };
930DA23D25ED55BF008558E3 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = "<group>"; };
930DA23E25ED55BF008558E3 /* macho_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_reader.h; path = ../../../common/mac/macho_reader.h; sourceTree = "<group>"; };
930DA23F25ED55BF008558E3 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = "<group>"; };
930DA24025ED55BF008558E3 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = "<group>"; };
930DA24125ED55BF008558E3 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = "<group>"; };
930DA24C25ED56DB008558E3 /* line_state_machine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = line_state_machine.h; path = ../../../common/dwarf/line_state_machine.h; sourceTree = "<group>"; };
930DA24D25ED56DB008558E3 /* dwarf_range_list_handler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_range_list_handler.cc; path = ../../../common/dwarf_range_list_handler.cc; sourceTree = "<group>"; };
930DA24E25ED56DB008558E3 /* cfi_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cfi_assembler.cc; path = ../../../common/dwarf/cfi_assembler.cc; sourceTree = "<group>"; };
930DA24F25ED56DB008558E3 /* dwarf2enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2enums.h; path = ../../../common/dwarf/dwarf2enums.h; sourceTree = "<group>"; };
930DA25025ED56DB008558E3 /* bytereader-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "bytereader-inl.h"; path = "../../../common/dwarf/bytereader-inl.h"; sourceTree = "<group>"; };
930DA25125ED56DB008558E3 /* dwarf_range_list_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_range_list_handler.h; path = ../../../common/dwarf_range_list_handler.h; sourceTree = "<group>"; };
930DA25225ED56DB008558E3 /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = "<group>"; };
930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = "<group>"; };
930DA25425ED56DB008558E3 /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = "<group>"; };
930DA25525ED56DB008558E3 /* bytereader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bytereader.h; path = ../../../common/dwarf/bytereader.h; sourceTree = "<group>"; };
930DA25625ED56DB008558E3 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = "<group>"; };
930DA25725ED56DB008558E3 /* dwarf2reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2reader.h; path = ../../../common/dwarf/dwarf2reader.h; sourceTree = "<group>"; };
930DA25825ED56DB008558E3 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = "<group>"; };
930DA25925ED56DB008558E3 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = "<group>"; };
930DA25A25ED56DB008558E3 /* cfi_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cfi_assembler.h; path = ../../../common/dwarf/cfi_assembler.h; sourceTree = "<group>"; };
930DA26725ED56FF008558E3 /* test_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test_assembler.h; path = ../../../common/test_assembler.h; sourceTree = "<group>"; };
930DA26825ED56FF008558E3 /* test_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test_assembler.cc; path = ../../../common/test_assembler.cc; sourceTree = "<group>"; };
930DA26C25ED571F008558E3 /* arch_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = "<group>"; };
930DA26D25ED571F008558E3 /* arch_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = "<group>"; };
930DA27125ED572C008558E3 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = "<group>"; };
930DA27225ED572C008558E3 /* byteswap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byteswap.h; path = ../../../common/mac/byteswap.h; sourceTree = "<group>"; };
930DA27325ED572C008558E3 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = "<group>"; };
930DA27425ED572C008558E3 /* byte_cursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byte_cursor.h; path = ../../../common/byte_cursor.h; sourceTree = "<group>"; };
930DA27525ED572C008558E3 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = "<group>"; };
930DA27625ED572C008558E3 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = "<group>"; };
930DA27725ED572D008558E3 /* md5.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = md5.cc; path = ../../../common/md5.cc; sourceTree = "<group>"; };
9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = "<group>"; tabWidth = 2; };
9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = "<group>"; tabWidth = 2; };
9BD835FB0B0544950055103E /* minidump_upload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = minidump_upload; sourceTree = BUILT_PRODUCTS_DIR; };
9BD836000B0544BA0055103E /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = minidump_upload.m; path = ../../../common/mac/minidump_upload.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8DD76F9B0486AA7600D96B5E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
9BD835F90B0544950055103E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8B31022C11F0CEBD00FCF3E4 /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
08FB7794FE84155DC02AAC07 /* symupload */ = {
isa = PBXGroup;
children = (
930DA21E25ED5586008558E3 /* dump_syms */,
5B6060CE22273BDA0015F0A0 /* SymbolCollectorClient.h */,
5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */,
5B6060C82227374E0015F0A0 /* HTTPSimplePostRequest.h */,
5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */,
5B6060C5222735E50015F0A0 /* HTTPGetRequest.h */,
5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */,
5B6060C22227303A0015F0A0 /* encoding_util.h */,
5B97447424D0AA5F000C71F5 /* encoding_util.m */,
5B6060BE2227201B0015F0A0 /* HTTPPutRequest.h */,
5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */,
5B6060BB222716FC0015F0A0 /* HTTPRequest.h */,
5B6060BC222716FC0015F0A0 /* HTTPRequest.m */,
8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */,
8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */,
8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */,
08FB7796FE84155DC02AAC07 /* symupload.mm */,
9BD836000B0544BA0055103E /* minidump_upload.m */,
9BD833680B03E4080055103E /* HTTPMultipartUpload.h */,
9BD833690B03E4080055103E /* HTTPMultipartUpload.m */,
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
1AB674ADFE9D54B511CA2CBB /* Products */,
);
name = symupload;
sourceTree = "<group>";
};
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
isa = PBXGroup;
children = (
08FB779EFE84155DC02AAC07 /* Foundation.framework */,
);
name = "External Frameworks and Libraries";
sourceTree = "<group>";
};
1AB674ADFE9D54B511CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
8DD76FA10486AA7600D96B5E /* symupload */,
9BD835FB0B0544950055103E /* minidump_upload */,
);
name = Products;
sourceTree = "<group>";
};
930DA21E25ED5586008558E3 /* dump_syms */ = {
isa = PBXGroup;
children = (
930DA23A25ED55BF008558E3 /* macho_id.cc */,
930DA23B25ED55BF008558E3 /* macho_id.h */,
930DA23F25ED55BF008558E3 /* macho_reader.cc */,
930DA23E25ED55BF008558E3 /* macho_reader.h */,
930DA23C25ED55BF008558E3 /* macho_utilities.cc */,
930DA24025ED55BF008558E3 /* macho_utilities.h */,
930DA24125ED55BF008558E3 /* macho_walker.cc */,
930DA23D25ED55BF008558E3 /* macho_walker.h */,
930DA19025ED543A008558E3 /* dump_syms.cc */,
930DA19125ED543A008558E3 /* dump_syms.h */,
930DA23625ED55B6008558E3 /* stabs_reader.cc */,
930DA23525ED55B6008558E3 /* stabs_reader.h */,
930DA22325ED55A8008558E3 /* dwarf_cfi_to_module.cc */,
930DA22125ED55A8008558E3 /* dwarf_cfi_to_module.h */,
930DA22B25ED55A9008558E3 /* dwarf_cu_to_module.cc */,
930DA22225ED55A8008558E3 /* dwarf_cu_to_module.h */,
930DA22A25ED55A9008558E3 /* dwarf_line_to_module.cc */,
930DA22725ED55A9008558E3 /* dwarf_line_to_module.h */,
930DA22625ED55A9008558E3 /* language.cc */,
930DA22425ED55A8008558E3 /* language.h */,
930DA21F25ED55A8008558E3 /* module.cc */,
930DA22025ED55A8008558E3 /* module.h */,
930DA22525ED55A8008558E3 /* stabs_to_module.cc */,
930DA22825ED55A9008558E3 /* stabs_to_module.h */,
930DA25025ED56DB008558E3 /* bytereader-inl.h */,
930DA25925ED56DB008558E3 /* bytereader.cc */,
930DA25525ED56DB008558E3 /* bytereader.h */,
930DA24E25ED56DB008558E3 /* cfi_assembler.cc */,
930DA25A25ED56DB008558E3 /* cfi_assembler.h */,
930DA24D25ED56DB008558E3 /* dwarf_range_list_handler.cc */,
930DA25125ED56DB008558E3 /* dwarf_range_list_handler.h */,
930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */,
930DA25825ED56DB008558E3 /* dwarf2diehandler.h */,
930DA24F25ED56DB008558E3 /* dwarf2enums.h */,
930DA25625ED56DB008558E3 /* dwarf2reader.cc */,
930DA25725ED56DB008558E3 /* dwarf2reader.h */,
930DA25225ED56DB008558E3 /* elf_reader.cc */,
930DA25425ED56DB008558E3 /* elf_reader.h */,
930DA24C25ED56DB008558E3 /* line_state_machine.h */,
930DA26825ED56FF008558E3 /* test_assembler.cc */,
930DA26725ED56FF008558E3 /* test_assembler.h */,
930DA26D25ED571F008558E3 /* arch_utilities.cc */,
930DA26C25ED571F008558E3 /* arch_utilities.h */,
930DA27425ED572C008558E3 /* byte_cursor.h */,
930DA27225ED572C008558E3 /* byteswap.h */,
930DA27525ED572C008558E3 /* file_id.cc */,
930DA27625ED572C008558E3 /* file_id.h */,
930DA27725ED572D008558E3 /* md5.cc */,
930DA27125ED572C008558E3 /* path_helper.cc */,
930DA27325ED572C008558E3 /* path_helper.h */,
);
name = dump_syms;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
8DD76F960486AA7600D96B5E /* symupload */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "symupload" */;
buildPhases = (
8DD76F990486AA7600D96B5E /* Sources */,
8DD76F9B0486AA7600D96B5E /* Frameworks */,
8DD76F9E0486AA7600D96B5E /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = symupload;
productInstallPath = "$(HOME)/bin";
productName = symupload;
productReference = 8DD76FA10486AA7600D96B5E /* symupload */;
productType = "com.apple.product-type.tool";
};
9BD835FA0B0544950055103E /* minidump_upload */ = {
isa = PBXNativeTarget;
buildConfigurationList = 9BD836020B0544BB0055103E /* Build configuration list for PBXNativeTarget "minidump_upload" */;
buildPhases = (
9BD835F80B0544950055103E /* Sources */,
9BD835F90B0544950055103E /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = minidump_upload;
productName = minidump_upload;
productReference = 9BD835FB0B0544950055103E /* minidump_upload */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
};
buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "symupload" */;
compatibilityVersion = "Xcode 3.1";
developmentRegion = en;
hasScannedForEncodings = 1;
knownRegions = (
en,
);
mainGroup = 08FB7794FE84155DC02AAC07 /* symupload */;
projectDirPath = "";
projectRoot = "";
targets = (
8DD76F960486AA7600D96B5E /* symupload */,
9BD835FA0B0544950055103E /* minidump_upload */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
8DD76F990486AA7600D96B5E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8DD76F9A0486AA7600D96B5E /* symupload.mm in Sources */,
930DA19225ED543A008558E3 /* dump_syms.cc in Sources */,
930DA24525ED55BF008558E3 /* macho_walker.cc in Sources */,
930DA22E25ED55A9008558E3 /* stabs_to_module.cc in Sources */,
5B6060CA2227374E0015F0A0 /* HTTPSimplePostRequest.m in Sources */,
930DA25F25ED56DB008558E3 /* dwarf2diehandler.cc in Sources */,
930DA27825ED572D008558E3 /* path_helper.cc in Sources */,
930DA27A25ED572D008558E3 /* md5.cc in Sources */,
930DA22D25ED55A9008558E3 /* dwarf_cfi_to_module.cc in Sources */,
930DA24425ED55BF008558E3 /* macho_reader.cc in Sources */,
930DA24325ED55BF008558E3 /* macho_utilities.cc in Sources */,
5B6060D022273BDA0015F0A0 /* SymbolCollectorClient.m in Sources */,
5B6060C7222735E50015F0A0 /* HTTPGetRequest.m in Sources */,
930DA27925ED572D008558E3 /* file_id.cc in Sources */,
930DA26925ED56FF008558E3 /* test_assembler.cc in Sources */,
930DA22F25ED55A9008558E3 /* language.cc in Sources */,
930DA25E25ED56DB008558E3 /* elf_reader.cc in Sources */,
930DA26E25ED571F008558E3 /* arch_utilities.cc in Sources */,
930DA24225ED55BF008558E3 /* macho_id.cc in Sources */,
5B6060C02227201B0015F0A0 /* HTTPPutRequest.m in Sources */,
930DA25C25ED56DB008558E3 /* dwarf_range_list_handler.cc in Sources */,
5B6060BD222716FC0015F0A0 /* HTTPRequest.m in Sources */,
930DA25D25ED56DB008558E3 /* cfi_assembler.cc in Sources */,
930DA23225ED55A9008558E3 /* dwarf_cu_to_module.cc in Sources */,
930DA23125ED55A9008558E3 /* dwarf_line_to_module.cc in Sources */,
930DA26125ED56DB008558E3 /* bytereader.cc in Sources */,
930DA22C25ED55A9008558E3 /* module.cc in Sources */,
5B97447524D0AA5F000C71F5 /* encoding_util.m in Sources */,
930DA23725ED55B6008558E3 /* stabs_reader.cc in Sources */,
9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */,
930DA26025ED56DB008558E3 /* dwarf2reader.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
9BD835F80B0544950055103E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9BD836180B0549F70055103E /* HTTPMultipartUpload.m in Sources */,
9BC1D49E0B37427A00F2A2B4 /* minidump_upload.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
1DEB927508733DD40010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H;
HEADER_SEARCH_PATHS = (
../../..,
../../../common/mac/include,
../../../third_party/musl/include/,
);
PRODUCT_NAME = symupload;
};
name = Debug;
};
1DEB927608733DD40010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
NDEBUG,
HAVE_MACH_O_NLIST_H,
);
HEADER_SEARCH_PATHS = (
../../..,
../../../common/mac/include,
../../../third_party/musl/include/,
);
PRODUCT_NAME = symupload;
};
name = Release;
};
1DEB927908733DD40010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */;
buildSettings = {
};
name = Debug;
};
1DEB927A08733DD40010E9CD /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */;
buildSettings = {
};
name = Release;
};
9BD836030B0544BB0055103E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = ../../..;
PRODUCT_NAME = minidump_upload;
};
name = Debug;
};
9BD836040B0544BB0055103E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = ../../..;
PRODUCT_NAME = minidump_upload;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "symupload" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB927508733DD40010E9CD /* Debug */,
1DEB927608733DD40010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "symupload" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB927908733DD40010E9CD /* Debug */,
1DEB927A08733DD40010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
9BD836020B0544BB0055103E /* Build configuration list for PBXNativeTarget "minidump_upload" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9BD836030B0544BB0055103E /* Debug */,
9BD836040B0544BB0055103E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
}

View file

@ -0,0 +1,66 @@
/* Copyright 2014 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.
*/
#include <mach-o/arch.h>
#include <mach-o/loader.h>
#include <mach/machine.h>
// Go/Cgo does not support #define constants, so turn them into symbols
// that are reachable from Go.
#ifndef CPU_TYPE_ARM64
#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
#endif
#ifndef CPU_SUBTYPE_ARM64_ALL
#define CPU_SUBTYPE_ARM64_ALL 0
#endif
#ifndef CPU_SUBTYPE_ARM64_E
#define CPU_SUBTYPE_ARM64_E 2
#endif
const cpu_type_t kCPU_TYPE_ARM = CPU_TYPE_ARM;
const cpu_type_t kCPU_TYPE_ARM64 = CPU_TYPE_ARM64;
const cpu_subtype_t kCPU_SUBTYPE_ARM64_ALL = CPU_SUBTYPE_ARM64_ALL;
const cpu_subtype_t kCPU_SUBTYPE_ARM64_E = CPU_SUBTYPE_ARM64_E;
const cpu_subtype_t kCPU_SUBTYPE_ARM_V7S = CPU_SUBTYPE_ARM_V7S;
const char* GetNXArchInfoName(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
const NXArchInfo* arch_info = NXGetArchInfoFromCpuType(cpu_type, cpu_subtype);
if (!arch_info)
return 0;
return arch_info->name;
}
const uint32_t kMachHeaderFtypeDylib = MH_DYLIB;
const uint32_t kMachHeaderFtypeBundle = MH_BUNDLE;
const uint32_t kMachHeaderFtypeExe = MH_EXECUTE;
const uint32_t kMachHeaderFtypeDylinker = MH_DYLINKER;

View file

@ -0,0 +1,68 @@
/* Copyright 2014 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.
*/
package main
import (
"debug/macho"
)
/*
#include "arch_constants.h"
*/
import "C"
// getArchStringFromHeader takes a MachO FileHeader and returns a string that
// represents the CPU type and subtype.
// This function is a Go version of src/common/mac/arch_utilities.cc:BreakpadGetArchInfoFromCpuType().
func getArchStringFromHeader(header macho.FileHeader) string {
// TODO(rsesek): As of 10.9.4, OS X doesn't list these in /usr/include/mach/machine.h.
if header.Cpu == C.kCPU_TYPE_ARM64 && header.SubCpu == C.kCPU_SUBTYPE_ARM64_ALL {
return "arm64"
}
if header.Cpu == C.kCPU_TYPE_ARM64 && header.SubCpu == C.kCPU_SUBTYPE_ARM64_E {
return "arm64e"
}
if header.Cpu == C.kCPU_TYPE_ARM && header.SubCpu == C.kCPU_SUBTYPE_ARM_V7S {
return "armv7s"
}
cstr := C.GetNXArchInfoName(C.cpu_type_t(header.Cpu), C.cpu_subtype_t(header.SubCpu))
if cstr == nil {
return ""
}
return C.GoString(cstr)
}
const (
MachODylib macho.Type = C.kMachHeaderFtypeDylib
MachOBundle = C.kMachHeaderFtypeBundle
MachOExe = C.kMachHeaderFtypeExe
MachODylinker = C.kMachHeaderFtypeDylinker
)

View file

@ -0,0 +1,3 @@
module upload_system_symbols
go 1.17

View file

@ -0,0 +1,484 @@
/* Copyright 2014 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.
*/
/*
Tool upload_system_symbols generates and uploads Breakpad symbol files for OS X system libraries.
This tool shells out to the dump_syms and symupload Breakpad tools. In its default mode, this
will find all dynamic libraries on the system, run dump_syms to create the Breakpad symbol files,
and then upload them to Google's crash infrastructure.
The tool can also be used to only dump libraries or upload from a directory. See -help for more
information.
Both i386 and x86_64 architectures will be dumped and uploaded.
*/
package main
import (
"debug/macho"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
"regexp"
"strings"
"sync"
"time"
)
var (
breakpadTools = flag.String("breakpad-tools", "out/Release/", "Path to the Breakpad tools directory, containing dump_syms and symupload.")
uploadOnlyPath = flag.String("upload-from", "", "Upload a directory of symbol files that has been dumped independently.")
dumpOnlyPath = flag.String("dump-to", "", "Dump the symbols to the specified directory, but do not upload them.")
systemRoot = flag.String("system-root", "", "Path to the root of the Mac OS X system whose symbols will be dumped.")
dumpArchitecture = flag.String("arch", "", "The CPU architecture for which symbols should be dumped. If not specified, dumps all architectures.")
apiKey = flag.String("api-key", "", "API key to use. If this is present, the `sym-upload-v2` protocol is used.\nSee https://chromium.googlesource.com/breakpad/breakpad/+/HEAD/docs/sym_upload_v2_protocol.md or\n`symupload`'s help for more information.")
)
var (
// pathsToScan are the subpaths in the systemRoot that should be scanned for shared libraries.
pathsToScan = []string{
"/System/Library/Frameworks",
"/System/Library/PrivateFrameworks",
"/usr/lib",
}
// optionalPathsToScan is just like pathsToScan, but the paths are permitted to be absent.
optionalPathsToScan = []string{
// Gone in 10.15.
"/Library/QuickTime",
// Not present in dumped dyld_shared_caches
"/System/Library/Components",
}
// uploadServersV1 are the list of servers to which symbols should be
// uploaded when using the V1 protocol.
uploadServersV1 = []string{
"https://clients2.google.com/cr/symbol",
"https://clients2.google.com/cr/staging_symbol",
}
// uploadServersV2 are the list of servers to which symbols should be
// uploaded when using the V2 protocol.
uploadServersV2 = []string{
"https://staging-crashsymbolcollector-pa.googleapis.com",
"https://prod-crashsymbolcollector-pa.googleapis.com",
}
// uploadServers are the list of servers that should be used, accounting
// for whether v1 or v2 protocol is used.
uploadServers = uploadServersV1
// blacklistRegexps match paths that should be excluded from dumping.
blacklistRegexps = []*regexp.Regexp{
regexp.MustCompile(`/System/Library/Frameworks/Python\.framework/`),
regexp.MustCompile(`/System/Library/Frameworks/Ruby\.framework/`),
regexp.MustCompile(`_profile\.dylib$`),
regexp.MustCompile(`_debug\.dylib$`),
regexp.MustCompile(`\.a$`),
regexp.MustCompile(`\.dat$`),
}
)
func main() {
flag.Parse()
log.SetFlags(0)
// If `apiKey` is set, we're using the v2 protocol.
if len(*apiKey) > 0 {
uploadServers = uploadServersV2
}
var uq *UploadQueue
if *uploadOnlyPath != "" {
// -upload-from specified, so handle that case early.
uq = StartUploadQueue()
uploadFromDirectory(*uploadOnlyPath, uq)
uq.Wait()
return
}
if *systemRoot == "" {
log.Fatal("Need a -system-root to dump symbols for")
}
if *dumpOnlyPath != "" {
// -dump-to specified, so make sure that the path is a directory.
if fi, err := os.Stat(*dumpOnlyPath); err != nil {
log.Fatalf("-dump-to location: %v", err)
} else if !fi.IsDir() {
log.Fatal("-dump-to location is not a directory")
}
}
dumpPath := *dumpOnlyPath
if *dumpOnlyPath == "" {
// If -dump-to was not specified, then run the upload pipeline and create
// a temporary dump output directory.
uq = StartUploadQueue()
if p, err := ioutil.TempDir("", "upload_system_symbols"); err != nil {
log.Fatalf("Failed to create temporary directory: %v", err)
} else {
dumpPath = p
defer os.RemoveAll(p)
}
}
dq := StartDumpQueue(*systemRoot, dumpPath, uq)
dq.Wait()
if uq != nil {
uq.Wait()
}
}
// 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
}
// StartWorkerPool will launch numWorkers goroutines all running workerFunc.
// When workerFunc exits, the goroutine will terminate.
func StartWorkerPool(numWorkers int, workerFunc func()) *WorkerPool {
p := new(WorkerPool)
for i := 0; i < numWorkers; i++ {
p.wg.Add(1)
go func() {
workerFunc()
p.wg.Done()
}()
}
return p
}
// Wait for all the workers in the pool to complete the workerFunc.
func (p *WorkerPool) Wait() {
p.wg.Wait()
}
type UploadQueue struct {
*WorkerPool
queue chan string
}
// StartUploadQueue creates a new worker pool and queue, to which paths to
// Breakpad symbol files may be sent for uploading.
func StartUploadQueue() *UploadQueue {
uq := &UploadQueue{
queue: make(chan string, 10),
}
uq.WorkerPool = StartWorkerPool(5, uq.worker)
return uq
}
// Upload enqueues the contents of filepath to be uploaded.
func (uq *UploadQueue) Upload(filepath string) {
uq.queue <- filepath
}
// Done tells the queue that no more files need to be uploaded. This must be
// called before WorkerPool.Wait.
func (uq *UploadQueue) Done() {
close(uq.queue)
}
func (uq *UploadQueue) runSymUpload(symfile, server string) *exec.Cmd {
symUpload := path.Join(*breakpadTools, "symupload")
args := []string{symfile, server}
if len(*apiKey) > 0 {
args = append([]string{"-p", "sym-upload-v2", "-k", *apiKey}, args...)
}
return exec.Command(symUpload, args...)
}
func (uq *UploadQueue) worker() {
for symfile := range uq.queue {
for _, server := range uploadServers {
for i := 0; i < 3; i++ { // Give each upload 3 attempts to succeed.
cmd := uq.runSymUpload(symfile, server)
if output, err := cmd.Output(); err == nil {
// Success. No retry needed.
fmt.Printf("Uploaded %s to %s\n", symfile, server)
break
} else if exitError, ok := err.(*exec.ExitError); ok && exitError.ExitCode() == 2 && *apiKey != "" {
// Exit code 2 in protocol v2 means the file already exists on the server.
// No point retrying.
fmt.Printf("File %s already exists on %s\n", symfile, server)
break
} else {
log.Printf("Error running symupload(%s, %s), attempt %d: %v: %s\n", symfile, server, i, err, output)
time.Sleep(1 * time.Second)
}
}
}
}
}
type DumpQueue struct {
*WorkerPool
dumpPath string
queue chan dumpRequest
uq *UploadQueue
}
type dumpRequest struct {
path string
arch string
}
// StartDumpQueue creates a new worker pool to find all the Mach-O libraries in
// root and dump their symbols to dumpPath. If an UploadQueue is passed, the
// path to the symbol file will be enqueued there, too.
func StartDumpQueue(root, dumpPath string, uq *UploadQueue) *DumpQueue {
dq := &DumpQueue{
dumpPath: dumpPath,
queue: make(chan dumpRequest),
uq: uq,
}
dq.WorkerPool = StartWorkerPool(12, dq.worker)
findLibsInRoot(root, dq)
return dq
}
// DumpSymbols enqueues the filepath to have its symbols dumped in the specified
// architecture.
func (dq *DumpQueue) DumpSymbols(filepath string, arch string) {
dq.queue <- dumpRequest{
path: filepath,
arch: arch,
}
}
func (dq *DumpQueue) Wait() {
dq.WorkerPool.Wait()
if dq.uq != nil {
dq.uq.Done()
}
}
func (dq *DumpQueue) done() {
close(dq.queue)
}
func (dq *DumpQueue) worker() {
dumpSyms := path.Join(*breakpadTools, "dump_syms")
for req := range dq.queue {
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 {
log.Fatalf("Error creating symbol file: %v", err)
}
cmd := exec.Command(dumpSyms, "-a", req.arch, req.path)
cmd.Stdout = f
err = cmd.Run()
f.Close()
if err != nil {
os.Remove(symfile)
log.Printf("Error running dump_syms(%s, %s): %v\n", req.arch, req.path, err)
} else if dq.uq != nil {
dq.uq.Upload(symfile)
}
}
}
// uploadFromDirectory handles the upload-only case and merely uploads all files in
// a directory.
func uploadFromDirectory(directory string, uq *UploadQueue) {
d, err := os.Open(directory)
if err != nil {
log.Fatalf("Could not open directory to upload: %v", err)
}
defer d.Close()
entries, err := d.Readdirnames(0)
if err != nil {
log.Fatalf("Could not read directory: %v", err)
}
for _, entry := range entries {
uq.Upload(path.Join(directory, entry))
}
uq.Done()
}
// findQueue is an implementation detail of the DumpQueue that finds all the
// Mach-O files and their architectures.
type findQueue struct {
*WorkerPool
queue chan string
dq *DumpQueue
}
// findLibsInRoot looks in all the pathsToScan in the root and manages the
// interaction between findQueue and DumpQueue.
func findLibsInRoot(root string, dq *DumpQueue) {
fq := &findQueue{
queue: make(chan string, 10),
dq: dq,
}
fq.WorkerPool = StartWorkerPool(12, fq.worker)
for _, p := range pathsToScan {
fq.findLibsInPath(path.Join(root, p), true)
}
for _, p := range optionalPathsToScan {
fq.findLibsInPath(path.Join(root, p), false)
}
close(fq.queue)
fq.Wait()
dq.done()
}
// findLibsInPath recursively walks the directory tree, sending file paths to
// test for being Mach-O to the findQueue.
func (fq *findQueue) findLibsInPath(loc string, mustExist bool) {
d, err := os.Open(loc)
if err != nil {
if !mustExist && os.IsNotExist(err) {
return
}
log.Fatalf("Could not open %s: %v", loc, err)
}
defer d.Close()
for {
fis, err := d.Readdir(100)
if err != nil && err != io.EOF {
log.Fatalf("Error reading directory %s: %v", loc, err)
}
for _, fi := range fis {
fp := path.Join(loc, fi.Name())
if fi.IsDir() {
fq.findLibsInPath(fp, true)
continue
} else if fi.Mode()&os.ModeSymlink != 0 {
continue
}
// Test the blacklist in the worker to not slow down this main loop.
fq.queue <- fp
}
if err == io.EOF {
break
}
}
}
func (fq *findQueue) worker() {
for fp := range fq.queue {
blacklisted := false
for _, re := range blacklistRegexps {
blacklisted = blacklisted || re.MatchString(fp)
}
if blacklisted {
continue
}
f, err := os.Open(fp)
if err != nil {
log.Printf("%s: %v", fp, err)
continue
}
fatFile, err := macho.NewFatFile(f)
if err == nil {
// The file is fat, so dump its architectures.
for _, fatArch := range fatFile.Arches {
fq.dumpMachOFile(fp, fatArch.File)
}
fatFile.Close()
} else if err == macho.ErrNotFat {
// The file isn't fat but may still be MachO.
thinFile, err := macho.NewFile(f)
if err != nil {
log.Printf("%s: %v", fp, err)
continue
}
fq.dumpMachOFile(fp, thinFile)
thinFile.Close()
} else {
f.Close()
}
}
}
func (fq *findQueue) dumpMachOFile(fp string, image *macho.File) {
if image.Type != MachODylib && image.Type != MachOBundle && image.Type != MachODylinker {
return
}
arch := getArchStringFromHeader(image.FileHeader)
if arch == "" {
// Don't know about this architecture type.
return
}
if (*dumpArchitecture != "" && *dumpArchitecture == arch) || *dumpArchitecture == "" {
fq.dq.DumpSymbols(fp, arch)
}
}

View file

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