1*9712c20fSFrederick Mayle// Copyright 2006 Google LLC 2*9712c20fSFrederick Mayle// 3*9712c20fSFrederick Mayle// Redistribution and use in source and binary forms, with or without 4*9712c20fSFrederick Mayle// modification, are permitted provided that the following conditions are 5*9712c20fSFrederick Mayle// met: 6*9712c20fSFrederick Mayle// 7*9712c20fSFrederick Mayle// * Redistributions of source code must retain the above copyright 8*9712c20fSFrederick Mayle// notice, this list of conditions and the following disclaimer. 9*9712c20fSFrederick Mayle// * Redistributions in binary form must reproduce the above 10*9712c20fSFrederick Mayle// copyright notice, this list of conditions and the following disclaimer 11*9712c20fSFrederick Mayle// in the documentation and/or other materials provided with the 12*9712c20fSFrederick Mayle// distribution. 13*9712c20fSFrederick Mayle// * Neither the name of Google LLC nor the names of its 14*9712c20fSFrederick Mayle// contributors may be used to endorse or promote products derived from 15*9712c20fSFrederick Mayle// this software without specific prior written permission. 16*9712c20fSFrederick Mayle// 17*9712c20fSFrederick Mayle// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18*9712c20fSFrederick Mayle// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19*9712c20fSFrederick Mayle// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20*9712c20fSFrederick Mayle// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21*9712c20fSFrederick Mayle// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22*9712c20fSFrederick Mayle// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23*9712c20fSFrederick Mayle// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24*9712c20fSFrederick Mayle// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25*9712c20fSFrederick Mayle// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26*9712c20fSFrederick Mayle// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27*9712c20fSFrederick Mayle// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28*9712c20fSFrederick Mayle 29*9712c20fSFrederick Mayle// symupload.mm: Upload a symbol file to a HTTP server. The upload is sent as 30*9712c20fSFrederick Mayle// a multipart/form-data POST request with the following parameters: 31*9712c20fSFrederick Mayle// code_file: the basename of the module, e.g. "app" 32*9712c20fSFrederick Mayle// debug_file: the basename of the debugging file, e.g. "app" 33*9712c20fSFrederick Mayle// debug_identifier: the debug file's identifier, usually consisting of 34*9712c20fSFrederick Mayle// the guid and age embedded in the pdb, e.g. 35*9712c20fSFrederick Mayle// "11111111BBBB3333DDDD555555555555F" 36*9712c20fSFrederick Mayle// os: the operating system that the module was built for 37*9712c20fSFrederick Mayle// cpu: the CPU that the module was built for (x86 or ppc) 38*9712c20fSFrederick Mayle// symbol_file: the contents of the breakpad-format symbol file 39*9712c20fSFrederick Mayle 40*9712c20fSFrederick Mayle#include <fcntl.h> 41*9712c20fSFrederick Mayle#include <sys/stat.h> 42*9712c20fSFrederick Mayle#include <unistd.h> 43*9712c20fSFrederick Mayle 44*9712c20fSFrederick Mayle#include <Foundation/Foundation.h> 45*9712c20fSFrederick Mayle 46*9712c20fSFrederick Mayle#include "HTTPMultipartUpload.h" 47*9712c20fSFrederick Mayle#include "HTTPPutRequest.h" 48*9712c20fSFrederick Mayle#include "SymbolCollectorClient.h" 49*9712c20fSFrederick Mayle#include "common/mac/dump_syms.h" 50*9712c20fSFrederick Mayle 51*9712c20fSFrederick Mayleusing google_breakpad::DumpSymbols; 52*9712c20fSFrederick Mayle 53*9712c20fSFrederick MayleNSString* const kBreakpadSymbolType = @"BREAKPAD"; 54*9712c20fSFrederick MayleNSString* const kMachOSymbolType = @"MACHO"; 55*9712c20fSFrederick MayleNSString* const kDSYMSymbolType = @"DSYM"; 56*9712c20fSFrederick Mayle 57*9712c20fSFrederick Mayletypedef enum { kSymUploadProtocolV1, kSymUploadProtocolV2 } SymUploadProtocol; 58*9712c20fSFrederick Mayle 59*9712c20fSFrederick Mayletypedef enum { 60*9712c20fSFrederick Mayle kResultSuccess = 0, 61*9712c20fSFrederick Mayle kResultFailure = 1, 62*9712c20fSFrederick Mayle kResultAlreadyExists = 2 63*9712c20fSFrederick Mayle} Result; 64*9712c20fSFrederick Mayle 65*9712c20fSFrederick Mayletypedef struct { 66*9712c20fSFrederick Mayle NSString* symbolsPath; 67*9712c20fSFrederick Mayle NSString* uploadURLStr; 68*9712c20fSFrederick Mayle SymUploadProtocol symUploadProtocol; 69*9712c20fSFrederick Mayle NSString* apiKey; 70*9712c20fSFrederick Mayle BOOL force; 71*9712c20fSFrederick Mayle Result result; 72*9712c20fSFrederick Mayle NSString* type; 73*9712c20fSFrederick Mayle NSString* codeFile; 74*9712c20fSFrederick Mayle NSString* debugID; 75*9712c20fSFrederick Mayle NSString* productName; 76*9712c20fSFrederick Mayle} Options; 77*9712c20fSFrederick Mayle 78*9712c20fSFrederick Mayle//============================================================================= 79*9712c20fSFrederick Maylestatic NSArray* ModuleDataForSymbolFile(NSString* file) { 80*9712c20fSFrederick Mayle NSFileHandle* fh = [NSFileHandle fileHandleForReadingAtPath:file]; 81*9712c20fSFrederick Mayle NSData* data = [fh readDataOfLength:1024]; 82*9712c20fSFrederick Mayle NSString* str = [[NSString alloc] initWithData:data 83*9712c20fSFrederick Mayle encoding:NSUTF8StringEncoding]; 84*9712c20fSFrederick Mayle NSScanner* scanner = [NSScanner scannerWithString:str]; 85*9712c20fSFrederick Mayle NSString* line; 86*9712c20fSFrederick Mayle NSMutableArray* parts = nil; 87*9712c20fSFrederick Mayle const int MODULE_ID_INDEX = 3; 88*9712c20fSFrederick Mayle 89*9712c20fSFrederick Mayle if ([scanner scanUpToString:@"\n" intoString:&line]) { 90*9712c20fSFrederick Mayle parts = [[NSMutableArray alloc] init]; 91*9712c20fSFrederick Mayle NSScanner* moduleInfoScanner = [NSScanner scannerWithString:line]; 92*9712c20fSFrederick Mayle NSString* moduleInfo; 93*9712c20fSFrederick Mayle // Get everything BEFORE the module name. None of these properties 94*9712c20fSFrederick Mayle // can have spaces. 95*9712c20fSFrederick Mayle for (int i = 0; i <= MODULE_ID_INDEX; i++) { 96*9712c20fSFrederick Mayle [moduleInfoScanner scanUpToString:@" " intoString:&moduleInfo]; 97*9712c20fSFrederick Mayle [parts addObject:moduleInfo]; 98*9712c20fSFrederick Mayle } 99*9712c20fSFrederick Mayle 100*9712c20fSFrederick Mayle // Now get the module name. This can have a space so we scan to 101*9712c20fSFrederick Mayle // the end of the line. 102*9712c20fSFrederick Mayle [moduleInfoScanner scanUpToString:@"\n" intoString:&moduleInfo]; 103*9712c20fSFrederick Mayle [parts addObject:moduleInfo]; 104*9712c20fSFrederick Mayle } 105*9712c20fSFrederick Mayle 106*9712c20fSFrederick Mayle [str release]; 107*9712c20fSFrederick Mayle 108*9712c20fSFrederick Mayle return parts; 109*9712c20fSFrederick Mayle} 110*9712c20fSFrederick Mayle 111*9712c20fSFrederick Mayle//============================================================================= 112*9712c20fSFrederick Maylestatic void StartSymUploadProtocolV1(Options* options, 113*9712c20fSFrederick Mayle NSString* OS, 114*9712c20fSFrederick Mayle NSString* CPU, 115*9712c20fSFrederick Mayle NSString* debugID, 116*9712c20fSFrederick Mayle NSString* debugFile) { 117*9712c20fSFrederick Mayle NSURL* url = [NSURL URLWithString:options->uploadURLStr]; 118*9712c20fSFrederick Mayle HTTPMultipartUpload* ul = [[HTTPMultipartUpload alloc] initWithURL:url]; 119*9712c20fSFrederick Mayle NSMutableDictionary* parameters = [NSMutableDictionary dictionary]; 120*9712c20fSFrederick Mayle 121*9712c20fSFrederick Mayle // Add parameters 122*9712c20fSFrederick Mayle [parameters setObject:debugID forKey:@"debug_identifier"]; 123*9712c20fSFrederick Mayle [parameters setObject:OS forKey:@"os"]; 124*9712c20fSFrederick Mayle [parameters setObject:CPU forKey:@"cpu"]; 125*9712c20fSFrederick Mayle [parameters setObject:debugFile forKey:@"debug_file"]; 126*9712c20fSFrederick Mayle [parameters setObject:debugFile forKey:@"code_file"]; 127*9712c20fSFrederick Mayle [ul setParameters:parameters]; 128*9712c20fSFrederick Mayle 129*9712c20fSFrederick Mayle NSArray* keys = [parameters allKeys]; 130*9712c20fSFrederick Mayle int count = [keys count]; 131*9712c20fSFrederick Mayle for (int i = 0; i < count; ++i) { 132*9712c20fSFrederick Mayle NSString* key = [keys objectAtIndex:i]; 133*9712c20fSFrederick Mayle NSString* value = [parameters objectForKey:key]; 134*9712c20fSFrederick Mayle fprintf(stdout, "'%s' = '%s'\n", [key UTF8String], [value UTF8String]); 135*9712c20fSFrederick Mayle } 136*9712c20fSFrederick Mayle 137*9712c20fSFrederick Mayle // Add file 138*9712c20fSFrederick Mayle [ul addFileAtPath:options->symbolsPath name:@"symbol_file"]; 139*9712c20fSFrederick Mayle 140*9712c20fSFrederick Mayle // Send it 141*9712c20fSFrederick Mayle NSError* error = nil; 142*9712c20fSFrederick Mayle NSData* data = [ul send:&error]; 143*9712c20fSFrederick Mayle NSString* result = [[NSString alloc] initWithData:data 144*9712c20fSFrederick Mayle encoding:NSUTF8StringEncoding]; 145*9712c20fSFrederick Mayle int status = [[ul response] statusCode]; 146*9712c20fSFrederick Mayle 147*9712c20fSFrederick Mayle fprintf(stdout, "Send: %s\n", 148*9712c20fSFrederick Mayle error ? [[error description] UTF8String] : "No Error"); 149*9712c20fSFrederick Mayle fprintf(stdout, "Response: %d\n", status); 150*9712c20fSFrederick Mayle fprintf(stdout, "Result: %lu bytes\n%s\n", (unsigned long)[data length], 151*9712c20fSFrederick Mayle [result UTF8String]); 152*9712c20fSFrederick Mayle 153*9712c20fSFrederick Mayle [result release]; 154*9712c20fSFrederick Mayle [ul release]; 155*9712c20fSFrederick Mayle options->result = (!error && status == 200) ? kResultSuccess : kResultFailure; 156*9712c20fSFrederick Mayle} 157*9712c20fSFrederick Mayle 158*9712c20fSFrederick Mayle//============================================================================= 159*9712c20fSFrederick Maylestatic void StartSymUploadProtocolV2(Options* options, 160*9712c20fSFrederick Mayle NSString* debugID, 161*9712c20fSFrederick Mayle NSString* debugFile) { 162*9712c20fSFrederick Mayle options->result = kResultFailure; 163*9712c20fSFrederick Mayle 164*9712c20fSFrederick Mayle // Only check status of BREAKPAD symbols, because the v2 protocol doesn't 165*9712c20fSFrederick Mayle // (yet) have a way to check status of other symbol types. 166*9712c20fSFrederick Mayle if (!options->force && [options->type isEqualToString:kBreakpadSymbolType]) { 167*9712c20fSFrederick Mayle SymbolStatus symbolStatus = 168*9712c20fSFrederick Mayle [SymbolCollectorClient checkSymbolStatusOnServer:options->uploadURLStr 169*9712c20fSFrederick Mayle withAPIKey:options->apiKey 170*9712c20fSFrederick Mayle withDebugFile:debugFile 171*9712c20fSFrederick Mayle withDebugID:debugID]; 172*9712c20fSFrederick Mayle if (symbolStatus == SymbolStatusFound) { 173*9712c20fSFrederick Mayle fprintf(stdout, "Symbol file already exists, upload aborted." 174*9712c20fSFrederick Mayle " Use \"-f\" to overwrite.\n"); 175*9712c20fSFrederick Mayle options->result = kResultAlreadyExists; 176*9712c20fSFrederick Mayle return; 177*9712c20fSFrederick Mayle } else if (symbolStatus == SymbolStatusUnknown) { 178*9712c20fSFrederick Mayle fprintf(stdout, "Failed to get check for existing symbol.\n"); 179*9712c20fSFrederick Mayle return; 180*9712c20fSFrederick Mayle } 181*9712c20fSFrederick Mayle } 182*9712c20fSFrederick Mayle 183*9712c20fSFrederick Mayle UploadURLResponse* URLResponse = 184*9712c20fSFrederick Mayle [SymbolCollectorClient createUploadURLOnServer:options->uploadURLStr 185*9712c20fSFrederick Mayle withAPIKey:options->apiKey]; 186*9712c20fSFrederick Mayle if (URLResponse == nil) { 187*9712c20fSFrederick Mayle return; 188*9712c20fSFrederick Mayle } 189*9712c20fSFrederick Mayle 190*9712c20fSFrederick Mayle NSURL* uploadURL = [NSURL URLWithString:[URLResponse uploadURL]]; 191*9712c20fSFrederick Mayle HTTPPutRequest* putRequest = [[HTTPPutRequest alloc] initWithURL:uploadURL]; 192*9712c20fSFrederick Mayle [putRequest setFile:options->symbolsPath]; 193*9712c20fSFrederick Mayle 194*9712c20fSFrederick Mayle NSError* error = nil; 195*9712c20fSFrederick Mayle NSData* data = [putRequest send:&error]; 196*9712c20fSFrederick Mayle NSString* result = [[NSString alloc] initWithData:data 197*9712c20fSFrederick Mayle encoding:NSUTF8StringEncoding]; 198*9712c20fSFrederick Mayle int responseCode = [[putRequest response] statusCode]; 199*9712c20fSFrederick Mayle [putRequest release]; 200*9712c20fSFrederick Mayle 201*9712c20fSFrederick Mayle if (error || responseCode != 200) { 202*9712c20fSFrederick Mayle fprintf(stdout, "Failed to upload symbol file.\n"); 203*9712c20fSFrederick Mayle fprintf(stdout, "Response code: %d\n", responseCode); 204*9712c20fSFrederick Mayle fprintf(stdout, "Response:\n"); 205*9712c20fSFrederick Mayle fprintf(stdout, "%s\n", [result UTF8String]); 206*9712c20fSFrederick Mayle return; 207*9712c20fSFrederick Mayle } 208*9712c20fSFrederick Mayle 209*9712c20fSFrederick Mayle CompleteUploadResult completeUploadResult = 210*9712c20fSFrederick Mayle [SymbolCollectorClient completeUploadOnServer:options->uploadURLStr 211*9712c20fSFrederick Mayle withAPIKey:options->apiKey 212*9712c20fSFrederick Mayle withUploadKey:[URLResponse uploadKey] 213*9712c20fSFrederick Mayle withDebugFile:debugFile 214*9712c20fSFrederick Mayle withDebugID:debugID 215*9712c20fSFrederick Mayle withType:options->type 216*9712c20fSFrederick Mayle withProductName:options->productName]; 217*9712c20fSFrederick Mayle [URLResponse release]; 218*9712c20fSFrederick Mayle if (completeUploadResult == CompleteUploadResultError) { 219*9712c20fSFrederick Mayle fprintf(stdout, "Failed to complete upload.\n"); 220*9712c20fSFrederick Mayle return; 221*9712c20fSFrederick Mayle } else if (completeUploadResult == CompleteUploadResultDuplicateData) { 222*9712c20fSFrederick Mayle fprintf(stdout, "Uploaded file checksum matched existing file checksum," 223*9712c20fSFrederick Mayle " no change necessary.\n"); 224*9712c20fSFrederick Mayle } else { 225*9712c20fSFrederick Mayle fprintf(stdout, "Successfully sent the symbol file.\n"); 226*9712c20fSFrederick Mayle } 227*9712c20fSFrederick Mayle options->result = kResultSuccess; 228*9712c20fSFrederick Mayle} 229*9712c20fSFrederick Mayle 230*9712c20fSFrederick Mayle//============================================================================= 231*9712c20fSFrederick Maylestatic void Start(Options* options) { 232*9712c20fSFrederick Mayle // If non-BREAKPAD upload special-case. 233*9712c20fSFrederick Mayle if (![options->type isEqualToString:kBreakpadSymbolType]) { 234*9712c20fSFrederick Mayle StartSymUploadProtocolV2(options, options->debugID, options->codeFile); 235*9712c20fSFrederick Mayle return; 236*9712c20fSFrederick Mayle } 237*9712c20fSFrederick Mayle 238*9712c20fSFrederick Mayle NSArray* moduleParts = ModuleDataForSymbolFile(options->symbolsPath); 239*9712c20fSFrederick Mayle // MODULE <os> <cpu> <uuid> <module-name> 240*9712c20fSFrederick Mayle // 0 1 2 3 4 241*9712c20fSFrederick Mayle NSString* OS = [moduleParts objectAtIndex:1]; 242*9712c20fSFrederick Mayle NSString* CPU = [moduleParts objectAtIndex:2]; 243*9712c20fSFrederick Mayle NSMutableString* debugID = 244*9712c20fSFrederick Mayle [NSMutableString stringWithString:[moduleParts objectAtIndex:3]]; 245*9712c20fSFrederick Mayle [debugID replaceOccurrencesOfString:@"-" 246*9712c20fSFrederick Mayle withString:@"" 247*9712c20fSFrederick Mayle options:0 248*9712c20fSFrederick Mayle range:NSMakeRange(0, [debugID length])]; 249*9712c20fSFrederick Mayle NSString* debugFile = [moduleParts objectAtIndex:4]; 250*9712c20fSFrederick Mayle 251*9712c20fSFrederick Mayle if (options->symUploadProtocol == kSymUploadProtocolV1) { 252*9712c20fSFrederick Mayle StartSymUploadProtocolV1(options, OS, CPU, debugID, debugFile); 253*9712c20fSFrederick Mayle } else if (options->symUploadProtocol == kSymUploadProtocolV2) { 254*9712c20fSFrederick Mayle StartSymUploadProtocolV2(options, debugID, debugFile); 255*9712c20fSFrederick Mayle } 256*9712c20fSFrederick Mayle} 257*9712c20fSFrederick Mayle 258*9712c20fSFrederick Mayle//============================================================================= 259*9712c20fSFrederick Maylestatic void Usage(int argc, const char* argv[]) { 260*9712c20fSFrederick Mayle fprintf(stderr, "Submit symbol information.\n"); 261*9712c20fSFrederick Mayle fprintf(stderr, "Usage: %s [options] <symbol-file> <upload-URL>\n", argv[0]); 262*9712c20fSFrederick Mayle fprintf(stderr, "<symbol-file> should be created by using the dump_syms " 263*9712c20fSFrederick Mayle "tool.\n"); 264*9712c20fSFrederick Mayle fprintf(stderr, "<upload-URL> is the destination for the upload.\n"); 265*9712c20fSFrederick Mayle fprintf(stderr, "Options:\n"); 266*9712c20fSFrederick Mayle fprintf(stderr, "\t-p <protocol>: protocol to use for upload, accepts " 267*9712c20fSFrederick Mayle "[\"sym-upload-v1\", \"sym-upload-v2\"]. Default is " 268*9712c20fSFrederick Mayle "\"sym-upload-v1\".\n"); 269*9712c20fSFrederick Mayle fprintf(stderr, "\t-k <api-key>: secret for authentication with upload " 270*9712c20fSFrederick Mayle "server. [Only in sym-upload-v2 protocol mode]\n"); 271*9712c20fSFrederick Mayle fprintf(stderr, "\t-f: Overwrite symbol file on server if already present. " 272*9712c20fSFrederick Mayle "[Only in sym-upload-v2 protocol mode]\n"); 273*9712c20fSFrederick Mayle fprintf( 274*9712c20fSFrederick Mayle stderr, 275*9712c20fSFrederick Mayle "\t-t: <symbol-type> Explicitly set symbol upload type (" 276*9712c20fSFrederick Mayle "default is 'breakpad').\n" 277*9712c20fSFrederick Mayle "\t One of ['breakpad', 'elf', 'pe', 'macho', 'debug_only', 'dwp', " 278*9712c20fSFrederick Mayle "'dsym', 'pdb'].\n" 279*9712c20fSFrederick Mayle "\t Note: When this flag is set to anything other than 'breakpad', then " 280*9712c20fSFrederick Mayle "the '-c' and '-i' flags must also be set.\n"); 281*9712c20fSFrederick Mayle fprintf(stderr, "\t-c: <code-file> Explicitly set 'code_file' for symbol " 282*9712c20fSFrederick Mayle "upload (basename of executable).\n"); 283*9712c20fSFrederick Mayle fprintf(stderr, "\t-i: <debug-id> Explicitly set 'debug_id' for symbol " 284*9712c20fSFrederick Mayle "upload (typically build ID of executable). The debug-id for " 285*9712c20fSFrederick Mayle "symbol-types 'dsym' and 'macho' will be determined " 286*9712c20fSFrederick Mayle "automatically. \n"); 287*9712c20fSFrederick Mayle fprintf(stderr, "\t-n: <product-name> Optionally set 'product_name' for " 288*9712c20fSFrederick Mayle "symbol upload\n"); 289*9712c20fSFrederick Mayle fprintf(stderr, "\t-h: Usage\n"); 290*9712c20fSFrederick Mayle fprintf(stderr, "\t-?: Usage\n"); 291*9712c20fSFrederick Mayle fprintf(stderr, "\n"); 292*9712c20fSFrederick Mayle fprintf(stderr, "Exit codes:\n"); 293*9712c20fSFrederick Mayle fprintf(stderr, "\t%d: Success\n", kResultSuccess); 294*9712c20fSFrederick Mayle fprintf(stderr, "\t%d: Failure\n", kResultFailure); 295*9712c20fSFrederick Mayle fprintf(stderr, 296*9712c20fSFrederick Mayle "\t%d: Symbol file already exists on server (and -f was not " 297*9712c20fSFrederick Mayle "specified).\n", 298*9712c20fSFrederick Mayle kResultAlreadyExists); 299*9712c20fSFrederick Mayle fprintf(stderr, 300*9712c20fSFrederick Mayle "\t [This exit code will only be returned by the sym-upload-v2 " 301*9712c20fSFrederick Mayle "protocol.\n"); 302*9712c20fSFrederick Mayle fprintf(stderr, 303*9712c20fSFrederick Mayle "\t The sym-upload-v1 protocol can return either Success or " 304*9712c20fSFrederick Mayle "Failure\n"); 305*9712c20fSFrederick Mayle fprintf(stderr, "\t in this case, and the action taken by the server is " 306*9712c20fSFrederick Mayle "unspecified.]\n"); 307*9712c20fSFrederick Mayle fprintf(stderr, "\n"); 308*9712c20fSFrederick Mayle fprintf(stderr, "Examples:\n"); 309*9712c20fSFrederick Mayle fprintf(stderr, " With 'sym-upload-v1':\n"); 310*9712c20fSFrederick Mayle fprintf(stderr, " %s path/to/symbol_file http://myuploadserver\n", 311*9712c20fSFrederick Mayle argv[0]); 312*9712c20fSFrederick Mayle fprintf(stderr, " With 'sym-upload-v2':\n"); 313*9712c20fSFrederick Mayle fprintf(stderr, " [Defaulting to symbol type 'BREAKPAD']\n"); 314*9712c20fSFrederick Mayle fprintf(stderr, 315*9712c20fSFrederick Mayle " %s -p sym-upload-v2 -k mysecret123! " 316*9712c20fSFrederick Mayle "path/to/symbol_file http://myuploadserver\n", 317*9712c20fSFrederick Mayle argv[0]); 318*9712c20fSFrederick Mayle fprintf(stderr, " [Explicitly set symbol type to 'macho']\n"); 319*9712c20fSFrederick Mayle fprintf(stderr, 320*9712c20fSFrederick Mayle " %s -p sym-upload-v2 -k mysecret123! -t macho " 321*9712c20fSFrederick Mayle "-c app -i 11111111BBBB3333DDDD555555555555F " 322*9712c20fSFrederick Mayle "path/to/symbol_file http://myuploadserver\n", 323*9712c20fSFrederick Mayle argv[0]); 324*9712c20fSFrederick Mayle} 325*9712c20fSFrederick Mayle 326*9712c20fSFrederick Mayle//============================================================================= 327*9712c20fSFrederick Maylestatic void SetupOptions(int argc, const char* argv[], Options* options) { 328*9712c20fSFrederick Mayle // Set default options values. 329*9712c20fSFrederick Mayle options->symUploadProtocol = kSymUploadProtocolV1; 330*9712c20fSFrederick Mayle options->apiKey = nil; 331*9712c20fSFrederick Mayle options->type = kBreakpadSymbolType; 332*9712c20fSFrederick Mayle options->codeFile = nil; 333*9712c20fSFrederick Mayle options->debugID = nil; 334*9712c20fSFrederick Mayle options->force = NO; 335*9712c20fSFrederick Mayle options->productName = nil; 336*9712c20fSFrederick Mayle 337*9712c20fSFrederick Mayle extern int optind; 338*9712c20fSFrederick Mayle int ch; 339*9712c20fSFrederick Mayle 340*9712c20fSFrederick Mayle while ((ch = getopt(argc, (char* const*)argv, "p:k:t:c:i:n:hf?")) != -1) { 341*9712c20fSFrederick Mayle switch (ch) { 342*9712c20fSFrederick Mayle case 'p': 343*9712c20fSFrederick Mayle if (strcmp(optarg, "sym-upload-v2") == 0) { 344*9712c20fSFrederick Mayle options->symUploadProtocol = kSymUploadProtocolV2; 345*9712c20fSFrederick Mayle break; 346*9712c20fSFrederick Mayle } else if (strcmp(optarg, "sym-upload-v1") == 0) { 347*9712c20fSFrederick Mayle // This is already the default but leave in case that changes. 348*9712c20fSFrederick Mayle options->symUploadProtocol = kSymUploadProtocolV1; 349*9712c20fSFrederick Mayle break; 350*9712c20fSFrederick Mayle } 351*9712c20fSFrederick Mayle Usage(argc, argv); 352*9712c20fSFrederick Mayle exit(0); 353*9712c20fSFrederick Mayle break; 354*9712c20fSFrederick Mayle case 'k': 355*9712c20fSFrederick Mayle options->apiKey = [NSString stringWithCString:optarg 356*9712c20fSFrederick Mayle encoding:NSASCIIStringEncoding]; 357*9712c20fSFrederick Mayle break; 358*9712c20fSFrederick Mayle case 't': { 359*9712c20fSFrederick Mayle // This is really an enum, so treat as upper-case for consistency with 360*9712c20fSFrederick Mayle // enum naming convention on server-side. 361*9712c20fSFrederick Mayle options->type = [[NSString stringWithCString:optarg 362*9712c20fSFrederick Mayle encoding:NSASCIIStringEncoding] 363*9712c20fSFrederick Mayle uppercaseString]; 364*9712c20fSFrederick Mayle break; 365*9712c20fSFrederick Mayle } 366*9712c20fSFrederick Mayle case 'c': 367*9712c20fSFrederick Mayle options->codeFile = [NSString stringWithCString:optarg 368*9712c20fSFrederick Mayle encoding:NSASCIIStringEncoding]; 369*9712c20fSFrederick Mayle break; 370*9712c20fSFrederick Mayle case 'i': 371*9712c20fSFrederick Mayle options->debugID = [NSString stringWithCString:optarg 372*9712c20fSFrederick Mayle encoding:NSASCIIStringEncoding]; 373*9712c20fSFrederick Mayle break; 374*9712c20fSFrederick Mayle case 'n': 375*9712c20fSFrederick Mayle options->productName = 376*9712c20fSFrederick Mayle [NSString stringWithCString:optarg 377*9712c20fSFrederick Mayle encoding:NSASCIIStringEncoding]; 378*9712c20fSFrederick Mayle break; 379*9712c20fSFrederick Mayle case 'f': 380*9712c20fSFrederick Mayle options->force = YES; 381*9712c20fSFrederick Mayle break; 382*9712c20fSFrederick Mayle default: 383*9712c20fSFrederick Mayle Usage(argc, argv); 384*9712c20fSFrederick Mayle exit(0); 385*9712c20fSFrederick Mayle break; 386*9712c20fSFrederick Mayle } 387*9712c20fSFrederick Mayle } 388*9712c20fSFrederick Mayle 389*9712c20fSFrederick Mayle if ((argc - optind) != 2) { 390*9712c20fSFrederick Mayle fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]); 391*9712c20fSFrederick Mayle Usage(argc, argv); 392*9712c20fSFrederick Mayle exit(1); 393*9712c20fSFrederick Mayle } 394*9712c20fSFrederick Mayle 395*9712c20fSFrederick Mayle int fd = open(argv[optind], O_RDONLY); 396*9712c20fSFrederick Mayle if (fd < 0) { 397*9712c20fSFrederick Mayle fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); 398*9712c20fSFrederick Mayle exit(1); 399*9712c20fSFrederick Mayle } 400*9712c20fSFrederick Mayle 401*9712c20fSFrederick Mayle struct stat statbuf; 402*9712c20fSFrederick Mayle if (fstat(fd, &statbuf) < 0) { 403*9712c20fSFrederick Mayle fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); 404*9712c20fSFrederick Mayle close(fd); 405*9712c20fSFrederick Mayle exit(1); 406*9712c20fSFrederick Mayle } 407*9712c20fSFrederick Mayle close(fd); 408*9712c20fSFrederick Mayle 409*9712c20fSFrederick Mayle if (!S_ISREG(statbuf.st_mode)) { 410*9712c20fSFrederick Mayle fprintf(stderr, "%s: %s: not a regular file\n", argv[0], argv[optind]); 411*9712c20fSFrederick Mayle exit(1); 412*9712c20fSFrederick Mayle } 413*9712c20fSFrederick Mayle 414*9712c20fSFrederick Mayle bool isBreakpadUpload = [options->type isEqualToString:kBreakpadSymbolType]; 415*9712c20fSFrederick Mayle bool hasCodeFile = options->codeFile != nil; 416*9712c20fSFrederick Mayle bool hasDebugID = options->debugID != nil; 417*9712c20fSFrederick Mayle if (isBreakpadUpload && (hasCodeFile || hasDebugID)) { 418*9712c20fSFrederick Mayle fprintf(stderr, "\n"); 419*9712c20fSFrederick Mayle fprintf(stderr, 420*9712c20fSFrederick Mayle "%s: -c and -i should only be specified for non-breakpad " 421*9712c20fSFrederick Mayle "symbol upload types.\n", 422*9712c20fSFrederick Mayle argv[0]); 423*9712c20fSFrederick Mayle fprintf(stderr, "\n"); 424*9712c20fSFrederick Mayle Usage(argc, argv); 425*9712c20fSFrederick Mayle exit(1); 426*9712c20fSFrederick Mayle } 427*9712c20fSFrederick Mayle 428*9712c20fSFrederick Mayle if (!isBreakpadUpload && hasCodeFile && !hasDebugID && 429*9712c20fSFrederick Mayle ([options->type isEqualToString:kMachOSymbolType] || 430*9712c20fSFrederick Mayle [options->type isEqualToString:kDSYMSymbolType])) { 431*9712c20fSFrederick Mayle DumpSymbols dump_symbols(SYMBOLS_AND_FILES | INLINES, false); 432*9712c20fSFrederick Mayle if (dump_symbols.Read(argv[optind])) { 433*9712c20fSFrederick Mayle std::string identifier = dump_symbols.Identifier(); 434*9712c20fSFrederick Mayle if (identifier.empty()) { 435*9712c20fSFrederick Mayle fprintf(stderr, "\n"); 436*9712c20fSFrederick Mayle fprintf(stderr, 437*9712c20fSFrederick Mayle "%s: Unable to determine debug-id. Please specify with '-i'.\n", 438*9712c20fSFrederick Mayle argv[0]); 439*9712c20fSFrederick Mayle fprintf(stderr, "\n"); 440*9712c20fSFrederick Mayle Usage(argc, argv); 441*9712c20fSFrederick Mayle exit(1); 442*9712c20fSFrederick Mayle } 443*9712c20fSFrederick Mayle options->debugID = [NSString stringWithUTF8String:identifier.c_str()]; 444*9712c20fSFrederick Mayle hasDebugID = true; 445*9712c20fSFrederick Mayle } 446*9712c20fSFrederick Mayle } 447*9712c20fSFrederick Mayle 448*9712c20fSFrederick Mayle if (!isBreakpadUpload && (!hasCodeFile || !hasDebugID)) { 449*9712c20fSFrederick Mayle fprintf(stderr, "\n"); 450*9712c20fSFrederick Mayle fprintf(stderr, 451*9712c20fSFrederick Mayle "%s: -c and -i must be specified for non-breakpad " 452*9712c20fSFrederick Mayle "symbol upload types.\n", 453*9712c20fSFrederick Mayle argv[0]); 454*9712c20fSFrederick Mayle fprintf(stderr, "\n"); 455*9712c20fSFrederick Mayle Usage(argc, argv); 456*9712c20fSFrederick Mayle exit(1); 457*9712c20fSFrederick Mayle } 458*9712c20fSFrederick Mayle 459*9712c20fSFrederick Mayle options->symbolsPath = [NSString stringWithUTF8String:argv[optind]]; 460*9712c20fSFrederick Mayle options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]]; 461*9712c20fSFrederick Mayle} 462*9712c20fSFrederick Mayle 463*9712c20fSFrederick Mayle//============================================================================= 464*9712c20fSFrederick Mayleint main(int argc, const char* argv[]) { 465*9712c20fSFrederick Mayle NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 466*9712c20fSFrederick Mayle Options options; 467*9712c20fSFrederick Mayle 468*9712c20fSFrederick Mayle bzero(&options, sizeof(Options)); 469*9712c20fSFrederick Mayle SetupOptions(argc, argv, &options); 470*9712c20fSFrederick Mayle Start(&options); 471*9712c20fSFrederick Mayle 472*9712c20fSFrederick Mayle [pool release]; 473*9712c20fSFrederick Mayle return options.result; 474*9712c20fSFrederick Mayle} 475