From 9c38ab7c67e5b199e6b7ffafa27b7f463f06dedd Mon Sep 17 00:00:00 2001 From: Nelson Billing Date: Fri, 14 Aug 2020 18:32:45 -0700 Subject: Add native symbol uploads to Mac OS symupload tool. - sym-upload-v2 protocol only. - Supports elf, dwp, debug_only, macho, dsym, pe, and pdb (with the classic mode being called 'breakpad'). Change-Id: I68c0065aec3a7ffe29b364dd9e2e1dbdb58e3e5d Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2357528 Reviewed-by: Mark Mentovai --- src/common/mac/SymbolCollectorClient.h | 3 +- src/common/mac/SymbolCollectorClient.m | 12 +-- src/tools/mac/symupload/symupload.m | 142 +++++++++++++++++++++++++++------ 3 files changed, 127 insertions(+), 30 deletions(-) diff --git a/src/common/mac/SymbolCollectorClient.h b/src/common/mac/SymbolCollectorClient.h index 1f27f23f..9e955c8e 100644 --- a/src/common/mac/SymbolCollectorClient.h +++ b/src/common/mac/SymbolCollectorClient.h @@ -95,7 +95,8 @@ typedef NS_ENUM(NSInteger, SymbolStatus) { withAPIKey:(NSString*)APIKey withUploadKey:(NSString*)uploadKey withDebugFile:(NSString*)debugFile - withDebugID:(NSString*)debugID; + withDebugID:(NSString*)debugID + withType:(NSString*)type; @end diff --git a/src/common/mac/SymbolCollectorClient.m b/src/common/mac/SymbolCollectorClient.m index f7cd9235..b135cdeb 100644 --- a/src/common/mac/SymbolCollectorClient.m +++ b/src/common/mac/SymbolCollectorClient.m @@ -77,9 +77,9 @@ [allowedDebugFileCharacters formUnionWithCharacterSet:[NSCharacterSet controlCharacterSet]]; [allowedDebugFileCharacters invert]; - NSString* escapedDebugFile = [debugFile - stringByAddingPercentEncodingWithAllowedCharacters: - allowedDebugFileCharacters]; + NSString* escapedDebugFile = + [debugFile stringByAddingPercentEncodingWithAllowedCharacters: + allowedDebugFileCharacters]; NSURL* URL = [NSURL URLWithString:[NSString @@ -189,7 +189,8 @@ withAPIKey:(NSString*)APIKey withUploadKey:(NSString*)uploadKey withDebugFile:(NSString*)debugFile - withDebugID:(NSString*)debugID { + withDebugID:(NSString*)debugID + withType:(NSString*)type { NSURL* URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/v1/uploads/%@:complete?key=%@", @@ -199,7 +200,8 @@ [NSDictionary dictionaryWithObjectsAndKeys:debugFile, @"debug_file", debugID, @"debug_id", nil]; NSDictionary* jsonDictionary = [NSDictionary - dictionaryWithObjectsAndKeys:symbolIdDictionary, @"symbol_id", nil]; + dictionaryWithObjectsAndKeys:symbolIdDictionary, @"symbol_id", type, + @"symbol_upload_type", nil]; NSError* error; NSData* jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary diff --git a/src/tools/mac/symupload/symupload.m b/src/tools/mac/symupload/symupload.m index 2c663fe1..61c2450d 100644 --- a/src/tools/mac/symupload/symupload.m +++ b/src/tools/mac/symupload/symupload.m @@ -48,6 +48,8 @@ #include "HTTPPutRequest.h" #include "SymbolCollectorClient.h" +NSString* const kBreakpadSymbolType = @"BREAKPAD"; + typedef enum { kSymUploadProtocolV1, kSymUploadProtocolV2 } SymUploadProtocol; typedef enum { @@ -63,6 +65,9 @@ typedef struct { NSString* apiKey; BOOL force; Result result; + NSString* type; + NSString* codeFile; + NSString* debugID; } Options; //============================================================================= @@ -100,21 +105,20 @@ static NSArray* ModuleDataForSymbolFile(NSString* file) { //============================================================================= static void StartSymUploadProtocolV1(Options* options, - NSArray* moduleParts, - NSString* compactedID) { + 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:compactedID forKey:@"debug_identifier"]; - - // MODULE - // 0 1 2 3 4 - [parameters setObject:[moduleParts objectAtIndex:1] forKey:@"os"]; - [parameters setObject:[moduleParts objectAtIndex:2] forKey:@"cpu"]; - [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"debug_file"]; - [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"code_file"]; + [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]; @@ -148,12 +152,13 @@ static void StartSymUploadProtocolV1(Options* options, //============================================================================= static void StartSymUploadProtocolV2(Options* options, - NSArray* moduleParts, - NSString* debugID) { + NSString* debugID, + NSString* debugFile) { options->result = kResultFailure; - NSString* debugFile = [moduleParts objectAtIndex:4]; - if (!options->force) { + // 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 @@ -201,7 +206,8 @@ static void StartSymUploadProtocolV2(Options* options, withAPIKey:options->apiKey withUploadKey:[URLResponse uploadKey] withDebugFile:debugFile - withDebugID:debugID]; + withDebugID:debugID + withType:options->type]; [URLResponse release]; if (completeUploadResult == CompleteUploadResultError) { fprintf(stdout, "Failed to complete upload.\n"); @@ -217,18 +223,29 @@ static void StartSymUploadProtocolV2(Options* options, //============================================================================= 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); - NSMutableString* compactedID = + // MODULE + // 0 1 2 3 4 + NSString* OS = [moduleParts objectAtIndex:1]; + NSString* CPU = [moduleParts objectAtIndex:2]; + NSMutableString* debugID = [NSMutableString stringWithString:[moduleParts objectAtIndex:3]]; - [compactedID replaceOccurrencesOfString:@"-" - withString:@"" - options:0 - range:NSMakeRange(0, [compactedID length])]; + [debugID replaceOccurrencesOfString:@"-" + withString:@"" + options:0 + range:NSMakeRange(0, [debugID length])]; + NSString* debugFile = [moduleParts objectAtIndex:4]; if (options->symUploadProtocol == kSymUploadProtocolV1) { - StartSymUploadProtocolV1(options, moduleParts, compactedID); + StartSymUploadProtocolV1(options, OS, CPU, debugID, debugFile); } else if (options->symUploadProtocol == kSymUploadProtocolV2) { - StartSymUploadProtocolV2(options, moduleParts, compactedID); + StartSymUploadProtocolV2(options, debugID, debugFile); } } @@ -247,8 +264,21 @@ static void Usage(int argc, const char* argv[]) { "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 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, "-c:\t Explicitly set 'code_file' for symbol " + "upload (basename of executable).\n"); + fprintf(stderr, "-i:\t Explicitly set 'debug_id' for symbol " + "upload (typically build ID of executable).\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); @@ -264,17 +294,39 @@ static void Usage(int argc, const char* argv[]) { "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 value of symUploadProtocol. + // Set default options values. options->symUploadProtocol = kSymUploadProtocolV1; + options->apiKey = nil; + options->type = kBreakpadSymbolType; + options->codeFile = nil; + options->debugID = nil; + options->force = NO; extern int optind; char ch; - while ((ch = getopt(argc, (char* const*)argv, "p:k:hf?")) != -1) { + while ((ch = getopt(argc, (char* const*)argv, "p:k:t:c:i:hf?")) != -1) { switch (ch) { case 'p': if (strcmp(optarg, "sym-upload-v2") == 0) { @@ -292,6 +344,24 @@ static void SetupOptions(int argc, const char* argv[], Options* options) { 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 'f': options->force = YES; break; @@ -327,6 +397,30 @@ static void SetupOptions(int argc, const char* argv[], Options* options) { 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)) { + 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]]; } -- cgit v1.2.1