1// Copyright (c) 2006, Google Inc. 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are 6// met: 7// 8// * Redistributions of source code must retain the above copyright 9// notice, this list of conditions and the following disclaimer. 10// * Redistributions in binary form must reproduce the above 11// copyright notice, this list of conditions and the following disclaimer 12// in the documentation and/or other materials provided with the 13// distribution. 14// * Neither the name of Google Inc. nor the names of its 15// contributors may be used to endorse or promote products derived from 16// this software without specific prior written permission. 17// 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30// symupload.m: Upload a symbol file to a HTTP server. The upload is sent as 31// a multipart/form-data POST request with the following parameters: 32// code_file: the basename of the module, e.g. "app" 33// debug_file: the basename of the debugging file, e.g. "app" 34// debug_identifier: the debug file's identifier, usually consisting of 35// the guid and age embedded in the pdb, e.g. 36// "11111111BBBB3333DDDD555555555555F" 37// os: the operating system that the module was built for 38// cpu: the CPU that the module was built for (x86 or ppc) 39// symbol_file: the contents of the breakpad-format symbol file 40 41#include <unistd.h> 42 43#include <Foundation/Foundation.h> 44#include "HTTPMultipartUpload.h" 45 46typedef struct { 47 NSString *symbolsPath; 48 NSString *uploadURLStr; 49 BOOL success; 50} Options; 51 52//============================================================================= 53static NSArray *ModuleDataForSymbolFile(NSString *file) { 54 NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:file]; 55 NSData *data = [fh readDataOfLength:1024]; 56 NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 57 NSScanner *scanner = [NSScanner scannerWithString:str]; 58 NSString *line; 59 NSMutableArray *parts = nil; 60 const int MODULE_ID_INDEX = 3; 61 62 if ([scanner scanUpToString:@"\n" intoString:&line]) { 63 parts = [[NSMutableArray alloc] init]; 64 NSScanner *moduleInfoScanner = [NSScanner scannerWithString:line]; 65 NSString *moduleInfo; 66 // Get everything BEFORE the module name. None of these properties 67 // can have spaces. 68 for (int i = 0; i <= MODULE_ID_INDEX; i++) { 69 [moduleInfoScanner scanUpToString:@" " intoString:&moduleInfo]; 70 [parts addObject:moduleInfo]; 71 } 72 73 // Now get the module name. This can have a space so we scan to 74 // the end of the line. 75 [moduleInfoScanner scanUpToString:@"\n" intoString:&moduleInfo]; 76 [parts addObject:moduleInfo]; 77 } 78 79 [str release]; 80 81 return parts; 82} 83 84//============================================================================= 85static NSString *CompactIdentifier(NSString *uuid) { 86 NSMutableString *str = [NSMutableString stringWithString:uuid]; 87 [str replaceOccurrencesOfString:@"-" withString:@"" options:0 88 range:NSMakeRange(0, [str length])]; 89 90 return str; 91} 92 93//============================================================================= 94static void Start(Options *options) { 95 NSURL *url = [NSURL URLWithString:options->uploadURLStr]; 96 HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url]; 97 NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; 98 NSArray *moduleParts = ModuleDataForSymbolFile(options->symbolsPath); 99 NSMutableString *compactedID = 100 [NSMutableString stringWithString:[moduleParts objectAtIndex:3]]; 101 [compactedID replaceOccurrencesOfString:@"-" withString:@"" options:0 102 range:NSMakeRange(0, [compactedID length])]; 103 104 // Add parameters 105 [parameters setObject:compactedID forKey:@"debug_identifier"]; 106 107 // MODULE <os> <cpu> <uuid> <module-name> 108 // 0 1 2 3 4 109 [parameters setObject:[moduleParts objectAtIndex:1] forKey:@"os"]; 110 [parameters setObject:[moduleParts objectAtIndex:2] forKey:@"cpu"]; 111 [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"debug_file"]; 112 [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"code_file"]; 113 [ul setParameters:parameters]; 114 115 NSArray *keys = [parameters allKeys]; 116 int count = [keys count]; 117 for (int i = 0; i < count; ++i) { 118 NSString *key = [keys objectAtIndex:i]; 119 NSString *value = [parameters objectForKey:key]; 120 fprintf(stdout, "'%s' = '%s'\n", [key UTF8String], 121 [value UTF8String]); 122 } 123 124 // Add file 125 [ul addFileAtPath:options->symbolsPath name:@"symbol_file"]; 126 127 // Send it 128 NSError *error = nil; 129 NSData *data = [ul send:&error]; 130 NSString *result = [[NSString alloc] initWithData:data 131 encoding:NSUTF8StringEncoding]; 132 int status = [[ul response] statusCode]; 133 134 fprintf(stdout, "Send: %s\n", error ? [[error description] UTF8String] : 135 "No Error"); 136 fprintf(stdout, "Response: %d\n", status); 137 fprintf(stdout, "Result: %lu bytes\n%s\n", 138 (unsigned long)[data length], [result UTF8String]); 139 140 [result release]; 141 [ul release]; 142 options->success = !error && status==200; 143} 144 145//============================================================================= 146static void 147Usage(int argc, const char *argv[]) { 148 fprintf(stderr, "Submit symbol information.\n"); 149 fprintf(stderr, "Usage: %s <symbols> <upload-URL>\n", argv[0]); 150 fprintf(stderr, "<symbols> should be created by using the dump_syms tool.\n"); 151 fprintf(stderr, "<upload-URL> is the destination for the upload\n"); 152 fprintf(stderr, "\t-h: Usage\n"); 153 fprintf(stderr, "\t-?: Usage\n"); 154} 155 156//============================================================================= 157static void 158SetupOptions(int argc, const char *argv[], Options *options) { 159 extern int optind; 160 char ch; 161 162 while ((ch = getopt(argc, (char * const *)argv, "h?")) != -1) { 163 switch (ch) { 164 default: 165 Usage(argc, argv); 166 exit(0); 167 break; 168 } 169 } 170 171 if ((argc - optind) != 2) { 172 fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]); 173 Usage(argc, argv); 174 exit(1); 175 } 176 177 options->symbolsPath = [NSString stringWithUTF8String:argv[optind]]; 178 options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]]; 179} 180 181//============================================================================= 182int main (int argc, const char * argv[]) { 183 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 184 Options options; 185 186 bzero(&options, sizeof(Options)); 187 SetupOptions(argc, argv, &options); 188 Start(&options); 189 190 [pool release]; 191 return options.success ? 0 : 1; 192} 193