|  | // Copyright (c) 2006, Google Inc. | 
|  | // All rights reserved. | 
|  | // | 
|  | // 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 Inc. 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.m: 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" | 
|  |  | 
|  | typedef struct { | 
|  | NSString *symbolsPath; | 
|  | NSString *uploadURLStr; | 
|  | BOOL success; | 
|  | } 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 Start(Options *options) { | 
|  | NSURL *url = [NSURL URLWithString:options->uploadURLStr]; | 
|  | HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url]; | 
|  | NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; | 
|  | NSArray *moduleParts = ModuleDataForSymbolFile(options->symbolsPath); | 
|  | NSMutableString *compactedID = | 
|  | [NSMutableString stringWithString:[moduleParts objectAtIndex:3]]; | 
|  | [compactedID replaceOccurrencesOfString:@"-" withString:@"" options:0 | 
|  | range:NSMakeRange(0, [compactedID length])]; | 
|  |  | 
|  | // Add parameters | 
|  | [parameters setObject:compactedID forKey:@"debug_identifier"]; | 
|  |  | 
|  | // MODULE <os> <cpu> <uuid> <module-name> | 
|  | // 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"]; | 
|  | [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->success = !error && status==200; | 
|  | } | 
|  |  | 
|  | //============================================================================= | 
|  | static void | 
|  | Usage(int argc, const char *argv[]) { | 
|  | fprintf(stderr, "Submit symbol information.\n"); | 
|  | fprintf(stderr, "Usage: %s <symbols> <upload-URL>\n", argv[0]); | 
|  | fprintf(stderr, "<symbols> should be created by using the dump_syms tool.\n"); | 
|  | fprintf(stderr, "<upload-URL> is the destination for the upload\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; | 
|  | char ch; | 
|  |  | 
|  | while ((ch = getopt(argc, (char * const *)argv, "h?")) != -1) { | 
|  | switch (ch) { | 
|  | 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); | 
|  | } | 
|  |  | 
|  | 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.success ? 0 : 1; | 
|  | } |