xref: /aosp_15_r20/external/google-breakpad/src/tools/mac/symupload/symupload.mm (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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