aboutsummaryrefslogtreecommitdiff
path: root/src/common/mac
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/mac')
-rw-r--r--src/common/mac/Breakpad.xcconfig5
-rw-r--r--src/common/mac/BreakpadDebug.xcconfig5
-rw-r--r--src/common/mac/BreakpadRelease.xcconfig5
-rw-r--r--src/common/mac/GTMDefines.h2
-rw-r--r--src/common/mac/GTMLogger.h2
-rw-r--r--src/common/mac/GTMLogger.m2
-rw-r--r--src/common/mac/HTTPGetRequest.h41
-rw-r--r--src/common/mac/HTTPGetRequest.m38
-rw-r--r--src/common/mac/HTTPMultipartUpload.h57
-rw-r--r--src/common/mac/HTTPMultipartUpload.m204
-rw-r--r--src/common/mac/HTTPPutRequest.h50
-rw-r--r--src/common/mac/HTTPPutRequest.m55
-rw-r--r--src/common/mac/HTTPRequest.h72
-rw-r--r--src/common/mac/HTTPRequest.m267
-rw-r--r--src/common/mac/HTTPSimplePostRequest.h56
-rw-r--r--src/common/mac/HTTPSimplePostRequest.m68
-rw-r--r--src/common/mac/MachIPC.h25
-rw-r--r--src/common/mac/MachIPC.mm31
-rw-r--r--src/common/mac/SymbolCollectorClient.h103
-rw-r--r--src/common/mac/SymbolCollectorClient.m271
-rw-r--r--src/common/mac/arch_utilities.cc12
-rw-r--r--src/common/mac/arch_utilities.h5
-rw-r--r--src/common/mac/bootstrap_compat.cc5
-rw-r--r--src/common/mac/bootstrap_compat.h5
-rw-r--r--src/common/mac/byteswap.h5
-rw-r--r--src/common/mac/dump_syms.cc258
-rw-r--r--src/common/mac/dump_syms.h95
-rw-r--r--src/common/mac/encoding_util.h40
-rw-r--r--src/common/mac/encoding_util.m46
-rw-r--r--src/common/mac/file_id.cc52
-rw-r--r--src/common/mac/file_id.h30
-rw-r--r--src/common/mac/launch_reporter.cc5
-rw-r--r--src/common/mac/launch_reporter.h5
-rw-r--r--src/common/mac/macho_id.cc175
-rw-r--r--src/common/mac/macho_id.h51
-rw-r--r--src/common/mac/macho_reader.cc62
-rw-r--r--src/common/mac/macho_reader.h51
-rw-r--r--src/common/mac/macho_reader_unittest.cc136
-rw-r--r--src/common/mac/macho_utilities.cc5
-rw-r--r--src/common/mac/macho_utilities.h5
-rw-r--r--src/common/mac/macho_walker.cc25
-rw-r--r--src/common/mac/macho_walker.h31
-rw-r--r--src/common/mac/minidump_upload.m134
-rw-r--r--src/common/mac/scoped_task_suspend-inl.h5
-rw-r--r--src/common/mac/string_utilities.cc9
-rw-r--r--src/common/mac/string_utilities.h7
-rw-r--r--src/common/mac/super_fat_arch.h7
-rw-r--r--src/common/mac/testing/GTMSenTestCase.h2
-rw-r--r--src/common/mac/testing/GTMSenTestCase.m2
49 files changed, 1840 insertions, 789 deletions
diff --git a/src/common/mac/Breakpad.xcconfig b/src/common/mac/Breakpad.xcconfig
index f0913690..fd28d3ce 100644
--- a/src/common/mac/Breakpad.xcconfig
+++ b/src/common/mac/Breakpad.xcconfig
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/BreakpadDebug.xcconfig b/src/common/mac/BreakpadDebug.xcconfig
index 94cdd8cf..6ec7c00e 100644
--- a/src/common/mac/BreakpadDebug.xcconfig
+++ b/src/common/mac/BreakpadDebug.xcconfig
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/BreakpadRelease.xcconfig b/src/common/mac/BreakpadRelease.xcconfig
index 920f277d..9121b0d0 100644
--- a/src/common/mac/BreakpadRelease.xcconfig
+++ b/src/common/mac/BreakpadRelease.xcconfig
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/GTMDefines.h b/src/common/mac/GTMDefines.h
index 04fcf6d0..ae5368cd 100644
--- a/src/common/mac/GTMDefines.h
+++ b/src/common/mac/GTMDefines.h
@@ -1,7 +1,7 @@
//
// GTMDefines.h
//
-// Copyright 2008 Google Inc.
+// Copyright 2008 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
diff --git a/src/common/mac/GTMLogger.h b/src/common/mac/GTMLogger.h
index c4fd1402..dcc7da44 100644
--- a/src/common/mac/GTMLogger.h
+++ b/src/common/mac/GTMLogger.h
@@ -1,7 +1,7 @@
//
// GTMLogger.h
//
-// Copyright 2007-2008 Google Inc.
+// Copyright 2007-2008 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
diff --git a/src/common/mac/GTMLogger.m b/src/common/mac/GTMLogger.m
index ebc5836a..17db83d6 100644
--- a/src/common/mac/GTMLogger.m
+++ b/src/common/mac/GTMLogger.m
@@ -1,7 +1,7 @@
//
// GTMLogger.m
//
-// Copyright 2007-2008 Google Inc.
+// Copyright 2007-2008 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
diff --git a/src/common/mac/HTTPGetRequest.h b/src/common/mac/HTTPGetRequest.h
new file mode 100644
index 00000000..9c3cb3f9
--- /dev/null
+++ b/src/common/mac/HTTPGetRequest.h
@@ -0,0 +1,41 @@
+// Copyright 2020 Google LLC
+//
+// 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 LLC 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.
+
+#import <Foundation/Foundation.h>
+
+#import "HTTPRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a HTTP GET request
+ */
+@interface HTTPGetRequest : HTTPRequest
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/HTTPGetRequest.m b/src/common/mac/HTTPGetRequest.m
new file mode 100644
index 00000000..e151cfd8
--- /dev/null
+++ b/src/common/mac/HTTPGetRequest.m
@@ -0,0 +1,38 @@
+// Copyright 2020 Google LLC
+//
+// 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 LLC 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.
+
+#import "HTTPGetRequest.h"
+
+@implementation HTTPGetRequest
+
+//=============================================================================
+- (NSString*)HTTPMethod {
+ return @"GET";
+}
+
+@end
diff --git a/src/common/mac/HTTPMultipartUpload.h b/src/common/mac/HTTPMultipartUpload.h
index 42e8fed3..27b9cf86 100644
--- a/src/common/mac/HTTPMultipartUpload.h
+++ b/src/common/mac/HTTPMultipartUpload.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -27,35 +26,37 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// HTTPMultipartUpload: A multipart/form-data HTTP uploader.
-// Each parameter pair is sent as a boundary
-// Each file is sent with a name field in addition to the filename and data
-// The data will be sent synchronously.
-
#import <Foundation/Foundation.h>
-@interface HTTPMultipartUpload : NSObject {
+#import "HTTPRequest.h"
+/**
+ Represents a multipart/form-data HTTP upload (POST request).
+ Each parameter pair is sent as a boundary.
+ Each file is sent with a name field in addition to the filename and data.
+ */
+@interface HTTPMultipartUpload : HTTPRequest {
@protected
- NSURL *url_; // The destination URL (STRONG)
- NSDictionary *parameters_; // The key/value pairs for sending data (STRONG)
- NSMutableDictionary *files_; // Dictionary of name/file-path (STRONG)
- NSString *boundary_; // The boundary string (STRONG)
- NSHTTPURLResponse *response_; // The response from the send (STRONG)
+ NSDictionary* parameters_; // The key/value pairs for sending data (STRONG)
+ NSMutableDictionary* files_; // Dictionary of name/file-path (STRONG)
+ NSString* boundary_; // The boundary string (STRONG)
}
-- (id)initWithURL:(NSURL *)url;
-
-- (NSURL *)URL;
-
-- (void)setParameters:(NSDictionary *)parameters;
-- (NSDictionary *)parameters;
-
-- (void)addFileAtPath:(NSString *)path name:(NSString *)name;
-- (void)addFileContents:(NSData *)data name:(NSString *)name;
-- (NSDictionary *)files;
-
-// Set the data and return the response
-- (NSData *)send:(NSError **)error;
-- (NSHTTPURLResponse *)response;
+/**
+ Sets the parameters that will be sent in the multipart POST request.
+ */
+- (void)setParameters:(NSDictionary*)parameters;
+- (NSDictionary*)parameters;
+
+/**
+ Adds a file to be uploaded in the multipart POST request, by its file path.
+ */
+- (void)addFileAtPath:(NSString*)path name:(NSString*)name;
+
+/**
+ Adds a file to be uploaded in the multipart POST request, by its name and
+ contents.
+ */
+- (void)addFileContents:(NSData*)data name:(NSString*)name;
+- (NSDictionary*)files;
@end
diff --git a/src/common/mac/HTTPMultipartUpload.m b/src/common/mac/HTTPMultipartUpload.m
index a3677f25..b3a084a9 100644
--- a/src/common/mac/HTTPMultipartUpload.m
+++ b/src/common/mac/HTTPMultipartUpload.m
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -28,74 +27,17 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import "HTTPMultipartUpload.h"
-#import "GTMDefines.h"
-// As -[NSString stringByAddingPercentEscapesUsingEncoding:] has been
-// deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements it
-// using -[NSString stringByAddingPercentEncodingWithAllowedCharacters:] when
-// using those SDKs.
-static NSString *PercentEncodeNSString(NSString *key) {
-#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \
- __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \
- (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
- defined(MAC_OS_X_VERSION_10_11) && \
- MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
- return [key stringByAddingPercentEncodingWithAllowedCharacters:
- [NSCharacterSet URLQueryAllowedCharacterSet]];
-#else
- return [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
-#endif
-}
+#import "GTMDefines.h"
+#import "encoding_util.h"
-// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has
-// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements
-// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is
-// available on iOS 7+.
-static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
- NSURLResponse **out_response,
- NSError **out_error) {
-#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
- __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) || \
- (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
- defined(MAC_OS_X_VERSION_10_11) && \
- MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
- __block NSData* result = nil;
- __block NSError* error = nil;
- __block NSURLResponse* response = nil;
- dispatch_semaphore_t wait_semaphone = dispatch_semaphore_create(0);
- [[[NSURLSession sharedSession]
- dataTaskWithRequest:req
- completionHandler:^(NSData *data,
- NSURLResponse *resp,
- NSError *err) {
- if (out_error)
- error = [err retain];
- if (out_response)
- response = [resp retain];
- if (err == nil)
- result = [data retain];
- dispatch_semaphore_signal(wait_semaphone);
- }] resume];
- dispatch_semaphore_wait(wait_semaphone, DISPATCH_TIME_FOREVER);
- dispatch_release(wait_semaphone);
- if (out_error)
- *out_error = [error autorelease];
- if (out_response)
- *out_response = [response autorelease];
- return [result autorelease];
-#else
- return [NSURLConnection sendSynchronousRequest:req
- returningResponse:out_response
- error:out_error];
-#endif
-}
-@interface HTTPMultipartUpload(PrivateMethods)
-- (NSString *)multipartBoundary;
+@interface HTTPMultipartUpload (PrivateMethods)
+- (NSString*)multipartBoundary;
// Each of the following methods will append the starting multipart boundary,
// but not the ending one.
-- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value;
-- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name;
-- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name;
+- (NSData*)formDataForKey:(NSString*)key value:(NSString*)value;
+- (NSData*)formDataForFileContents:(NSData*)contents name:(NSString*)name;
+- (NSData*)formDataForFile:(NSString*)file name:(NSString*)name;
@end
@implementation HTTPMultipartUpload
@@ -103,50 +45,39 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
#pragma mark -
#pragma mark || Private ||
//=============================================================================
-- (NSString *)multipartBoundary {
+- (NSString*)multipartBoundary {
// The boundary has 27 '-' characters followed by 16 hex digits
- return [NSString stringWithFormat:@"---------------------------%08X%08X",
- rand(), rand()];
-}
-
-//=============================================================================
-- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value {
- NSString *escaped = PercentEncodeNSString(key);
- NSString *fmt =
- @"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
- NSString *form = [NSString stringWithFormat:fmt, boundary_, escaped, value];
-
- return [form dataUsingEncoding:NSUTF8StringEncoding];
+ return [NSString
+ stringWithFormat:@"---------------------------%08X%08X", rand(), rand()];
}
//=============================================================================
-- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name {
- NSMutableData *data = [NSMutableData data];
- NSString *escaped = PercentEncodeNSString(name);
- NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"%@\"; "
- "filename=\"minidump.dmp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
- NSString *pre = [NSString stringWithFormat:fmt, boundary_, escaped];
+- (NSData*)formDataForKey:(NSString*)key value:(NSString*)value {
+ NSMutableData* data = [NSMutableData data];
+ [self appendBoundaryData:data];
- [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
- [data appendData:contents];
+ NSString* escaped = PercentEncodeNSString(key);
+ NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
+ NSString *form = [NSString stringWithFormat:fmt, escaped, value];
+ [data appendData:[form dataUsingEncoding:NSUTF8StringEncoding]];
return data;
}
//=============================================================================
-- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name {
- NSData *contents = [NSData dataWithContentsOfFile:file];
+- (void)appendBoundaryData:(NSMutableData*)data {
+ NSString* fmt = @"--%@\r\n";
+ NSString* pre = [NSString stringWithFormat:fmt, boundary_];
- return [self formDataForFileContents:contents name:name];
+ [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
}
//=============================================================================
#pragma mark -
#pragma mark || Public ||
//=============================================================================
-- (id)initWithURL:(NSURL *)url {
- if ((self = [super init])) {
- url_ = [url copy];
+- (id)initWithURL:(NSURL*)url {
+ if ((self = [super initWithURL:url])) {
boundary_ = [[self multipartBoundary] retain];
files_ = [[NSMutableDictionary alloc] init];
}
@@ -156,22 +87,15 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
//=============================================================================
- (void)dealloc {
- [url_ release];
[parameters_ release];
[files_ release];
[boundary_ release];
- [response_ release];
[super dealloc];
}
//=============================================================================
-- (NSURL *)URL {
- return url_;
-}
-
-//=============================================================================
-- (void)setParameters:(NSDictionary *)parameters {
+- (void)setParameters:(NSDictionary*)parameters {
if (parameters != parameters_) {
[parameters_ release];
parameters_ = [parameters copy];
@@ -179,40 +103,43 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
}
//=============================================================================
-- (NSDictionary *)parameters {
+- (NSDictionary*)parameters {
return parameters_;
}
//=============================================================================
-- (void)addFileAtPath:(NSString *)path name:(NSString *)name {
+- (void)addFileAtPath:(NSString*)path name:(NSString*)name {
[files_ setObject:path forKey:name];
}
//=============================================================================
-- (void)addFileContents:(NSData *)data name:(NSString *)name {
+- (void)addFileContents:(NSData*)data name:(NSString*)name {
[files_ setObject:data forKey:name];
}
//=============================================================================
-- (NSDictionary *)files {
+- (NSDictionary*)files {
return files_;
}
//=============================================================================
-- (NSData *)send:(NSError **)error {
- NSMutableURLRequest *req =
- [[NSMutableURLRequest alloc]
- initWithURL:url_ cachePolicy:NSURLRequestUseProtocolCachePolicy
- timeoutInterval:60.0];
+- (NSString*)HTTPMethod {
+ return @"POST";
+}
- NSMutableData *postBody = [NSMutableData data];
+//=============================================================================
+- (NSString*)contentType {
+ return [NSString
+ stringWithFormat:@"multipart/form-data; boundary=%@", boundary_];
+}
- [req setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",
- boundary_] forHTTPHeaderField:@"Content-type"];
+//=============================================================================
+- (NSData*)bodyData {
+ NSMutableData* postBody = [NSMutableData data];
// Add any parameters to the message
- NSArray *parameterKeys = [parameters_ allKeys];
- NSString *key;
+ NSArray* parameterKeys = [parameters_ allKeys];
+ NSString* key;
NSInteger count = [parameterKeys count];
for (NSInteger i = 0; i < count; ++i) {
@@ -222,46 +149,21 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
}
// Add any files to the message
- NSArray *fileNames = [files_ allKeys];
- for (NSString *name in fileNames) {
+ NSArray* fileNames = [files_ allKeys];
+ for (NSString* name in fileNames) {
+ // First append boundary
+ [self appendBoundaryData:postBody];
+ // Then the formdata
id fileOrData = [files_ objectForKey:name];
- NSData *fileData;
-
- // The object can be either the path to a file (NSString) or the contents
- // of the file (NSData).
- if ([fileOrData isKindOfClass:[NSData class]])
- fileData = [self formDataForFileContents:fileOrData name:name];
- else
- fileData = [self formDataForFile:fileOrData name:name];
-
- [postBody appendData:fileData];
+ [HTTPRequest appendFileToBodyData:postBody
+ withName:name
+ withFileOrData:fileOrData];
}
- NSString *epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_];
+ NSString* epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_];
[postBody appendData:[epilogue dataUsingEncoding:NSUTF8StringEncoding]];
- [req setHTTPBody:postBody];
- [req setHTTPMethod:@"POST"];
-
- [response_ release];
- response_ = nil;
-
- NSData *data = nil;
- if ([[req URL] isFileURL]) {
- [[req HTTPBody] writeToURL:[req URL] options:0 error:error];
- } else {
- NSURLResponse *response = nil;
- data = SendSynchronousNSURLRequest(req, &response, error);
- response_ = (NSHTTPURLResponse *)[response retain];
- }
- [req release];
-
- return data;
-}
-
-//=============================================================================
-- (NSHTTPURLResponse *)response {
- return response_;
+ return postBody;
}
@end
diff --git a/src/common/mac/HTTPPutRequest.h b/src/common/mac/HTTPPutRequest.h
new file mode 100644
index 00000000..36d38c01
--- /dev/null
+++ b/src/common/mac/HTTPPutRequest.h
@@ -0,0 +1,50 @@
+// Copyright 2020 Google LLC
+//
+// 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 LLC 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.
+
+#import <Foundation/Foundation.h>
+
+#import "HTTPRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents an HTTP PUT request.
+ */
+@interface HTTPPutRequest : HTTPRequest {
+ @protected
+ NSString* file_;
+}
+
+/**
+ Sets the path of the file that will be sent in the PUT request.
+ */
+- (void)setFile:(NSString*)file;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/HTTPPutRequest.m b/src/common/mac/HTTPPutRequest.m
new file mode 100644
index 00000000..b7c7e091
--- /dev/null
+++ b/src/common/mac/HTTPPutRequest.m
@@ -0,0 +1,55 @@
+// Copyright 2020 Google LLC
+//
+// 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 LLC 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.
+
+#import "HTTPPutRequest.h"
+
+@implementation HTTPPutRequest
+
+//=============================================================================
+- (void)dealloc {
+ [file_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (void)setFile:(NSString*)file {
+ file_ = [file copy];
+}
+
+//=============================================================================
+- (NSString*)HTTPMethod {
+ return @"PUT";
+}
+
+//=============================================================================
+- (NSData*)bodyData {
+ return [NSData dataWithContentsOfFile:file_];
+}
+
+@end
diff --git a/src/common/mac/HTTPRequest.h b/src/common/mac/HTTPRequest.h
new file mode 100644
index 00000000..49374147
--- /dev/null
+++ b/src/common/mac/HTTPRequest.h
@@ -0,0 +1,72 @@
+// Copyright 2020 Google LLC
+//
+// 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 LLC 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.
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+/**
+ Represents a single HTTP request. Sending the request is synchronous.
+ Once the send is complete, the response will be set.
+
+ This is a base interface that specific HTTP requests derive from.
+ It is not intended to be instantiated directly.
+ */
+@interface HTTPRequest : NSObject {
+ @protected
+ NSURL* URL_; // The destination URL (STRONG)
+ NSHTTPURLResponse* response_; // The response from the send (STRONG)
+}
+
+/**
+ Initializes the HTTPRequest and sets its URL.
+ */
+- (id)initWithURL:(NSURL*)URL;
+
+- (NSURL*)URL;
+
+- (NSHTTPURLResponse*)response;
+
+- (NSString*)HTTPMethod; // Internal, don't call outside class hierarchy.
+
+- (NSString*)contentType; // Internal, don't call outside class hierarchy.
+
+- (NSData*)bodyData; // Internal, don't call outside class hierarchy.
+
+- (NSData*)send:(NSError**)error;
+
+/**
+ Appends a file to the HTTP request, either by filename or by file content
+ (in the form of NSData).
+ */
++ (void)appendFileToBodyData:(NSMutableData*)data
+ withName:(NSString*)name
+ withFileOrData:(id)fileOrData;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/HTTPRequest.m b/src/common/mac/HTTPRequest.m
new file mode 100644
index 00000000..af21874d
--- /dev/null
+++ b/src/common/mac/HTTPRequest.m
@@ -0,0 +1,267 @@
+// Copyright 2020 Google LLC
+//
+// 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 LLC 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.
+
+#import "HTTPRequest.h"
+
+#include <Availability.h>
+#include <AvailabilityMacros.h>
+
+#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
+ __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0)
+#import <UIKit/UIKit.h>
+#define HAS_BACKGROUND_TASK_API 1
+#else
+#define HAS_BACKGROUND_TASK_API 0
+#endif
+
+#import "encoding_util.h"
+
+#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
+ __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) || \
+ (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
+ defined(MAC_OS_X_VERSION_10_11) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
+#define USE_NSURLSESSION 1
+#else
+#define USE_NSURLSESSION 0
+#endif
+
+// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has
+// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements
+// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is
+// available on iOS 7+.
+static NSData* SendSynchronousNSURLRequest(NSURLRequest* req,
+ NSURLResponse** outResponse,
+ NSError** outError) {
+#if USE_NSURLSESSION
+ __block NSData* result = nil;
+ __block NSError* error = nil;
+ __block NSURLResponse* response = nil;
+ dispatch_semaphore_t waitSemaphone = dispatch_semaphore_create(0);
+
+ NSURLSessionConfiguration* config =
+ [NSURLSessionConfiguration defaultSessionConfiguration];
+ [config setTimeoutIntervalForRequest:240.0];
+ NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
+ NSURLSessionDataTask *task = [session
+ dataTaskWithRequest:req
+ completionHandler:^(NSData* data, NSURLResponse* resp, NSError* err) {
+ if (outError)
+ error = [err retain];
+ if (outResponse)
+ response = [resp retain];
+ if (err == nil)
+ result = [data retain];
+ dispatch_semaphore_signal(waitSemaphone);
+ }];
+ [task resume];
+
+#if HAS_BACKGROUND_TASK_API
+ // Used to guard against ending the background task twice, which UIKit
+ // considers to be an error.
+ __block BOOL isBackgroundTaskActive = YES;
+ __block UIBackgroundTaskIdentifier backgroundTaskIdentifier =
+ UIBackgroundTaskInvalid;
+ backgroundTaskIdentifier = [UIApplication.sharedApplication
+ beginBackgroundTaskWithName:@"Breakpad Upload"
+ expirationHandler:^{
+ if (!isBackgroundTaskActive) {
+ return;
+ }
+ isBackgroundTaskActive = NO;
+
+ [task cancel];
+ [UIApplication.sharedApplication
+ endBackgroundTask:backgroundTaskIdentifier];
+ }];
+#endif // HAS_BACKGROUND_TASK_API
+
+ dispatch_semaphore_wait(waitSemaphone, DISPATCH_TIME_FOREVER);
+ dispatch_release(waitSemaphone);
+
+#if HAS_BACKGROUND_TASK_API
+ if (backgroundTaskIdentifier != UIBackgroundTaskInvalid) {
+ // Dispatch to main queue in order to synchronize access to
+ // `isBackgroundTaskActive` with the background task expiration handler,
+ // which is always run on the main thread.
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (!isBackgroundTaskActive) {
+ return;
+ }
+ isBackgroundTaskActive = NO;
+
+ [UIApplication.sharedApplication
+ endBackgroundTask:backgroundTaskIdentifier];
+ });
+ }
+#endif // HAS_BACKGROUND_TASK_API
+
+ if (outError)
+ *outError = [error autorelease];
+ if (outResponse)
+ *outResponse = [response autorelease];
+ return [result autorelease];
+#else // USE_NSURLSESSION
+ return [NSURLConnection sendSynchronousRequest:req
+ returningResponse:outResponse
+ error:outError];
+#endif // USE_NSURLSESSION
+}
+
+@implementation HTTPRequest
+
+//=============================================================================
+- (id)initWithURL:(NSURL*)URL {
+ if ((self = [super init])) {
+ URL_ = [URL copy];
+ }
+
+ return self;
+}
+
+//=============================================================================
+- (void)dealloc {
+ [URL_ release];
+ [response_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (NSURL*)URL {
+ return URL_;
+}
+
+//=============================================================================
+- (NSHTTPURLResponse*)response {
+ return response_;
+}
+
+//=============================================================================
+- (NSString*)HTTPMethod {
+ @throw [NSException
+ exceptionWithName:NSInternalInconsistencyException
+ reason:[NSString stringWithFormat:@"You must"
+ "override %@ in a subclass",
+ NSStringFromSelector(_cmd)]
+ userInfo:nil];
+}
+
+//=============================================================================
+- (NSString*)contentType {
+ return nil;
+}
+
+//=============================================================================
+- (NSData*)bodyData {
+ return nil;
+}
+
+//=============================================================================
+- (NSData*)send:(NSError**)withError {
+ NSMutableURLRequest* req = [[NSMutableURLRequest alloc]
+ initWithURL:URL_
+ cachePolicy:NSURLRequestUseProtocolCachePolicy
+ timeoutInterval:60.0];
+
+ NSString* contentType = [self contentType];
+ if ([contentType length] > 0) {
+ [req setValue:contentType forHTTPHeaderField:@"Content-type"];
+ }
+
+ NSData* bodyData = [self bodyData];
+ if ([bodyData length] > 0) {
+ [req setHTTPBody:bodyData];
+ }
+
+ [req setHTTPMethod:[self HTTPMethod]];
+
+ [response_ release];
+ response_ = nil;
+
+ NSData* data = nil;
+ if ([[req URL] isFileURL]) {
+ [[req HTTPBody] writeToURL:[req URL] options:0 error:withError];
+ } else {
+ NSURLResponse* response = nil;
+ data = SendSynchronousNSURLRequest(req, &response, withError);
+ response_ = (NSHTTPURLResponse*)[response retain];
+ }
+ [req release];
+
+ return data;
+}
+
+//=============================================================================
++ (NSData*)formDataForFileContents:(NSData*)contents withName:(NSString*)name {
+ NSMutableData* data = [NSMutableData data];
+ NSString* escaped = PercentEncodeNSString(name);
+ NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"; "
+ "filename=\"minidump.dmp\"\r\nContent-Type: "
+ "application/octet-stream\r\n\r\n";
+ NSString* pre = [NSString stringWithFormat:fmt, escaped];
+
+ [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
+ [data appendData:contents];
+
+ return data;
+}
+
+//=============================================================================
++ (NSData*)formDataForFile:(NSString*)file withName:(NSString*)name {
+ NSData* contents = [NSData dataWithContentsOfFile:file];
+
+ return [HTTPRequest formDataForFileContents:contents withName:name];
+}
+
+//=============================================================================
++ (NSData*)formDataForKey:(NSString*)key value:(NSString*)value {
+ NSString* escaped = PercentEncodeNSString(key);
+ NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
+ NSString* form = [NSString stringWithFormat:fmt, escaped, value];
+
+ return [form dataUsingEncoding:NSUTF8StringEncoding];
+}
+
+//=============================================================================
++ (void)appendFileToBodyData:(NSMutableData*)data
+ withName:(NSString*)name
+ withFileOrData:(id)fileOrData {
+ NSData* fileData;
+
+ // The object can be either the path to a file (NSString) or the contents
+ // of the file (NSData).
+ if ([fileOrData isKindOfClass:[NSData class]])
+ fileData = [self formDataForFileContents:fileOrData withName:name];
+ else
+ fileData = [HTTPRequest formDataForFile:fileOrData withName:name];
+
+ [data appendData:fileData];
+}
+
+@end
diff --git a/src/common/mac/HTTPSimplePostRequest.h b/src/common/mac/HTTPSimplePostRequest.h
new file mode 100644
index 00000000..01a1e868
--- /dev/null
+++ b/src/common/mac/HTTPSimplePostRequest.h
@@ -0,0 +1,56 @@
+// Copyright 2020 Google LLC
+//
+// 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 LLC 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.
+
+#import <Foundation/Foundation.h>
+
+#import "HTTPRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a simple (non-multipart) HTTP POST request.
+ */
+@interface HTTPSimplePostRequest : HTTPRequest {
+ @protected
+ NSString* contentType_;
+ NSString* body_;
+}
+
+/**
+ Sets the content type of the POST request.
+ */
+- (void)setContentType:(NSString*)contentType;
+
+/**
+ Sets the contents of the POST request's body.
+ */
+- (void)setBody:(NSString*)body;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/HTTPSimplePostRequest.m b/src/common/mac/HTTPSimplePostRequest.m
new file mode 100644
index 00000000..7aba94fd
--- /dev/null
+++ b/src/common/mac/HTTPSimplePostRequest.m
@@ -0,0 +1,68 @@
+// Copyright 2020 Google LLC
+//
+// 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 LLC 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.
+
+#import "HTTPSimplePostRequest.h"
+
+@implementation HTTPSimplePostRequest
+
+//=============================================================================
+- (void)dealloc {
+ [contentType_ release];
+ [body_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (void)setContentType:(NSString*)contentType {
+ contentType_ = [contentType copy];
+}
+
+//=============================================================================
+- (void)setBody:(NSString*)body {
+ body_ = [body copy];
+}
+
+//=============================================================================
+- (NSString*)HTTPMethod {
+ return @"POST";
+}
+
+//=============================================================================
+- (NSString*)contentType {
+ return contentType_;
+}
+
+//=============================================================================
+- (NSData*)bodyData {
+ NSMutableData* data = [NSMutableData data];
+ [data appendData:[body_ dataUsingEncoding:NSUTF8StringEncoding]];
+ return data;
+}
+
+@end
diff --git a/src/common/mac/MachIPC.h b/src/common/mac/MachIPC.h
index 71419be9..78b97ad9 100644
--- a/src/common/mac/MachIPC.h
+++ b/src/common/mac/MachIPC.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -73,7 +72,7 @@
// mach_port_t task = message.GetTranslatedPort(0);
// mach_port_t thread = message.GetTranslatedPort(1);
//
-// char *messageString = message.GetData();
+// char* messageString = message.GetData();
//
// printf("message string = %s\n", messageString);
// }
@@ -164,7 +163,7 @@ class MachMessage {
public:
// The receiver of the message can retrieve the raw data this way
- uint8_t *GetData() {
+ uint8_t* GetData() {
return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
}
@@ -181,10 +180,10 @@ class MachMessage {
// Adds a descriptor (typically a mach port) to be translated
// returns true if successful, otherwise not enough space
- bool AddDescriptor(const MachMsgPortDescriptor &desc);
+ bool AddDescriptor(const MachMsgPortDescriptor& desc);
int GetDescriptorCount() const { return body.msgh_descriptor_count; }
- MachMsgPortDescriptor *GetDescriptor(int n);
+ MachMsgPortDescriptor* GetDescriptor(int n);
// Convenience method which gets the mach port described by the descriptor
mach_port_t GetTranslatedPort(int n);
@@ -193,7 +192,7 @@ class MachMessage {
bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
// Sets raw data for the message (returns false if not enough space)
- bool SetData(void *data, int32_t data_length);
+ bool SetData(void* data, int32_t data_length);
protected:
// Consider this an abstract base class - must create an actual instance
@@ -216,7 +215,7 @@ class MachMessage {
MessageDataPacket* GetDataPacket();
void SetDescriptorCount(int n);
- void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
+ void SetDescriptor(int n, const MachMsgPortDescriptor& desc);
// Returns total message size setting msgh_size in the header to this value
mach_msg_size_t CalculateSize();
@@ -250,7 +249,7 @@ class MachSendMessage : public MachMessage {
class ReceivePort {
public:
// Creates a new mach port for receiving messages and registers a name for it
- explicit ReceivePort(const char *receive_port_name);
+ explicit ReceivePort(const char* receive_port_name);
// Given an already existing mach port, use it. We take ownership of the
// port and deallocate it in our destructor.
@@ -262,7 +261,7 @@ class ReceivePort {
~ReceivePort();
// Waits on the mach port until message received or timeout
- kern_return_t WaitForMessage(MachReceiveMessage *out_message,
+ kern_return_t WaitForMessage(MachReceiveMessage* out_message,
mach_msg_timeout_t timeout);
// The underlying mach port that we wrap
@@ -280,13 +279,13 @@ class ReceivePort {
class MachPortSender {
public:
// get a port with send rights corresponding to a named registered service
- explicit MachPortSender(const char *receive_port_name);
+ explicit MachPortSender(const char* receive_port_name);
// Given an already existing mach port, use it.
explicit MachPortSender(mach_port_t send_port);
- kern_return_t SendMessage(MachSendMessage &message,
+ kern_return_t SendMessage(MachSendMessage& message,
mach_msg_timeout_t timeout);
private:
diff --git a/src/common/mac/MachIPC.mm b/src/common/mac/MachIPC.mm
index dc9773f7..62e0f6b5 100644
--- a/src/common/mac/MachIPC.mm
+++ b/src/common/mac/MachIPC.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -52,7 +51,7 @@ MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
//==============================================================================
// returns true if successful
-bool MachMessage::SetData(void *data,
+bool MachMessage::SetData(void* data,
int32_t data_length) {
// first check to make sure we have enough space
size_t size = CalculateSize();
@@ -90,9 +89,9 @@ mach_msg_size_t MachMessage::CalculateSize() {
}
//==============================================================================
-MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
+MachMessage::MessageDataPacket* MachMessage::GetDataPacket() {
size_t desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
- MessageDataPacket *packet =
+ MessageDataPacket* packet =
reinterpret_cast<MessageDataPacket*>(padding + desc_size);
return packet;
@@ -100,15 +99,15 @@ MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
//==============================================================================
void MachMessage::SetDescriptor(int n,
- const MachMsgPortDescriptor &desc) {
- MachMsgPortDescriptor *desc_array =
+ const MachMsgPortDescriptor& desc) {
+ MachMsgPortDescriptor* desc_array =
reinterpret_cast<MachMsgPortDescriptor*>(padding);
desc_array[n] = desc;
}
//==============================================================================
// returns true if successful otherwise there was not enough space
-bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
+bool MachMessage::AddDescriptor(const MachMsgPortDescriptor& desc) {
// first check to make sure we have enough space
int size = CalculateSize();
size_t new_size = size + sizeof(MachMsgPortDescriptor);
@@ -119,7 +118,7 @@ bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
// unfortunately, we need to move the data to allow space for the
// new descriptor
- u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
+ u_int8_t* p = reinterpret_cast<u_int8_t*>(GetDataPacket());
bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
SetDescriptor(GetDescriptorCount(), desc);
@@ -142,9 +141,9 @@ void MachMessage::SetDescriptorCount(int n) {
}
//==============================================================================
-MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
+MachMsgPortDescriptor* MachMessage::GetDescriptor(int n) {
if (n < GetDescriptorCount()) {
- MachMsgPortDescriptor *desc =
+ MachMsgPortDescriptor* desc =
reinterpret_cast<MachMsgPortDescriptor*>(padding);
return desc + n;
}
@@ -164,7 +163,7 @@ mach_port_t MachMessage::GetTranslatedPort(int n) {
//==============================================================================
// create a new mach port for receiving messages and register a name for it
-ReceivePort::ReceivePort(const char *receive_port_name) {
+ReceivePort::ReceivePort(const char* receive_port_name) {
mach_port_t current_task = mach_task_self();
init_result_ = mach_port_allocate(current_task,
@@ -227,7 +226,7 @@ ReceivePort::~ReceivePort() {
}
//==============================================================================
-kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
+kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage* out_message,
mach_msg_timeout_t timeout) {
if (!out_message) {
return KERN_INVALID_ARGUMENT;
@@ -261,7 +260,7 @@ kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
//==============================================================================
// get a port with send rights corresponding to a named registered service
-MachPortSender::MachPortSender(const char *receive_port_name) {
+MachPortSender::MachPortSender(const char* receive_port_name) {
mach_port_t task_bootstrap_port = 0;
init_result_ = task_get_bootstrap_port(mach_task_self(),
&task_bootstrap_port);
@@ -281,7 +280,7 @@ MachPortSender::MachPortSender(mach_port_t send_port)
}
//==============================================================================
-kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
+kern_return_t MachPortSender::SendMessage(MachSendMessage& message,
mach_msg_timeout_t timeout) {
if (message.head.msgh_size == 0) {
return KERN_INVALID_VALUE; // just for safety -- never should occur
diff --git a/src/common/mac/SymbolCollectorClient.h b/src/common/mac/SymbolCollectorClient.h
new file mode 100644
index 00000000..367753a4
--- /dev/null
+++ b/src/common/mac/SymbolCollectorClient.h
@@ -0,0 +1,103 @@
+// Copyright 2020 Google LLC
+//
+// 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 LLC 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.
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a response from a sym-upload-v2 server to a createUploadURLOnServer
+ call.
+ */
+@interface UploadURLResponse : NSObject {
+ @protected
+ NSString* uploadURL_;
+ NSString* uploadKey_;
+}
+
+- (id)initWithUploadURL:(NSString*)uploadURL withUploadKey:(NSString*)uploadKey;
+
+- (NSString*)uploadURL;
+- (NSString*)uploadKey;
+@end
+
+/**
+ Possible return statuses from a sym-upload-v2 server to a
+ completeUploadOnServer call.
+ */
+typedef NS_ENUM(NSInteger, CompleteUploadResult) {
+ CompleteUploadResultOk,
+ CompleteUploadResultDuplicateData,
+ CompleteUploadResultError
+};
+
+/**
+ Possible return statuses from a sym-upload-v2 server to a
+ checkSymbolStatusOnServer call.
+ */
+typedef NS_ENUM(NSInteger, SymbolStatus) {
+ SymbolStatusFound,
+ SymbolStatusMissing,
+ SymbolStatusUnknown
+};
+
+/**
+ Interface to help a client interact with a sym-upload-v2 server, over HTTP.
+ For details of the API and protocol, see :/docs/sym_upload_v2_protocol.md.
+ */
+@interface SymbolCollectorClient : NSObject
+;
+
+/**
+ Calls the /v1/symbols/{debug_file}/{debug_id}:checkStatus API on the server.
+ */
++ (SymbolStatus)checkSymbolStatusOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID;
+
+/**
+ Calls the /v1/uploads:create API on the server.
+ */
++ (UploadURLResponse*)createUploadURLOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey;
+
+/**
+ Calls the /v1/uploads/{key}:complete API on the server.
+ */
++ (CompleteUploadResult)completeUploadOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withUploadKey:(NSString*)uploadKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID
+ withType:(NSString*)type
+ withProductName:(NSString*)productName;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/SymbolCollectorClient.m b/src/common/mac/SymbolCollectorClient.m
new file mode 100644
index 00000000..fd33432b
--- /dev/null
+++ b/src/common/mac/SymbolCollectorClient.m
@@ -0,0 +1,271 @@
+// Copyright 2020 Google LLC
+//
+// 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 LLC 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.
+
+#import "SymbolCollectorClient.h"
+
+#import "HTTPGetRequest.h"
+#import "HTTPSimplePostRequest.h"
+
+@implementation UploadURLResponse
+
+//=============================================================================
+- (id)initWithUploadURL:(NSString*)uploadURL
+ withUploadKey:(NSString*)uploadKey {
+ if (self = [super init]) {
+ uploadURL_ = [uploadURL copy];
+ uploadKey_ = [uploadKey copy];
+ }
+ return self;
+}
+
+//=============================================================================
+- (void)dealloc {
+ [uploadURL_ release];
+ [uploadKey_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (NSString*)uploadURL {
+ return uploadURL_;
+}
+
+//=============================================================================
+- (NSString*)uploadKey {
+ return uploadKey_;
+}
+@end
+
+@implementation SymbolCollectorClient
+
+//=============================================================================
++ (SymbolStatus)checkSymbolStatusOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID {
+ // Note that forward-slash is listed as a character to escape here, for
+ // completeness, however it is illegal in a debugFile input.
+ NSMutableCharacterSet* allowedDebugFileCharacters = [NSMutableCharacterSet
+ characterSetWithCharactersInString:@" \"\\/#%:?@|^`{}<>[]&=;"];
+ [allowedDebugFileCharacters
+ formUnionWithCharacterSet:[NSCharacterSet controlCharacterSet]];
+ [allowedDebugFileCharacters invert];
+ NSString* escapedDebugFile =
+ [debugFile stringByAddingPercentEncodingWithAllowedCharacters:
+ allowedDebugFileCharacters];
+
+ NSURL* URL = [NSURL
+ URLWithString:[NSString
+ stringWithFormat:@"%@/v1/symbols/%@/%@:checkStatus"
+ @"?key=%@",
+ APIURL, escapedDebugFile, debugID,
+ APIKey]];
+
+ HTTPGetRequest* getRequest = [[HTTPGetRequest alloc] initWithURL:URL];
+ NSError* error = nil;
+ NSData* data = [getRequest send:&error];
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ int responseCode = [[getRequest response] statusCode];
+ [getRequest release];
+
+ if (error || responseCode != 200) {
+ fprintf(stdout, "Failed to check symbol status.\n");
+ fprintf(stdout, "Response code: %d\n", responseCode);
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return SymbolStatusUnknown;
+ }
+
+ error = nil;
+ NSRegularExpression* statusRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"\"status\": \"([^\"]+)\""
+ options:0
+ error:&error];
+ NSArray* matches =
+ [statusRegex matchesInString:result
+ options:0
+ range:NSMakeRange(0, [result length])];
+ if ([matches count] != 1) {
+ fprintf(stdout, "Failed to parse check symbol status response.");
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return SymbolStatusUnknown;
+ }
+
+ NSString* status = [result substringWithRange:[matches[0] rangeAtIndex:1]];
+ [result release];
+
+ return [status isEqualToString:@"FOUND"] ? SymbolStatusFound
+ : SymbolStatusMissing;
+}
+
+//=============================================================================
++ (UploadURLResponse*)createUploadURLOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey {
+ NSURL* URL = [NSURL
+ URLWithString:[NSString stringWithFormat:@"%@/v1/uploads:create?key=%@",
+ APIURL, APIKey]];
+
+ HTTPSimplePostRequest* postRequest =
+ [[HTTPSimplePostRequest alloc] initWithURL:URL];
+ NSError* error = nil;
+ NSData* data = [postRequest send:&error];
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ int responseCode = [[postRequest response] statusCode];
+ [postRequest release];
+
+ if (error || responseCode != 200) {
+ fprintf(stdout, "Failed to create upload URL.\n");
+ fprintf(stdout, "Response code: %d\n", responseCode);
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return nil;
+ }
+
+ // Note camel-case rather than underscores.
+ NSRegularExpression* uploadURLRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"\"uploadUrl\": \"([^\"]+)\""
+ options:0
+ error:&error];
+ NSRegularExpression* uploadKeyRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"\"uploadKey\": \"([^\"]+)\""
+ options:0
+ error:&error];
+
+ NSArray* uploadURLMatches =
+ [uploadURLRegex matchesInString:result
+ options:0
+ range:NSMakeRange(0, [result length])];
+ NSArray* uploadKeyMatches =
+ [uploadKeyRegex matchesInString:result
+ options:0
+ range:NSMakeRange(0, [result length])];
+ if ([uploadURLMatches count] != 1 || [uploadKeyMatches count] != 1) {
+ fprintf(stdout, "Failed to parse create url response.");
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return nil;
+ }
+ NSString* uploadURL =
+ [result substringWithRange:[uploadURLMatches[0] rangeAtIndex:1]];
+ NSString* uploadKey =
+ [result substringWithRange:[uploadKeyMatches[0] rangeAtIndex:1]];
+
+ return [[UploadURLResponse alloc] initWithUploadURL:uploadURL
+ withUploadKey:uploadKey];
+}
+
+//=============================================================================
++ (CompleteUploadResult)completeUploadOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withUploadKey:(NSString*)uploadKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID
+ withType:(NSString*)type
+ withProductName:(NSString*)productName {
+ NSURL* URL = [NSURL
+ URLWithString:[NSString
+ stringWithFormat:@"%@/v1/uploads/%@:complete?key=%@",
+ APIURL, uploadKey, APIKey]];
+
+ NSMutableDictionary* jsonDictionary = [@{
+ @"symbol_id" : @{@"debug_file" : debugFile, @"debug_id" : debugID},
+ @"symbol_upload_type" : type, @"use_async_processing" : @"true"
+ } mutableCopy];
+
+ if (productName != nil) {
+ jsonDictionary[@"metadata"] = @{@"product_name": productName};
+ }
+
+ NSError* error = nil;
+ NSData* jsonData =
+ [NSJSONSerialization dataWithJSONObject:jsonDictionary
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+ if (jsonData == nil) {
+ fprintf(stdout, "Error: %s\n", [[error localizedDescription] UTF8String]);
+ fprintf(stdout,
+ "Failed to complete upload. Could not write JSON payload.\n");
+ return CompleteUploadResultError;
+ }
+
+ NSString* body = [[NSString alloc] initWithData:jsonData
+ encoding:NSUTF8StringEncoding];
+ HTTPSimplePostRequest* postRequest =
+ [[HTTPSimplePostRequest alloc] initWithURL:URL];
+ [postRequest setBody:body];
+ [postRequest setContentType:@"application/json"];
+
+ NSData* data = [postRequest send:&error];
+ if (data == nil) {
+ fprintf(stdout, "Error: %s\n", [[error localizedDescription] UTF8String]);
+ fprintf(stdout, "Failed to complete upload URL.\n");
+ return CompleteUploadResultError;
+ }
+
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ int responseCode = [[postRequest response] statusCode];
+ [postRequest release];
+ if (responseCode != 200) {
+ fprintf(stdout, "Failed to complete upload URL.\n");
+ fprintf(stdout, "Response code: %d\n", responseCode);
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return CompleteUploadResultError;
+ }
+
+ // Note camel-case rather than underscores.
+ NSRegularExpression* completeResultRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"\"result\": \"([^\"]+)\""
+ options:0
+ error:&error];
+
+ NSArray* completeResultMatches =
+ [completeResultRegex matchesInString:result
+ options:0
+ range:NSMakeRange(0, [result length])];
+
+ if ([completeResultMatches count] != 1) {
+ fprintf(stdout, "Failed to parse complete upload response.");
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return CompleteUploadResultError;
+ }
+ NSString* completeResult =
+ [result substringWithRange:[completeResultMatches[0] rangeAtIndex:1]];
+ [result release];
+
+ return ([completeResult isEqualToString:@"DUPLICATE_DATA"])
+ ? CompleteUploadResultDuplicateData
+ : CompleteUploadResultOk;
+}
+@end
diff --git a/src/common/mac/arch_utilities.cc b/src/common/mac/arch_utilities.cc
index c0e4bac5..392efe78 100644
--- a/src/common/mac/arch_utilities.cc
+++ b/src/common/mac/arch_utilities.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -130,7 +129,10 @@ const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type,
} // namespace google_breakpad
-#ifndef __APPLE__
+// TODO(crbug.com/1242776): The "#ifndef __APPLE__" should be here, but the
+// system version of NXGetLocalArchInfo returns incorrect information on
+// x86_64 machines (treating them as just x86), so use the Breakpad version
+// all the time for now.
namespace {
enum Architecture {
@@ -219,6 +221,8 @@ const NXArchInfo *NXGetLocalArchInfo(void) {
return &kKnownArchitectures[arch];
}
+#ifndef __APPLE__
+
const NXArchInfo *NXGetArchInfoFromName(const char *name) {
for (int arch = 0; arch < kNumArchitectures; ++arch) {
if (!strcmp(name, kKnownArchitectures[arch].name)) {
diff --git a/src/common/mac/arch_utilities.h b/src/common/mac/arch_utilities.h
index 397c1f58..d267c43b 100644
--- a/src/common/mac/arch_utilities.h
+++ b/src/common/mac/arch_utilities.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/bootstrap_compat.cc b/src/common/mac/bootstrap_compat.cc
index d875d95b..6647bae3 100644
--- a/src/common/mac/bootstrap_compat.cc
+++ b/src/common/mac/bootstrap_compat.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/bootstrap_compat.h b/src/common/mac/bootstrap_compat.h
index 8ca7357c..b57d9070 100644
--- a/src/common/mac/bootstrap_compat.h
+++ b/src/common/mac/bootstrap_compat.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/byteswap.h b/src/common/mac/byteswap.h
index b7bbc0b9..c4c7e617 100644
--- a/src/common/mac/byteswap.h
+++ b/src/common/mac/byteswap.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/dump_syms.cc b/src/common/mac/dump_syms.cc
index 3fbedd95..9658b2c6 100644
--- a/src/common/mac/dump_syms.cc
+++ b/src/common/mac/dump_syms.cc
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -74,12 +73,12 @@
#define CPU_TYPE_ARM64 (static_cast<cpu_type_t>(16777228))
#endif // CPU_TYPE_ARM64
-using dwarf2reader::ByteReader;
+using google_breakpad::ByteReader;
using google_breakpad::DwarfCUToModule;
using google_breakpad::DwarfLineToModule;
using google_breakpad::DwarfRangeListHandler;
-using google_breakpad::FileID;
using google_breakpad::mach_o::FatReader;
+using google_breakpad::mach_o::FileID;
using google_breakpad::mach_o::Section;
using google_breakpad::mach_o::Segment;
using google_breakpad::Module;
@@ -120,7 +119,8 @@ vector<string> list_directory(const string& directory) {
namespace google_breakpad {
-bool DumpSymbols::Read(const string &filename) {
+bool DumpSymbols::Read(const string& filename) {
+ selected_object_file_ = nullptr;
struct stat st;
if (stat(filename.c_str(), &st) == -1) {
fprintf(stderr, "Could not access object file %s: %s\n",
@@ -128,10 +128,11 @@ bool DumpSymbols::Read(const string &filename) {
return false;
}
- input_pathname_ = filename;
+ from_disk_ = true;
// Does this filename refer to a dSYM bundle?
- string contents_path = input_pathname_ + "/Contents/Resources/DWARF";
+ string contents_path = filename + "/Contents/Resources/DWARF";
+ string object_filename;
if (S_ISDIR(st.st_mode) &&
access(contents_path.c_str(), F_OK) == 0) {
// If there's one file under Contents/Resources/DWARF then use that,
@@ -139,30 +140,31 @@ bool DumpSymbols::Read(const string &filename) {
const vector<string> entries = list_directory(contents_path);
if (entries.size() == 0) {
fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
- input_pathname_.c_str());
+ filename.c_str());
return false;
}
if (entries.size() > 1) {
fprintf(stderr, "Too many DWARF files in bundle: %s\n",
- input_pathname_.c_str());
+ filename.c_str());
return false;
}
- object_filename_ = entries[0];
+ object_filename = entries[0];
} else {
- object_filename_ = input_pathname_;
+ object_filename = filename;
}
// Read the file's contents into memory.
bool read_ok = true;
string error;
- if (stat(object_filename_.c_str(), &st) != -1) {
- FILE* f = fopen(object_filename_.c_str(), "rb");
+ scoped_array<uint8_t> contents;
+ off_t total = 0;
+ if (stat(object_filename.c_str(), &st) != -1) {
+ FILE* f = fopen(object_filename.c_str(), "rb");
if (f) {
- contents_.reset(new uint8_t[st.st_size]);
- off_t total = 0;
+ contents.reset(new uint8_t[st.st_size]);
while (total < st.st_size && !feof(f)) {
- size_t read = fread(&contents_[0] + total, 1, st.st_size - total, f);
+ size_t read = fread(&contents[0] + total, 1, st.st_size - total, f);
if (read == 0) {
if (ferror(f)) {
read_ok = false;
@@ -180,22 +182,28 @@ bool DumpSymbols::Read(const string &filename) {
if (!read_ok) {
fprintf(stderr, "Error reading object file: %s: %s\n",
- object_filename_.c_str(),
- error.c_str());
+ object_filename.c_str(), error.c_str());
return false;
}
+ return ReadData(contents.release(), total, object_filename);
+}
+
+bool DumpSymbols::ReadData(uint8_t* contents, size_t size,
+ const std::string& filename) {
+ contents_.reset(contents);
+ size_ = size;
+ object_filename_ = filename;
// Get the list of object files present in the file.
FatReader::Reporter fat_reporter(object_filename_);
FatReader fat_reader(&fat_reporter);
- if (!fat_reader.Read(&contents_[0],
- st.st_size)) {
+ if (!fat_reader.Read(contents_.get(), size)) {
return false;
}
// Get our own copy of fat_reader's object file list.
size_t object_files_count;
- const SuperFatArch *object_files =
+ const SuperFatArch* object_files =
fat_reader.object_files(&object_files_count);
if (object_files_count == 0) {
fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
@@ -212,7 +220,7 @@ bool DumpSymbols::Read(const string &filename) {
bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype) {
// Find the best match for the architecture the user requested.
- const SuperFatArch *best_match = FindBestMatchForArchitecture(
+ const SuperFatArch* best_match = FindBestMatchForArchitecture(
cpu_type, cpu_subtype);
if (!best_match) return false;
@@ -221,9 +229,9 @@ bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
return true;
}
-bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
+bool DumpSymbols::SetArchitecture(const std::string& arch_name) {
bool arch_set = false;
- const NXArchInfo *arch_info =
+ const NXArchInfo* arch_info =
google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str());
if (arch_info) {
arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype);
@@ -251,7 +259,7 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture(
// If all the object files can be converted to struct fat_arch, use
// NXFindBestFatArch.
if (can_convert_to_fat_arch) {
- const struct fat_arch *best_match
+ const struct fat_arch* best_match
= NXFindBestFatArch(cpu_type, cpu_subtype, &fat_arch_vector[0],
static_cast<uint32_t>(fat_arch_vector.size()));
@@ -260,7 +268,8 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture(
return &object_files_[i];
}
assert(best_match == NULL);
- return NULL;
+ // Fall through since NXFindBestFatArch can't find arm slices on x86_64
+ // macOS 13. See FB11955188.
}
// Check for an exact match with cpu_type and cpu_subtype.
@@ -268,7 +277,8 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture(
it != object_files_.end();
++it) {
if (static_cast<cpu_type_t>(it->cputype) == cpu_type &&
- static_cast<cpu_subtype_t>(it->cpusubtype) == cpu_subtype)
+ (static_cast<cpu_subtype_t>(it->cpusubtype) & ~CPU_SUBTYPE_MASK) ==
+ (cpu_subtype & ~CPU_SUBTYPE_MASK))
return &*it;
}
@@ -277,17 +287,31 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture(
// NXFindBestFatArch, located at
// http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c.
fprintf(stderr, "Failed to find an exact match for an object file with cpu "
- "type: %d and cpu subtype: %d. Furthermore, at least one object file is "
- "larger than 2**32.\n", cpu_type, cpu_subtype);
+ "type: %d and cpu subtype: %d.\n", cpu_type, cpu_subtype);
+ if (!can_convert_to_fat_arch) {
+ fprintf(stderr, "Furthermore, at least one object file is larger "
+ "than 2**32.\n");
+ }
return NULL;
}
string DumpSymbols::Identifier() {
- FileID file_id(object_filename_.c_str());
+ scoped_ptr<FileID> file_id;
+
+ if (from_disk_) {
+ file_id.reset(new FileID(object_filename_.c_str()));
+ } else {
+ file_id.reset(new FileID(contents_.get(), size_));
+ }
unsigned char identifier_bytes[16];
+ scoped_ptr<Module> module;
+ if (!selected_object_file_) {
+ if (!CreateEmptyModule(module))
+ return string();
+ }
cpu_type_t cpu_type = selected_object_file_->cputype;
cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype;
- if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) {
+ if (!file_id->MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) {
fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
object_filename_.c_str());
return "";
@@ -302,57 +326,67 @@ string DumpSymbols::Identifier() {
i = compacted.find('-', i))
compacted.erase(i, 1);
+ // The pdb for these IDs has an extra byte, so to make everything uniform put
+ // a 0 on the end of mac IDs.
+ compacted += "0";
+
return compacted;
}
// A range handler that accepts rangelist data parsed by
-// dwarf2reader::RangeListReader and populates a range vector (typically
+// RangeListReader and populates a range vector (typically
// owned by a function) with the results.
class DumpSymbols::DumperRangesHandler:
public DwarfCUToModule::RangesHandler {
public:
- DumperRangesHandler(const uint8_t *buffer, uint64_t size,
- dwarf2reader::ByteReader* reader)
- : buffer_(buffer), size_(size), reader_(reader) { }
-
- bool ReadRanges(uint64_t offset, Module::Address base_address,
- vector<Module::Range>* ranges) {
- DwarfRangeListHandler handler(base_address, ranges);
- dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_,
- &handler);
-
- return rangelist_reader.ReadRangeList(offset);
+ DumperRangesHandler(ByteReader* reader) :
+ reader_(reader) { }
+
+ bool ReadRanges(
+ enum DwarfForm form, uint64_t data,
+ RangeListReader::CURangesInfo* cu_info,
+ vector<Module::Range>* ranges) {
+ DwarfRangeListHandler handler(ranges);
+ RangeListReader range_list_reader(reader_, cu_info,
+ &handler);
+ return range_list_reader.ReadRanges(form, data);
}
private:
- const uint8_t *buffer_;
- uint64_t size_;
- dwarf2reader::ByteReader* reader_;
+ ByteReader* reader_;
};
// A line-to-module loader that accepts line number info parsed by
-// dwarf2reader::LineInfo and populates a Module and a line vector
+// LineInfo and populates a Module and a line vector
// with the results.
class DumpSymbols::DumperLineToModule:
public DwarfCUToModule::LineToModuleHandler {
public:
// Create a line-to-module converter using BYTE_READER.
- DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
+ DumperLineToModule(ByteReader* byte_reader)
: byte_reader_(byte_reader) { }
void StartCompilationUnit(const string& compilation_dir) {
compilation_dir_ = compilation_dir;
}
- void ReadProgram(const uint8_t *program, uint64_t length,
- Module *module, vector<Module::Line> *lines) {
- DwarfLineToModule handler(module, compilation_dir_, lines);
- dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
+ void ReadProgram(const uint8_t* program,
+ uint64_t length,
+ const uint8_t* string_section,
+ uint64_t string_section_length,
+ const uint8_t* line_string_section,
+ uint64_t line_string_section_length,
+ Module* module,
+ vector<Module::Line>* lines,
+ std::map<uint32_t, Module::File*>* files) {
+ DwarfLineToModule handler(module, compilation_dir_, lines, files);
+ LineInfo parser(program, length, byte_reader_, nullptr, 0,
+ nullptr, 0, &handler);
parser.Start();
}
private:
string compilation_dir_;
- dwarf2reader::ByteReader *byte_reader_; // WEAK
+ ByteReader* byte_reader_; // WEAK
};
bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) {
@@ -364,7 +398,7 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) {
selected_object_file_ = &object_files_[0];
else {
// Look for an object file whose architecture matches our own.
- const NXArchInfo *local_arch = NXGetLocalArchInfo();
+ const NXArchInfo* local_arch = NXGetLocalArchInfo();
if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
fprintf(stderr, "%s: object file contains more than one"
" architecture, none of which match the current"
@@ -380,11 +414,18 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) {
// Find the name of the selected file's architecture, to appear in
// the MODULE record and in error messages.
- const NXArchInfo *selected_arch_info =
+ const NXArchInfo* selected_arch_info =
google_breakpad::BreakpadGetArchInfoFromCpuType(
selected_object_file_->cputype, selected_object_file_->cpusubtype);
- const char *selected_arch_name = selected_arch_info->name;
+ // In certain cases, it is possible that architecture info can't be reliably
+ // determined, e.g. new architectures that breakpad is unware of. In that
+ // case, avoid crashing and return false instead.
+ if (selected_arch_info == NULL) {
+ return false;
+ }
+
+ const char* selected_arch_name = selected_arch_info->name;
if (strcmp(selected_arch_name, "i386") == 0)
selected_arch_name = "x86";
@@ -403,31 +444,28 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) {
string identifier = Identifier();
if (identifier.empty())
return false;
- identifier += "0";
// Create a module to hold the debugging information.
- module.reset(new Module(module_name,
- "mac",
- selected_arch_name,
- identifier));
+ module.reset(new Module(module_name, "mac", selected_arch_name, identifier,
+ "", enable_multiple_));
return true;
}
-void DumpSymbols::ReadDwarf(google_breakpad::Module *module,
- const mach_o::Reader &macho_reader,
- const mach_o::SectionMap &dwarf_sections,
+void DumpSymbols::ReadDwarf(google_breakpad::Module* module,
+ const mach_o::Reader& macho_reader,
+ const mach_o::SectionMap& dwarf_sections,
bool handle_inter_cu_refs) const {
// Build a byte reader of the appropriate endianness.
ByteReader byte_reader(macho_reader.big_endian()
- ? dwarf2reader::ENDIANNESS_BIG
- : dwarf2reader::ENDIANNESS_LITTLE);
+ ? ENDIANNESS_BIG
+ : ENDIANNESS_LITTLE);
// Construct a context for this file.
DwarfCUToModule::FileContext file_context(selected_object_name_,
module,
handle_inter_cu_refs);
- // Build a dwarf2reader::SectionMap from our mach_o::SectionMap.
+ // Build a SectionMap from our mach_o::SectionMap.
for (mach_o::SectionMap::const_iterator it = dwarf_sections.begin();
it != dwarf_sections.end(); ++it) {
file_context.AddSectionToSectionMap(
@@ -437,7 +475,7 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module *module,
}
// Find the __debug_info section.
- dwarf2reader::SectionMap::const_iterator debug_info_entry =
+ SectionMap::const_iterator debug_info_entry =
file_context.section_map().find("__debug_info");
// There had better be a __debug_info section!
if (debug_info_entry == file_context.section_map().end()) {
@@ -451,17 +489,8 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module *module,
// Build a line-to-module loader for the root handler to use.
DumperLineToModule line_to_module(&byte_reader);
- // Optional .debug_ranges reader
- scoped_ptr<DumperRangesHandler> ranges_handler;
- dwarf2reader::SectionMap::const_iterator ranges_entry =
- file_context.section_map().find("__debug_ranges");
- if (ranges_entry != file_context.section_map().end()) {
- const std::pair<const uint8_t *, uint64_t>& ranges_section =
- ranges_entry->second;
- ranges_handler.reset(
- new DumperRangesHandler(ranges_section.first, ranges_section.second,
- &byte_reader));
- }
+ // .debug_ranges and .debug_rngslists reader
+ DumperRangesHandler ranges_handler(&byte_reader);
// Walk the __debug_info section, one compilation unit at a time.
uint64_t debug_info_length = debug_info_section.second;
@@ -471,11 +500,12 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module *module,
DwarfCUToModule::WarningReporter reporter(selected_object_name_,
offset);
DwarfCUToModule root_handler(&file_context, &line_to_module,
- ranges_handler.get(), &reporter);
+ &ranges_handler, &reporter,
+ symbol_data_ & INLINES);
// Make a Dwarf2Handler that drives our DIEHandler.
- dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
+ DIEDispatcher die_dispatcher(&root_handler);
// Make a DWARF parser for the compilation unit at OFFSET.
- dwarf2reader::CompilationUnit dwarf_reader(selected_object_name_,
+ CompilationUnit dwarf_reader(selected_object_name_,
file_context.section_map(),
offset,
&byte_reader,
@@ -485,9 +515,9 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module *module,
}
}
-bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
- const mach_o::Reader &macho_reader,
- const mach_o::Section &section,
+bool DumpSymbols::ReadCFI(google_breakpad::Module* module,
+ const mach_o::Reader& macho_reader,
+ const mach_o::Section& section,
bool eh_frame) const {
// Find the appropriate set of register names for this file's
// architecture.
@@ -506,7 +536,7 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
register_names = DwarfCFIToModule::RegisterNames::ARM64();
break;
default: {
- const NXArchInfo *arch = google_breakpad::BreakpadGetArchInfoFromCpuType(
+ const NXArchInfo* arch = google_breakpad::BreakpadGetArchInfoFromCpuType(
macho_reader.cpu_type(), macho_reader.cpu_subtype());
fprintf(stderr, "%s: cannot convert DWARF call frame information for ",
selected_object_name_.c_str());
@@ -521,25 +551,25 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
}
// Find the call frame information and its size.
- const uint8_t *cfi = section.contents.start;
+ const uint8_t* cfi = section.contents.start;
size_t cfi_size = section.contents.Size();
// Plug together the parser, handler, and their entourages.
DwarfCFIToModule::Reporter module_reporter(selected_object_name_,
section.section_name);
DwarfCFIToModule handler(module, register_names, &module_reporter);
- dwarf2reader::ByteReader byte_reader(macho_reader.big_endian() ?
- dwarf2reader::ENDIANNESS_BIG :
- dwarf2reader::ENDIANNESS_LITTLE);
+ ByteReader byte_reader(macho_reader.big_endian() ?
+ ENDIANNESS_BIG :
+ ENDIANNESS_LITTLE);
byte_reader.SetAddressSize(macho_reader.bits_64() ? 8 : 4);
// At the moment, according to folks at Apple and some cursory
// investigation, Mac OS X only uses DW_EH_PE_pcrel-based pointers, so
// this is the only base address the CFI parser will need.
byte_reader.SetCFIDataBase(section.address, cfi);
- dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(selected_object_name_,
+ CallFrameInfo::Reporter dwarf_reporter(selected_object_name_,
section.section_name);
- dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
+ CallFrameInfo parser(cfi, cfi_size,
&byte_reader, &handler, &dwarf_reporter,
eh_frame);
parser.Start();
@@ -553,9 +583,9 @@ class DumpSymbols::LoadCommandDumper:
public:
// Create a load command dumper handling load commands from READER's
// file, and adding data to MODULE.
- LoadCommandDumper(const DumpSymbols &dumper,
- google_breakpad::Module *module,
- const mach_o::Reader &reader,
+ LoadCommandDumper(const DumpSymbols& dumper,
+ google_breakpad::Module* module,
+ const mach_o::Reader& reader,
SymbolData symbol_data,
bool handle_inter_cu_refs)
: dumper_(dumper),
@@ -564,25 +594,25 @@ class DumpSymbols::LoadCommandDumper:
symbol_data_(symbol_data),
handle_inter_cu_refs_(handle_inter_cu_refs) { }
- bool SegmentCommand(const mach_o::Segment &segment);
- bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings);
+ bool SegmentCommand(const mach_o::Segment& segment);
+ bool SymtabCommand(const ByteBuffer& entries, const ByteBuffer& strings);
private:
- const DumpSymbols &dumper_;
- google_breakpad::Module *module_; // WEAK
- const mach_o::Reader &reader_;
+ const DumpSymbols& dumper_;
+ google_breakpad::Module* module_; // WEAK
+ const mach_o::Reader& reader_;
const SymbolData symbol_data_;
const bool handle_inter_cu_refs_;
};
-bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
+bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment& segment) {
mach_o::SectionMap section_map;
if (!reader_.MapSegmentSections(segment, &section_map))
return false;
if (segment.name == "__TEXT") {
module_->SetLoadAddress(segment.vmaddr);
- if (symbol_data_ != NO_CFI) {
+ if (symbol_data_ & CFI) {
mach_o::SectionMap::const_iterator eh_frame =
section_map.find("__eh_frame");
if (eh_frame != section_map.end()) {
@@ -594,10 +624,10 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
}
if (segment.name == "__DWARF") {
- if (symbol_data_ != ONLY_CFI) {
+ if ((symbol_data_ & SYMBOLS_AND_FILES) || (symbol_data_ & INLINES)) {
dumper_.ReadDwarf(module_, reader_, section_map, handle_inter_cu_refs_);
}
- if (symbol_data_ != NO_CFI) {
+ if (symbol_data_ & CFI) {
mach_o::SectionMap::const_iterator debug_frame
= section_map.find("__debug_frame");
if (debug_frame != section_map.end()) {
@@ -610,8 +640,8 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
return true;
}
-bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
- const ByteBuffer &strings) {
+bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer& entries,
+ const ByteBuffer& strings) {
StabsToModule stabs_to_module(module_);
// Mac OS X STABS are never "unitized", and the size of the 'value' field
// matches the address size of the executable.
@@ -653,22 +683,10 @@ bool DumpSymbols::ReadSymbolData(Module** out_module) {
return true;
}
-bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
- Module* module = NULL;
-
- if (ReadSymbolData(&module) && module) {
- bool res = module->Write(stream, symbol_data_);
- delete module;
- return res;
- }
-
- return false;
-}
-
// Read the selected object file's debugging information, and write out the
// header only to |stream|. Return true on success; if an error occurs, report
// it and return false.
-bool DumpSymbols::WriteSymbolFileHeader(std::ostream &stream) {
+bool DumpSymbols::WriteSymbolFileHeader(std::ostream& stream) {
scoped_ptr<Module> module;
if (!CreateEmptyModule(module))
return false;
diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h
index 1e57f86d..c2e1b40b 100644
--- a/src/common/mac/dump_syms.h
+++ b/src/common/mac/dump_syms.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -54,23 +53,34 @@ namespace google_breakpad {
class DumpSymbols {
public:
- DumpSymbols(SymbolData symbol_data, bool handle_inter_cu_refs)
+ DumpSymbols(SymbolData symbol_data,
+ bool handle_inter_cu_refs,
+ bool enable_multiple = false)
: symbol_data_(symbol_data),
handle_inter_cu_refs_(handle_inter_cu_refs),
- input_pathname_(),
object_filename_(),
contents_(),
+ size_(0),
+ from_disk_(false),
object_files_(),
selected_object_file_(),
- selected_object_name_() { }
- ~DumpSymbols() {
- }
+ selected_object_name_(),
+ enable_multiple_(enable_multiple) {}
+ ~DumpSymbols() = default;
// Prepare to read debugging information from |filename|. |filename| may be
- // the name of a universal binary, a Mach-O file, or a dSYM bundle
- // containing either of the above. On success, return true; if there is a
- // problem reading |filename|, report it and return false.
- bool Read(const std::string &filename);
+ // the name of a fat file, a Mach-O file, or a dSYM bundle containing either
+ // of the above. On success, return true; if there is a problem reading
+ // |filename|, report it and return false.
+ bool Read(const std::string& filename);
+
+ // Prepare to read debugging information from |contents|. |contents| is
+ // expected to be the data obtained from reading a fat file, or a Mach-O file.
+ // |filename| is used to determine the object filename in the generated
+ // output; there will not be an attempt to open this file as the data
+ // is already expected to be in memory. On success, return true; if there is a
+ // problem reading |contents|, report it and return false.
+ bool ReadData(uint8_t* contents, size_t size, const std::string& filename);
// If this dumper's file includes an object file for |cpu_type| and
// |cpu_subtype|, then select that object file for dumping, and return
@@ -91,7 +101,7 @@ class DumpSymbols {
// the dumper will dump those symbols; and if it contains more than one
// object file, then the dumper will dump the object file whose
// architecture matches that of this dumper program.
- bool SetArchitecture(const std::string &arch_name);
+ bool SetArchitecture(const std::string& arch_name);
// Return a pointer to an array of SuperFatArch structures describing the
// object files contained in this dumper's file. Set *|count| to the number
@@ -100,28 +110,26 @@ class DumpSymbols {
//
// If there are no available architectures, this function
// may return NULL.
- const SuperFatArch* AvailableArchitectures(size_t *count) {
+ const SuperFatArch* AvailableArchitectures(size_t* count) {
*count = object_files_.size();
if (object_files_.size() > 0)
return &object_files_[0];
return NULL;
}
- // Read the selected object file's debugging information, and write it out to
- // |stream|. Return true on success; if an error occurs, report it and
- // return false.
- bool WriteSymbolFile(std::ostream &stream);
-
// Read the selected object file's debugging information, and write out the
// header only to |stream|. Return true on success; if an error occurs, report
// it and return false.
- bool WriteSymbolFileHeader(std::ostream &stream);
+ bool WriteSymbolFileHeader(std::ostream& stream);
- // As above, but simply return the debugging information in module
- // instead of writing it to a stream. The caller owns the resulting
- // module object and must delete it when finished.
+ // Read the selected object file's debugging information and store it in
+ // `module`. The caller owns the resulting module object and must delete
+ // it when finished.
bool ReadSymbolData(Module** module);
+ // Return an identifier string for the file this DumpSymbols is dumping.
+ std::string Identifier();
+
private:
// Used internally.
class DumperLineToModule;
@@ -133,18 +141,14 @@ class DumpSymbols {
SuperFatArch* FindBestMatchForArchitecture(
cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
- // Return an identifier string for the file this DumpSymbols is dumping.
- std::string Identifier();
-
-
// Creates an empty module object.
bool CreateEmptyModule(scoped_ptr<Module>& module);
// Read debugging information from |dwarf_sections|, which was taken from
// |macho_reader|, and add it to |module|.
- void ReadDwarf(google_breakpad::Module *module,
- const mach_o::Reader &macho_reader,
- const mach_o::SectionMap &dwarf_sections,
+ void ReadDwarf(google_breakpad::Module* module,
+ const mach_o::Reader& macho_reader,
+ const mach_o::SectionMap& dwarf_sections,
bool handle_inter_cu_refs) const;
// Read DWARF CFI or .eh_frame data from |section|, belonging to
@@ -152,9 +156,9 @@ class DumpSymbols {
// then the data is .eh_frame-format data; otherwise, it is standard DWARF
// .debug_frame data. On success, return true; on failure, report
// the problem and return false.
- bool ReadCFI(google_breakpad::Module *module,
- const mach_o::Reader &macho_reader,
- const mach_o::Section &section,
+ bool ReadCFI(google_breakpad::Module* module,
+ const mach_o::Reader& macho_reader,
+ const mach_o::Section& section,
bool eh_frame) const;
// The selection of what type of symbol data to read/write.
@@ -163,19 +167,22 @@ class DumpSymbols {
// Whether to handle references between compilation units.
const bool handle_inter_cu_refs_;
- // The name of the file or bundle whose symbols this will dump.
- // This is the path given to Read, for use in error messages.
- std::string input_pathname_;
-
// The name of the file this DumpSymbols will actually read debugging
- // information from. Normally, this is the same as input_pathname_, but if
- // filename refers to a dSYM bundle, then this is the resource file
- // within that bundle.
+ // information from. If the filename passed to Read refers to a dSYM bundle,
+ // then this is the resource file within that bundle.
std::string object_filename_;
// The complete contents of object_filename_, mapped into memory.
scoped_array<uint8_t> contents_;
+ // The size of contents_.
+ size_t size_;
+
+ // Indicates which entry point to DumpSymbols was used, i.e. Read vs ReadData.
+ // This is used to indicate that downstream code paths can/should also read
+ // from disk or not.
+ bool from_disk_;
+
// A vector of SuperFatArch structures describing the object files
// object_filename_ contains. If object_filename_ refers to a fat binary,
// this may have more than one element; if it refers to a Mach-O file, this
@@ -184,13 +191,19 @@ class DumpSymbols {
// The object file in object_files_ selected to dump, or NULL if
// SetArchitecture hasn't been called yet.
- const SuperFatArch *selected_object_file_;
+ const SuperFatArch* selected_object_file_;
// A string that identifies the selected object file, for use in error
// messages. This is usually object_filename_, but if that refers to a
// fat binary, it includes an indication of the particular architecture
// within that binary.
string selected_object_name_;
+
+ // Whether symbols sharing an address should be collapsed into a single entry
+ // and marked with an `m` in the output.
+ // See: https://crbug.com/google-breakpad/751 and docs at
+ // docs/symbol_files.md#records-3
+ bool enable_multiple_;
};
} // namespace google_breakpad
diff --git a/src/common/mac/encoding_util.h b/src/common/mac/encoding_util.h
new file mode 100644
index 00000000..3028f2e9
--- /dev/null
+++ b/src/common/mac/encoding_util.h
@@ -0,0 +1,40 @@
+// Copyright 2020 Google LLC
+//
+// 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 LLC 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.
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MAC_ENCODING_UTIL_H
+#define GOOGLE_BREAKPAD_COMMON_MAC_ENCODING_UTIL_H
+
+#import <Foundation/Foundation.h>
+
+// As -[NSString stringByAddingPercentEscapesUsingEncoding:] has been
+// deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements it
+// using -[NSString stringByAddingPercentEncodingWithAllowedCharacters:] when
+// using those SDKs.
+NSString* PercentEncodeNSString(NSString* key);
+
+#endif // GOOGLE_BREAKPAD_COMMON_MAC_ENCODING_UTIL_H
diff --git a/src/common/mac/encoding_util.m b/src/common/mac/encoding_util.m
new file mode 100644
index 00000000..5cf84fc5
--- /dev/null
+++ b/src/common/mac/encoding_util.m
@@ -0,0 +1,46 @@
+// Copyright 2020 Google LLC
+//
+// 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 LLC 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.
+
+#include "encoding_util.h"
+
+#include <Availability.h>
+#include <AvailabilityMacros.h>
+#import <Foundation/Foundation.h>
+
+NSString* PercentEncodeNSString(NSString* key) {
+#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \
+ __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \
+ (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
+ defined(MAC_OS_X_VERSION_10_11) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
+ return [key stringByAddingPercentEncodingWithAllowedCharacters:
+ [NSCharacterSet URLQueryAllowedCharacterSet]];
+#else
+ return [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+#endif
+}
diff --git a/src/common/mac/file_id.cc b/src/common/mac/file_id.cc
index 4661d5d6..a6c1d26f 100644
--- a/src/common/mac/file_id.cc
+++ b/src/common/mac/file_id.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -33,53 +32,41 @@
//
// Author: Dan Waylonis
+#include "common/mac/file_id.h"
+
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
-#include <unistd.h>
-#include "common/mac/file_id.h"
#include "common/mac/macho_id.h"
+#include "common/scoped_ptr.h"
using MacFileUtilities::MachoID;
namespace google_breakpad {
-
-FileID::FileID(const char *path) {
+namespace mach_o {
+// Constructs a FileID given a path to a file
+FileID::FileID(const char* path) : memory_(nullptr), size_(0) {
snprintf(path_, sizeof(path_), "%s", path);
}
-bool FileID::FileIdentifier(unsigned char identifier[16]) {
- int fd = open(path_, O_RDONLY);
- if (fd == -1)
- return false;
-
- MD5Context md5;
- MD5Init(&md5);
-
- // Read 4k x 2 bytes at a time. This is faster than just 4k bytes, but
- // doesn't seem to be an unreasonable size for the stack.
- unsigned char buffer[4096 * 2];
- size_t buffer_size = sizeof(buffer);
- while ((buffer_size = read(fd, buffer, buffer_size) > 0)) {
- MD5Update(&md5, buffer, static_cast<unsigned>(buffer_size));
- }
-
- close(fd);
- MD5Final(identifier, &md5);
-
- return true;
-}
+// Constructs a FileID given the contents of a file and its size
+FileID::FileID(void* memory, size_t size)
+ : path_(), memory_(memory), size_(size) {}
bool FileID::MachoIdentifier(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]) {
- MachoID macho(path_);
-
- if (macho.UUIDCommand(cpu_type, cpu_subtype, identifier))
+ scoped_ptr<MachoID> macho;
+ if (memory_) {
+ macho.reset(new MachoID(memory_, size_));
+ } else {
+ macho.reset(new MachoID(path_));
+ }
+ if (macho->UUIDCommand(cpu_type, cpu_subtype, identifier))
return true;
- return macho.MD5(cpu_type, cpu_subtype, identifier);
+ return macho->MD5(cpu_type, cpu_subtype, identifier);
}
// static
@@ -103,4 +90,5 @@ void FileID::ConvertIdentifierToString(const unsigned char identifier[16],
buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0;
}
+} // namespace mach_o
} // namespace google_breakpad
diff --git a/src/common/mac/file_id.h b/src/common/mac/file_id.h
index 5d60e84c..a14cd137 100644
--- a/src/common/mac/file_id.h
+++ b/src/common/mac/file_id.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -36,19 +35,19 @@
#include <limits.h>
#include <mach/machine.h>
+#include <stddef.h>
namespace google_breakpad {
+namespace mach_o {
class FileID {
public:
- FileID(const char *path);
- ~FileID() {}
+ // Constructs a FileID given a path to a file
+ FileID(const char* path);
- // Load the identifier for the file path specified in the constructor into
- // |identifier|. Return false if the identifier could not be created for the
- // file.
- // The current implementation will return the MD5 hash of the file's bytes.
- bool FileIdentifier(unsigned char identifier[16]);
+ // Constructs a FileID given the contents of a file and its size.
+ FileID(void* memory, size_t size);
+ ~FileID() {}
// Treat the file as a mach-o file that will contain one or more archicture.
// Accepted values for |cpu_type| and |cpu_subtype| (e.g., CPU_TYPE_X86 or
@@ -74,8 +73,19 @@ class FileID {
private:
// Storage for the path specified
char path_[PATH_MAX];
+
+ // Storage for contents of a file if this instance is used to operate on in
+ // memory file data rather than directly from a filesystem. If memory_ is
+ // null, the file represented by path_ will be opened/read. If memory_ is
+ // non-null, it is assumed to contain valid data, and no file operations will
+ // occur.
+ void* memory_;
+
+ // Size of memory_
+ size_t size_;
};
+} // namespace mach_o
} // namespace google_breakpad
#endif // COMMON_MAC_FILE_ID_H__
diff --git a/src/common/mac/launch_reporter.cc b/src/common/mac/launch_reporter.cc
index 245be826..de554ee3 100644
--- a/src/common/mac/launch_reporter.cc
+++ b/src/common/mac/launch_reporter.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/launch_reporter.h b/src/common/mac/launch_reporter.h
index 4531123c..0cf73547 100644
--- a/src/common/mac/launch_reporter.h
+++ b/src/common/mac/launch_reporter.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/macho_id.cc b/src/common/mac/macho_id.cc
index c396ad88..e67ccddb 100644
--- a/src/common/mac/macho_id.cc
+++ b/src/common/mac/macho_id.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -37,11 +36,7 @@
#include <fcntl.h>
#include <mach-o/loader.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
#include "common/mac/macho_id.h"
#include "common/mac/macho_walker.h"
@@ -53,80 +48,25 @@ using google_breakpad::MD5Init;
using google_breakpad::MD5Update;
using google_breakpad::MD5Final;
-MachoID::MachoID(const char *path)
- : memory_(0),
- memory_size_(0),
- crc_(0),
- md5_context_(),
- update_function_(NULL) {
+MachoID::MachoID(const char* path)
+ : memory_(0), memory_size_(0), md5_context_(), update_function_(NULL) {
snprintf(path_, sizeof(path_), "%s", path);
}
-MachoID::MachoID(const char *path, void *memory, size_t size)
- : memory_(memory),
- memory_size_(size),
- crc_(0),
- md5_context_(),
- update_function_(NULL) {
- snprintf(path_, sizeof(path_), "%s", path);
-}
-
-MachoID::~MachoID() {
-}
+MachoID::MachoID(void* memory, size_t size)
+ : path_(),
+ memory_(memory),
+ memory_size_(size),
+ md5_context_(),
+ update_function_(NULL) {}
-// The CRC info is from http://en.wikipedia.org/wiki/Adler-32
-// With optimizations from http://www.zlib.net/
-
-// The largest prime smaller than 65536
-#define MOD_ADLER 65521
-// MAX_BLOCK is the largest n such that 255n(n+1)/2 + (n+1)(MAX_BLOCK-1) <= 2^32-1
-#define MAX_BLOCK 5552
-
-void MachoID::UpdateCRC(unsigned char *bytes, size_t size) {
-// Unrolled loops for summing
-#define DO1(buf,i) {sum1 += (buf)[i]; sum2 += sum1;}
-#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
-#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
-#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
-#define DO16(buf) DO8(buf,0); DO8(buf,8);
- // Split up the crc
- uint32_t sum1 = crc_ & 0xFFFF;
- uint32_t sum2 = (crc_ >> 16) & 0xFFFF;
-
- // Do large blocks
- while (size >= MAX_BLOCK) {
- size -= MAX_BLOCK;
- int block_count = MAX_BLOCK / 16;
- do {
- DO16(bytes);
- bytes += 16;
- } while (--block_count);
- sum1 %= MOD_ADLER;
- sum2 %= MOD_ADLER;
- }
+MachoID::~MachoID() {}
- // Do remaining bytes
- if (size) {
- while (size >= 16) {
- size -= 16;
- DO16(bytes);
- bytes += 16;
- }
- while (size--) {
- sum1 += *bytes++;
- sum2 += sum1;
- }
- sum1 %= MOD_ADLER;
- sum2 %= MOD_ADLER;
- crc_ = (sum2 << 16) | sum1;
- }
-}
-
-void MachoID::UpdateMD5(unsigned char *bytes, size_t size) {
+void MachoID::UpdateMD5(unsigned char* bytes, size_t size) {
MD5Update(&md5_context_, bytes, static_cast<unsigned>(size));
}
-void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
+void MachoID::Update(MachoWalker* walker, off_t offset, size_t size) {
if (!update_function_ || !size)
return;
@@ -169,59 +109,6 @@ bool MachoID::UUIDCommand(cpu_type_t cpu_type,
return false;
}
-bool MachoID::IDCommand(cpu_type_t cpu_type,
- cpu_subtype_t cpu_subtype,
- unsigned char identifier[16]) {
- struct dylib_command dylib_cmd;
- dylib_cmd.cmd = 0;
- if (!WalkHeader(cpu_type, cpu_subtype, IDWalkerCB, &dylib_cmd))
- return false;
-
- // If we found the command, we'll have initialized the dylib_command
- // structure
- if (dylib_cmd.cmd == LC_ID_DYLIB) {
- // Take the hashed filename, version, and compatability version bytes
- // to form the first 12 bytes, pad the rest with zeros
-
- // create a crude hash of the filename to generate the first 4 bytes
- identifier[0] = 0;
- identifier[1] = 0;
- identifier[2] = 0;
- identifier[3] = 0;
-
- for (int j = 0, i = (int)strlen(path_)-1; i>=0 && path_[i]!='/'; ++j, --i) {
- identifier[j%4] += path_[i];
- }
-
- identifier[4] = (dylib_cmd.dylib.current_version >> 24) & 0xFF;
- identifier[5] = (dylib_cmd.dylib.current_version >> 16) & 0xFF;
- identifier[6] = (dylib_cmd.dylib.current_version >> 8) & 0xFF;
- identifier[7] = dylib_cmd.dylib.current_version & 0xFF;
- identifier[8] = (dylib_cmd.dylib.compatibility_version >> 24) & 0xFF;
- identifier[9] = (dylib_cmd.dylib.compatibility_version >> 16) & 0xFF;
- identifier[10] = (dylib_cmd.dylib.compatibility_version >> 8) & 0xFF;
- identifier[11] = dylib_cmd.dylib.compatibility_version & 0xFF;
- identifier[12] = (cpu_type >> 24) & 0xFF;
- identifier[13] = (cpu_type >> 16) & 0xFF;
- identifier[14] = (cpu_type >> 8) & 0xFF;
- identifier[15] = cpu_type & 0xFF;
-
- return true;
- }
-
- return false;
-}
-
-uint32_t MachoID::Adler32(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
- update_function_ = &MachoID::UpdateCRC;
- crc_ = 0;
-
- if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
- return 0;
-
- return crc_;
-}
-
bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) {
update_function_ = &MachoID::UpdateMD5;
@@ -237,7 +124,7 @@ bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char
bool MachoID::WalkHeader(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
MachoWalker::LoadCommandCallback callback,
- void *context) {
+ void* context) {
if (memory_) {
MachoWalker walker(memory_, memory_size_, callback, context);
return walker.WalkHeader(cpu_type, cpu_subtype);
@@ -248,9 +135,9 @@ bool MachoID::WalkHeader(cpu_type_t cpu_type,
}
// static
-bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
- bool swap, void *context) {
- MachoID *macho_id = (MachoID *)context;
+bool MachoID::WalkerCB(MachoWalker* walker, load_command* cmd, off_t offset,
+ bool swap, void* context) {
+ MachoID* macho_id = (MachoID*)context;
if (cmd->cmd == LC_SEGMENT) {
struct segment_command seg;
@@ -327,11 +214,11 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
}
// static
-bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
- bool swap, void *context) {
+bool MachoID::UUIDWalkerCB(MachoWalker* walker, load_command* cmd, off_t offset,
+ bool swap, void* context) {
if (cmd->cmd == LC_UUID) {
- struct breakpad_uuid_command *uuid_cmd =
- (struct breakpad_uuid_command *)context;
+ struct breakpad_uuid_command* uuid_cmd =
+ (struct breakpad_uuid_command*)context;
if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command),
offset))
@@ -346,24 +233,4 @@ bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
// Continue processing
return true;
}
-
-// static
-bool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
- bool swap, void *context) {
- if (cmd->cmd == LC_ID_DYLIB) {
- struct dylib_command *dylib_cmd = (struct dylib_command *)context;
-
- if (!walker->ReadBytes(dylib_cmd, sizeof(struct dylib_command), offset))
- return false;
-
- if (swap)
- breakpad_swap_dylib_command(dylib_cmd);
-
- return false;
- }
-
- // Continue processing
- return true;
-}
-
} // namespace MacFileUtilities
diff --git a/src/common/mac/macho_id.h b/src/common/mac/macho_id.h
index 10375491..b9cbdb00 100644
--- a/src/common/mac/macho_id.h
+++ b/src/common/mac/macho_id.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -45,8 +44,8 @@ namespace MacFileUtilities {
class MachoID {
public:
- MachoID(const char *path);
- MachoID(const char *path, void *memory, size_t size);
+ MachoID(const char* path);
+ MachoID(void* memory, size_t size);
~MachoID();
// For the given |cpu_type| and |cpu_subtype|, return a UUID from the LC_UUID
@@ -56,19 +55,6 @@ class MachoID {
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]);
- // For the given |cpu_type| and |cpu_subtype|, return a UUID from the
- // LC_ID_DYLIB command.
- // Return false if there isn't a LC_ID_DYLIB command.
- bool IDCommand(cpu_type_t cpu_type,
- cpu_subtype_t cpu_subtype,
- unsigned char identifier[16]);
-
- // For the given |cpu_type| and |cpu_subtype|, return the Adler32 CRC for the
- // mach-o data segment(s).
- // Return 0 on error (e.g., if the file is not a mach-o file)
- uint32_t Adler32(cpu_type_t cpu_type,
- cpu_subtype_t cpu_subtype);
-
// For the given |cpu_type|, and |cpu_subtype| return the MD5 for the mach-o
// data segment(s).
// Return true on success, false otherwise
@@ -78,47 +64,36 @@ class MachoID {
private:
// Signature of class member function to be called with data read from file
- typedef void (MachoID::*UpdateFunction)(unsigned char *bytes, size_t size);
-
- // Update the CRC value by examining |size| |bytes| and applying the algorithm
- // to each byte.
- void UpdateCRC(unsigned char *bytes, size_t size);
+ typedef void (MachoID::*UpdateFunction)(unsigned char* bytes, size_t size);
// Update the MD5 value by examining |size| |bytes| and applying the algorithm
// to each byte.
- void UpdateMD5(unsigned char *bytes, size_t size);
+ void UpdateMD5(unsigned char* bytes, size_t size);
// Bottleneck for update routines
- void Update(MachoWalker *walker, off_t offset, size_t size);
+ void Update(MachoWalker* walker, off_t offset, size_t size);
// Factory for the MachoWalker
bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype,
- MachoWalker::LoadCommandCallback callback, void *context);
+ MachoWalker::LoadCommandCallback callback, void* context);
// The callback from the MachoWalker for CRC and MD5
- static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
- bool swap, void *context);
+ static bool WalkerCB(MachoWalker* walker, load_command* cmd, off_t offset,
+ bool swap, void* context);
// The callback from the MachoWalker for LC_UUID
- static bool UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
- bool swap, void *context);
-
- // The callback from the MachoWalker for LC_ID_DYLIB
- static bool IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
- bool swap, void *context);
+ static bool UUIDWalkerCB(MachoWalker* walker, load_command* cmd, off_t offset,
+ bool swap, void* context);
// File path
char path_[PATH_MAX];
// Memory region to read from
- void *memory_;
+ void* memory_;
// Size of the memory region
size_t memory_size_;
- // The current crc value
- uint32_t crc_;
-
// The MD5 context
google_breakpad::MD5Context md5_context_;
diff --git a/src/common/mac/macho_reader.cc b/src/common/mac/macho_reader.cc
index 91e1fdd2..23c809c4 100644
--- a/src/common/mac/macho_reader.cc
+++ b/src/common/mac/macho_reader.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -81,7 +80,7 @@ void FatReader::Reporter::MisplacedObjectFile() {
" to contain\n", filename_.c_str());
}
-bool FatReader::Read(const uint8_t *buffer, size_t size) {
+bool FatReader::Read(const uint8_t* buffer, size_t size) {
buffer_.start = buffer;
buffer_.end = buffer + size;
ByteCursor cursor(&buffer_);
@@ -196,19 +195,19 @@ void Reader::Reporter::LoadCommandTooShort(size_t i, LoadCommandType type) {
filename_.c_str(), i, type);
}
-void Reader::Reporter::SectionsMissing(const string &name) {
+void Reader::Reporter::SectionsMissing(const string& name) {
fprintf(stderr, "%s: the load command for segment '%s'"
" is too short to hold the section headers it claims to have\n",
filename_.c_str(), name.c_str());
}
-void Reader::Reporter::MisplacedSegmentData(const string &name) {
+void Reader::Reporter::MisplacedSegmentData(const string& name) {
fprintf(stderr, "%s: the segment '%s' claims its contents lie beyond"
" the end of the file\n", filename_.c_str(), name.c_str());
}
-void Reader::Reporter::MisplacedSectionData(const string &section,
- const string &segment) {
+void Reader::Reporter::MisplacedSectionData(const string& section,
+ const string& segment) {
fprintf(stderr, "%s: the section '%s' in segment '%s'"
" claims its contents lie outside the segment's contents\n",
filename_.c_str(), section.c_str(), segment.c_str());
@@ -225,7 +224,7 @@ void Reader::Reporter::UnsupportedCPUType(cpu_type_t cpu_type) {
filename_.c_str(), cpu_type);
}
-bool Reader::Read(const uint8_t *buffer,
+bool Reader::Read(const uint8_t* buffer,
size_t size,
cpu_type_t expected_cpu_type,
cpu_subtype_t expected_cpu_subtype) {
@@ -309,7 +308,7 @@ bool Reader::Read(const uint8_t *buffer,
return true;
}
-bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
+bool Reader::WalkLoadCommands(Reader::LoadCommandHandler* handler) const {
ByteCursor list_cursor(&load_commands_, big_endian_);
for (size_t index = 0; index < load_command_count_; ++index) {
@@ -422,13 +421,13 @@ class Reader::SegmentFinder : public LoadCommandHandler {
public:
// Create a load command handler that looks for a segment named NAME,
// and sets SEGMENT to describe it if found.
- SegmentFinder(const string &name, Segment *segment)
+ SegmentFinder(const string& name, Segment* segment)
: name_(name), segment_(segment), found_() { }
// Return true if the traversal found the segment, false otherwise.
bool found() const { return found_; }
- bool SegmentCommand(const Segment &segment) {
+ bool SegmentCommand(const Segment& segment) {
if (segment.name == name_) {
*segment_ = segment;
found_ = true;
@@ -439,23 +438,23 @@ class Reader::SegmentFinder : public LoadCommandHandler {
private:
// The name of the segment our creator is looking for.
- const string &name_;
+ const string& name_;
// Where we should store the segment if found. (WEAK)
- Segment *segment_;
+ Segment* segment_;
// True if we found the segment.
bool found_;
};
-bool Reader::FindSegment(const string &name, Segment *segment) const {
+bool Reader::FindSegment(const string& name, Segment* segment) const {
SegmentFinder finder(name, segment);
WalkLoadCommands(&finder);
return finder.found();
}
-bool Reader::WalkSegmentSections(const Segment &segment,
- SectionHandler *handler) const {
+bool Reader::WalkSegmentSections(const Segment& segment,
+ SectionHandler* handler) const {
size_t word_size = segment.bits_64 ? 8 : 4;
ByteCursor cursor(&segment.section_list, big_endian_);
@@ -518,12 +517,21 @@ bool Reader::WalkSegmentSections(const Segment &segment,
if (offset < size_t(segment.contents.start - buffer_.start) ||
offset > size_t(segment.contents.end - buffer_.start) ||
size > size_t(segment.contents.end - buffer_.start - offset)) {
- reporter_->MisplacedSectionData(section.section_name,
- section.segment_name);
- return false;
+ if (offset > 0) {
+ reporter_->MisplacedSectionData(section.section_name,
+ section.segment_name);
+ return false;
+ } else {
+ // Mach-O files in .dSYM bundles have the contents of the loaded
+ // segments partially removed. The removed sections will have zero as
+ // their offset. MisplacedSectionData should not be called in this
+ // case.
+ section.contents.start = section.contents.end = NULL;
+ }
+ } else {
+ section.contents.start = buffer_.start + offset;
+ section.contents.end = section.contents.start + size;
}
- section.contents.start = buffer_.start + offset;
- section.contents.end = section.contents.start + size;
}
if (!handler->HandleSection(section))
return false;
@@ -537,18 +545,18 @@ class Reader::SectionMapper: public SectionHandler {
public:
// Create a SectionHandler that populates MAP with an entry for
// each section it is given.
- SectionMapper(SectionMap *map) : map_(map) { }
- bool HandleSection(const Section &section) {
+ SectionMapper(SectionMap* map) : map_(map) { }
+ bool HandleSection(const Section& section) {
(*map_)[section.section_name] = section;
return true;
}
private:
// The map under construction. (WEAK)
- SectionMap *map_;
+ SectionMap* map_;
};
-bool Reader::MapSegmentSections(const Segment &segment,
- SectionMap *section_map) const {
+bool Reader::MapSegmentSections(const Segment& segment,
+ SectionMap* section_map) const {
section_map->clear();
SectionMapper mapper(section_map);
return WalkSegmentSections(segment, &mapper);
diff --git a/src/common/mac/macho_reader.h b/src/common/mac/macho_reader.h
index 145d17d1..d3c61a06 100644
--- a/src/common/mac/macho_reader.h
+++ b/src/common/mac/macho_reader.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -78,7 +77,7 @@ class FatReader {
class Reporter {
public:
// Create a reporter that attributes problems to |filename|.
- explicit Reporter(const string &filename) : filename_(filename) { }
+ explicit Reporter(const string& filename) : filename_(filename) { }
virtual ~Reporter() { }
@@ -101,7 +100,7 @@ class FatReader {
};
// Create a fat binary file reader that uses |reporter| to report problems.
- explicit FatReader(Reporter *reporter) : reporter_(reporter) { }
+ explicit FatReader(Reporter* reporter) : reporter_(reporter) { }
// Read the |size| bytes at |buffer| as a fat binary file. On success,
// return true; on failure, report the problem to reporter_ and return
@@ -110,7 +109,7 @@ class FatReader {
// If the data is a plain Mach-O file, rather than a fat binary file,
// then the reader behaves as if it had found a fat binary file whose
// single object file is the Mach-O file.
- bool Read(const uint8_t *buffer, size_t size);
+ bool Read(const uint8_t* buffer, size_t size);
// Return an array of 'SuperFatArch' structures describing the
// object files present in this fat binary file. Set |size| to the
@@ -130,7 +129,7 @@ class FatReader {
// possible to use the result with OS X functions like NXFindBestFatArch,
// so that the symbol dumper will behave consistently with other OS X
// utilities that work with fat binaries.
- const SuperFatArch* object_files(size_t *count) const {
+ const SuperFatArch* object_files(size_t* count) const {
*count = object_files_.size();
if (object_files_.size() > 0)
return &object_files_[0];
@@ -139,7 +138,7 @@ class FatReader {
private:
// We use this to report problems parsing the file's contents. (WEAK)
- Reporter *reporter_;
+ Reporter* reporter_;
// The contents of the fat binary or Mach-O file we're parsing. We do not
// own the storage it refers to.
@@ -240,7 +239,7 @@ class Reader {
class Reporter {
public:
// Create a reporter that attributes problems to |filename|.
- explicit Reporter(const string &filename) : filename_(filename) { }
+ explicit Reporter(const string& filename) : filename_(filename) { }
virtual ~Reporter() { }
// Reporter functions for fatal errors return void; the reader will
@@ -282,16 +281,16 @@ class Reader {
// The LC_SEGMENT or LC_SEGMENT_64 load command for the segment named
// |name| is too short to hold the sections that its header says it does.
// (This more specific than LoadCommandTooShort.)
- virtual void SectionsMissing(const string &name);
+ virtual void SectionsMissing(const string& name);
// The segment named |name| claims that its contents lie beyond the end
// of the file.
- virtual void MisplacedSegmentData(const string &name);
+ virtual void MisplacedSegmentData(const string& name);
// The section named |section| in the segment named |segment| claims that
// its contents do not lie entirely within the segment.
- virtual void MisplacedSectionData(const string &section,
- const string &segment);
+ virtual void MisplacedSectionData(const string& section,
+ const string& segment);
// The LC_SYMTAB command claims that symbol table contents are located
// beyond the end of the file.
@@ -315,7 +314,7 @@ class Reader {
// Called to report that the segment's section list contains |section|.
// This should return true if the iteration should continue, or false
// if it should stop.
- virtual bool HandleSection(const Section &section) = 0;
+ virtual bool HandleSection(const Section& section) = 0;
};
// A handler for the load commands in a Mach-O file.
@@ -341,20 +340,20 @@ class Reader {
// cannot parse the command type or its size, we call
// reporter_->IncompleteLoadCommand instead.)
virtual bool UnknownCommand(LoadCommandType type,
- const ByteBuffer &contents) {
+ const ByteBuffer& contents) {
return true;
}
// The load command is LC_SEGMENT or LC_SEGMENT_64, defining a segment
// with the properties given in |segment|.
- virtual bool SegmentCommand(const Segment &segment) {
+ virtual bool SegmentCommand(const Segment& segment) {
return true;
}
// The load command is LC_SYMTAB. |entries| holds the array of nlist
// entries, and |names| holds the strings the entries refer to.
- virtual bool SymtabCommand(const ByteBuffer &entries,
- const ByteBuffer &names) {
+ virtual bool SymtabCommand(const ByteBuffer& entries,
+ const ByteBuffer& names) {
return true;
}
@@ -362,7 +361,7 @@ class Reader {
};
// Create a Mach-O file reader that reports problems to |reporter|.
- explicit Reader(Reporter *reporter)
+ explicit Reader(Reporter* reporter)
: reporter_(reporter) { }
// Read the given data as a Mach-O file. The reader retains pointers
@@ -371,11 +370,11 @@ class Reader {
//
// At most one of these functions should be invoked once on each Reader
// instance.
- bool Read(const uint8_t *buffer,
+ bool Read(const uint8_t* buffer,
size_t size,
cpu_type_t expected_cpu_type,
cpu_subtype_t expected_cpu_subtype);
- bool Read(const ByteBuffer &buffer,
+ bool Read(const ByteBuffer& buffer,
cpu_type_t expected_cpu_type,
cpu_subtype_t expected_cpu_subtype) {
return Read(buffer.start,
@@ -402,25 +401,25 @@ class Reader {
// a handler function returns false. If we encounter a malformed load
// command, report it via reporter_ and return false. Return true if all
// load commands were parseable and all handlers returned true.
- bool WalkLoadCommands(LoadCommandHandler *handler) const;
+ bool WalkLoadCommands(LoadCommandHandler* handler) const;
// Set |segment| to describe the segment named |name|, if present. If
// found, |segment|'s byte buffers refer to a subregion of the bytes
// passed to Read. If we find the section, return true; otherwise,
// return false.
- bool FindSegment(const string &name, Segment *segment) const;
+ bool FindSegment(const string& name, Segment* segment) const;
// Apply |handler| to each section defined in |segment|. If |handler| returns
// false, stop iterating and return false. If all calls to |handler| return
// true and we reach the end of the section list, return true.
- bool WalkSegmentSections(const Segment &segment, SectionHandler *handler)
+ bool WalkSegmentSections(const Segment& segment, SectionHandler* handler)
const;
// Clear |section_map| and then populate it with a map of the sections
// in |segment|, from section names to Section structures.
// Each Section's contents refer to bytes in |segment|'s contents.
// On success, return true; if a problem occurs, report it and return false.
- bool MapSegmentSections(const Segment &segment, SectionMap *section_map)
+ bool MapSegmentSections(const Segment& segment, SectionMap* section_map)
const;
private:
@@ -429,7 +428,7 @@ class Reader {
class SectionMapper;
// We use this to report problems parsing the file's contents. (WEAK)
- Reporter *reporter_;
+ Reporter* reporter_;
// The contents of the Mach-O file we're parsing. We do not own the
// storage it refers to.
diff --git a/src/common/mac/macho_reader_unittest.cc b/src/common/mac/macho_reader_unittest.cc
index d8459d8c..3beec341 100644
--- a/src/common/mac/macho_reader_unittest.cc
+++ b/src/common/mac/macho_reader_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -75,7 +74,7 @@ using testing::_;
class MockFatReaderReporter: public FatReader::Reporter {
public:
- MockFatReaderReporter(const string &filename)
+ MockFatReaderReporter(const string& filename)
: FatReader::Reporter(filename) { }
MOCK_METHOD0(BadHeader, void());
MOCK_METHOD0(MisplacedObjectFile, void());
@@ -84,7 +83,7 @@ class MockFatReaderReporter: public FatReader::Reporter {
class MockReaderReporter: public Reader::Reporter {
public:
- MockReaderReporter(const string &filename) : Reader::Reporter(filename) { }
+ MockReaderReporter(const string& filename) : Reader::Reporter(filename) { }
MOCK_METHOD0(BadHeader, void());
MOCK_METHOD4(CPUTypeMismatch, void(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
@@ -95,24 +94,24 @@ class MockReaderReporter: public Reader::Reporter {
MOCK_METHOD3(LoadCommandsOverrun, void(size_t claimed, size_t i,
LoadCommandType type));
MOCK_METHOD2(LoadCommandTooShort, void(size_t i, LoadCommandType type));
- MOCK_METHOD1(SectionsMissing, void(const string &name));
- MOCK_METHOD1(MisplacedSegmentData, void(const string &name));
- MOCK_METHOD2(MisplacedSectionData, void(const string &section,
- const string &segment));
+ MOCK_METHOD1(SectionsMissing, void(const string& name));
+ MOCK_METHOD1(MisplacedSegmentData, void(const string& name));
+ MOCK_METHOD2(MisplacedSectionData, void(const string& section,
+ const string& segment));
MOCK_METHOD0(MisplacedSymbolTable, void());
MOCK_METHOD1(UnsupportedCPUType, void(cpu_type_t cpu_type));
};
class MockLoadCommandHandler: public Reader::LoadCommandHandler {
public:
- MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer &));
- MOCK_METHOD1(SegmentCommand, bool(const Segment &));
- MOCK_METHOD2(SymtabCommand, bool(const ByteBuffer &, const ByteBuffer &));
+ MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer&));
+ MOCK_METHOD1(SegmentCommand, bool(const Segment&));
+ MOCK_METHOD2(SymtabCommand, bool(const ByteBuffer&, const ByteBuffer&));
};
class MockSectionHandler: public Reader::SectionHandler {
public:
- MOCK_METHOD1(HandleSection, bool(const Section &section));
+ MOCK_METHOD1(HandleSection, bool(const Section& section));
};
@@ -221,7 +220,7 @@ struct FatReaderFixture {
}
void ReadFat(bool expect_parse_success = true) {
ASSERT_TRUE(fat.GetContents(&contents));
- fat_bytes = reinterpret_cast<const uint8_t *>(contents.data());
+ fat_bytes = reinterpret_cast<const uint8_t*>(contents.data());
if (expect_parse_success) {
EXPECT_TRUE(reader.Read(fat_bytes, contents.size()));
size_t fat_files_count;
@@ -238,7 +237,7 @@ struct FatReaderFixture {
MockFatReaderReporter reporter;
FatReader reader;
string contents;
- const uint8_t *fat_bytes;
+ const uint8_t* fat_bytes;
vector<struct fat_arch> object_files;
};
@@ -487,16 +486,16 @@ class WithConfiguration {
private:
// The innermost WithConfiguration in whose dynamic scope we are
// currently executing.
- static WithConfiguration *current_;
+ static WithConfiguration* current_;
// The innermost WithConfiguration whose dynamic scope encloses this
// WithConfiguration.
Endianness endianness_;
size_t word_size_;
- WithConfiguration *saved_;
+ WithConfiguration* saved_;
};
-WithConfiguration *WithConfiguration::current_ = NULL;
+WithConfiguration* WithConfiguration::current_ = NULL;
// A test_assembler::Section with a size that we can cite. The start(),
// Here() and Mark() member functions of a SizedSection always represent
@@ -527,7 +526,7 @@ class SizedSection: public test_assembler::Section {
// Append SECTION to the end of this section, and call its Finish member.
// Return a reference to this section.
- SizedSection &Place(SizedSection *section) {
+ SizedSection& Place(SizedSection* section) {
assert(section->endianness() == endianness());
section->Finish();
section->start() = Here();
@@ -563,7 +562,7 @@ class LoadedSection: public SizedSection {
// Placing a loaded section within a loaded section sets the relationship
// between their addresses.
- LoadedSection &Place(LoadedSection *section) {
+ LoadedSection& Place(LoadedSection* section) {
section->address() = address() + Size();
SizedSection::Place(section);
return *this;
@@ -583,7 +582,7 @@ class SegmentLoadCommand: public SizedSection {
// The load command will refer to CONTENTS, which must be Placed in the
// file separately, at the desired position. Return a reference to this
// section.
- SegmentLoadCommand &Header(const string &name, const LoadedSection &contents,
+ SegmentLoadCommand& Header(const string& name, const LoadedSection& contents,
uint32_t maxprot, uint32_t initprot,
uint32_t flags) {
assert(contents.word_size() == word_size());
@@ -608,16 +607,16 @@ class SegmentLoadCommand: public SizedSection {
// memory. If this label is still undefined by the time we place this
// segment, it defaults to the final size of the segment's in-file
// contents. Return a reference to this load command.
- Label &vmsize() { return vmsize_; }
+ Label& vmsize() { return vmsize_; }
// Add a section entry with the given characteristics to this segment
// load command. Return a reference to this. The section entry will refer
// to CONTENTS, which must be Placed in the segment's contents
// separately, at the desired position.
- SegmentLoadCommand &AppendSectionEntry(const string &section_name,
- const string &segment_name,
+ SegmentLoadCommand& AppendSectionEntry(const string& section_name,
+ const string& segment_name,
uint32_t alignment, uint32_t flags,
- const LoadedSection &contents) {
+ const LoadedSection& contents) {
AppendCString(section_name, 16);
AppendCString(segment_name, 16);
Append(endianness(), word_size() / 8, contents.address());
@@ -671,14 +670,14 @@ class LoadCommands: public SizedSection {
Label final_command_count() const { return final_command_count_; }
// Increment the command count; return a reference to this section.
- LoadCommands &CountCommand() {
+ LoadCommands& CountCommand() {
command_count_++;
return *this;
}
// Place COMMAND, containing a load command, at the end of this section.
// Return a reference to this section.
- LoadCommands &Place(SizedSection *section) {
+ LoadCommands& Place(SizedSection* section) {
SizedSection::Place(section);
CountCommand();
return *this;
@@ -710,7 +709,7 @@ class MachOFile: public SizedSection {
// Create a Mach-O file header using the given characteristics and load
// command list. This Places COMMANDS immediately after the header.
// Return a reference to this section.
- MachOFile &Header(LoadCommands *commands,
+ MachOFile& Header(LoadCommands* commands,
cpu_type_t cpu_type = CPU_TYPE_X86,
cpu_subtype_t cpu_subtype = CPU_SUBTYPE_I386_ALL,
FileType file_type = MH_EXECUTE,
@@ -752,12 +751,12 @@ struct ReaderFixture {
EXPECT_CALL(load_command_handler, SegmentCommand(_)).Times(0);
}
- void ReadFile(MachOFile *file,
+ void ReadFile(MachOFile* file,
bool expect_parse_success,
cpu_type_t expected_cpu_type,
cpu_subtype_t expected_cpu_subtype) {
ASSERT_TRUE(file->GetContents(&file_contents));
- file_bytes = reinterpret_cast<const uint8_t *>(file_contents.data());
+ file_bytes = reinterpret_cast<const uint8_t*>(file_contents.data());
if (expect_parse_success) {
EXPECT_TRUE(reader.Read(file_bytes,
file_contents.size(),
@@ -772,7 +771,7 @@ struct ReaderFixture {
}
string file_contents;
- const uint8_t *file_bytes;
+ const uint8_t* file_bytes;
MockReaderReporter reporter;
Reader reader;
MockLoadCommandHandler load_command_handler;
@@ -1343,14 +1342,14 @@ TEST_F(LoadCommand, ThreeLoadCommands) {
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
}
-static inline Matcher<const Section &> MatchSection(
+static inline Matcher<const Section&> MatchSection(
Matcher<bool> bits_64,
- Matcher<const string &> section_name,
- Matcher<const string &> segment_name,
+ Matcher<const string&> section_name,
+ Matcher<const string&> segment_name,
Matcher<uint64_t> address,
Matcher<uint32_t> alignment,
Matcher<uint32_t> flags,
- Matcher<const ByteBuffer &> contents) {
+ Matcher<const ByteBuffer&> contents) {
return AllOf(AllOf(Field(&Section::bits_64, bits_64),
Field(&Section::section_name, section_name),
Field(&Section::segment_name, segment_name),
@@ -1360,10 +1359,10 @@ static inline Matcher<const Section &> MatchSection(
Field(&Section::contents, contents)));
}
-static inline Matcher<const Section &> MatchSection(
+static inline Matcher<const Section&> MatchSection(
Matcher<bool> bits_64,
- Matcher<const string &> section_name,
- Matcher<const string &> segment_name,
+ Matcher<const string&> section_name,
+ Matcher<const string&> segment_name,
Matcher<uint64_t> address) {
return AllOf(Field(&Section::bits_64, bits_64),
Field(&Section::section_name, section_name),
@@ -1410,7 +1409,7 @@ TEST_F(LoadCommand, OneSegmentTwoSections) {
contents1.start = file_bytes + section1.start().Value();
contents1.end = contents1.start + section1.final_size().Value();
EXPECT_EQ("buddha's hand",
- string(reinterpret_cast<const char *>(contents1.start),
+ string(reinterpret_cast<const char*>(contents1.start),
contents1.Size()));
EXPECT_CALL(section_handler,
HandleSection(MatchSection(true, "mandarin", "kishu",
@@ -1422,7 +1421,7 @@ TEST_F(LoadCommand, OneSegmentTwoSections) {
contents2.start = file_bytes + section2.start().Value();
contents2.end = contents2.start + section2.final_size().Value();
EXPECT_EQ("kumquat",
- string(reinterpret_cast<const char *>(contents2.start),
+ string(reinterpret_cast<const char*>(contents2.start),
contents2.Size()));
EXPECT_CALL(section_handler,
HandleSection(MatchSection(true, "bergamot", "cara cara",
@@ -1529,6 +1528,51 @@ TEST_F(LoadCommand, MisplacedSectionTooBig) {
// to set all their labels by hand to get the (impossible)
// configurations we want.
+ // A section with 0 as is start address.
+ LoadedSection empty;
+ empty.Append(10, '4');
+ empty.start() = 0;
+ empty.address() = segment.address() + 1;
+ empty.final_size() = empty.Size();
+
+ SegmentLoadCommand command;
+ command.Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
+ .AppendSectionEntry("empty", "segment", 0, 0x8b53ae5c, empty);
+
+ LoadCommands commands;
+ commands.Place(&command);
+
+ MachOFile file;
+ file.Header(&commands).Place(&segment);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment actual_segment;
+ EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
+
+ EXPECT_CALL(reporter, MisplacedSectionData("empty", "segment")).Times(0);
+
+ EXPECT_CALL(section_handler,
+ HandleSection(MatchSection(true, "empty", "segment",
+ empty.address().Value())))
+ .WillOnce(Return(true));
+
+ EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, &section_handler));
+}
+
+TEST_F(LoadCommand, MisplacedSectionButSectionIsEmpty) {
+ WithConfiguration config(kLittleEndian, 64);
+
+ // The segment.
+ LoadedSection segment;
+ segment.address() = 0x696d83cc;
+ segment.Append(10, '0');
+
+ // The contents of the following sections don't matter, because
+ // we're not really going to Place them in segment; we're just going
+ // to set all their labels by hand to get the (impossible)
+ // configurations we want.
+
// A section that extends beyond the end of its section.
LoadedSection too_big;
too_big.Append(10, '3');
@@ -1716,7 +1760,7 @@ class StringAssembler: public SizedSection {
public:
// Add the string S to this StringAssembler, and return the string's
// offset within this compilation unit's strings.
- size_t Add(const string &s) {
+ size_t Add(const string& s) {
size_t offset = Size();
AppendCString(s);
return offset;
@@ -1728,7 +1772,7 @@ class StringAssembler: public SizedSection {
class SymbolAssembler: public SizedSection {
public:
// Create a SymbolAssembler that uses StringAssembler for its strings.
- explicit SymbolAssembler(StringAssembler *string_assembler)
+ explicit SymbolAssembler(StringAssembler* string_assembler)
: string_assembler_(string_assembler),
entry_count_(0) { }
@@ -1737,7 +1781,7 @@ class SymbolAssembler: public SizedSection {
// its compilation unit's portion of the .stabstr section; this can be a
// value generated by a StringAssembler. Return a reference to this
// SymbolAssembler.
- SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
+ SymbolAssembler& Symbol(uint8_t type, uint8_t other, Label descriptor,
Label value, Label name) {
D32(name);
D8(type);
@@ -1749,14 +1793,14 @@ class SymbolAssembler: public SizedSection {
}
// As above, but automatically add NAME to our StringAssembler.
- SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
- Label value, const string &name) {
+ SymbolAssembler& Symbol(uint8_t type, uint8_t other, Label descriptor,
+ Label value, const string& name) {
return Symbol(type, other, descriptor, value, string_assembler_->Add(name));
}
private:
// The strings for our STABS entries.
- StringAssembler *string_assembler_;
+ StringAssembler* string_assembler_;
// The number of entries in this compilation unit so far.
size_t entry_count_;
diff --git a/src/common/mac/macho_utilities.cc b/src/common/mac/macho_utilities.cc
index f56fe768..16e430df 100644
--- a/src/common/mac/macho_utilities.cc
+++ b/src/common/mac/macho_utilities.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/macho_utilities.h b/src/common/mac/macho_utilities.h
index 00563a77..470cb5d2 100644
--- a/src/common/mac/macho_utilities.h
+++ b/src/common/mac/macho_utilities.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/macho_walker.cc b/src/common/mac/macho_walker.cc
index 1acd8665..505a4df1 100644
--- a/src/common/mac/macho_walker.cc
+++ b/src/common/mac/macho_walker.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -47,8 +46,8 @@
namespace MacFileUtilities {
-MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
- void *context)
+MachoWalker::MachoWalker(const char* path, LoadCommandCallback callback,
+ void* context)
: file_(-1),
memory_(NULL),
memory_size_(0),
@@ -60,8 +59,8 @@ MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
file_ = open(path, O_RDONLY);
}
-MachoWalker::MachoWalker(void *memory, size_t size,
- LoadCommandCallback callback, void *context)
+MachoWalker::MachoWalker(void* memory, size_t size,
+ LoadCommandCallback callback, void* context)
: file_(-1),
memory_(memory),
memory_size_(size),
@@ -82,7 +81,7 @@ bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
cpu_subtype_t valid_cpu_subtype = cpu_subtype;
// if |cpu_type| is 0, use the native cpu type.
if (cpu_type == 0) {
- const NXArchInfo *arch = NXGetLocalArchInfo();
+ const NXArchInfo* arch = NXGetLocalArchInfo();
assert(arch);
valid_cpu_type = arch->cputype;
valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE;
@@ -98,7 +97,7 @@ bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
return false;
}
-bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
+bool MachoWalker::ReadBytes(void* buffer, size_t size, off_t offset) {
if (memory_) {
if (offset < 0)
return false;
@@ -109,14 +108,14 @@ bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
size = memory_size_ - static_cast<size_t>(offset);
result = false;
}
- memcpy(buffer, static_cast<char *>(memory_) + offset, size);
+ memcpy(buffer, static_cast<char*>(memory_) + offset, size);
return result;
} else {
return pread(file_, buffer, size, offset) == (ssize_t)size;
}
}
-bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
+bool MachoWalker::CurrentHeader(struct mach_header_64* header, off_t* offset) {
if (current_header_) {
memcpy(header, current_header_, sizeof(mach_header_64));
*offset = current_header_offset_;
@@ -128,7 +127,7 @@ bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
bool MachoWalker::FindHeader(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
- off_t &offset) {
+ off_t& offset) {
// Read the magic bytes that's common amongst all mach-o files
uint32_t magic;
if (!ReadBytes(&magic, sizeof(magic), 0))
@@ -211,7 +210,7 @@ bool MachoWalker::WalkHeaderAtOffset(off_t offset) {
// Copy the data into the mach_header_64 structure. Since the 32-bit and
// 64-bit only differ in the last field (reserved), this is safe to do.
struct mach_header_64 header64;
- memcpy((void *)&header64, (const void *)&header, sizeof(header));
+ memcpy((void*)&header64, (const void*)&header, sizeof(header));
header64.reserved = 0;
current_header_ = &header64;
diff --git a/src/common/mac/macho_walker.h b/src/common/mac/macho_walker.h
index dd535814..13e8232e 100644
--- a/src/common/mac/macho_walker.h
+++ b/src/common/mac/macho_walker.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -49,12 +48,12 @@ class MachoWalker {
// beginning of the file (not header) where the command was read. If |swap|
// is set, then any command data (other than the returned load_command) should
// be swapped when read
- typedef bool (*LoadCommandCallback)(MachoWalker *walker, load_command *cmd,
- off_t offset, bool swap, void *context);
+ typedef bool (*LoadCommandCallback)(MachoWalker* walker, load_command* cmd,
+ off_t offset, bool swap, void* context);
- MachoWalker(const char *path, LoadCommandCallback callback, void *context);
- MachoWalker(void *memory, size_t size, LoadCommandCallback callback,
- void *context);
+ MachoWalker(const char* path, LoadCommandCallback callback, void* context);
+ MachoWalker(void* memory, size_t size, LoadCommandCallback callback,
+ void* context);
~MachoWalker();
// Begin walking the header for |cpu_type| and |cpu_subtype|. If |cpu_type|
@@ -67,17 +66,17 @@ class MachoWalker {
bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
// Read |size| bytes from the opened file at |offset| into |buffer|
- bool ReadBytes(void *buffer, size_t size, off_t offset);
+ bool ReadBytes(void* buffer, size_t size, off_t offset);
// Return the current header and header offset
- bool CurrentHeader(struct mach_header_64 *header, off_t *offset);
+ bool CurrentHeader(struct mach_header_64* header, off_t* offset);
private:
// Locate (if any) the header offset for |cpu_type| and return in |offset|.
// Return true if found, false otherwise.
bool FindHeader(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
- off_t &offset);
+ off_t& offset);
// Process an individual header starting at |offset| from the start of the
// file. Return true if successful, false otherwise.
@@ -91,27 +90,27 @@ class MachoWalker {
int file_;
// Memory location to read from.
- void *memory_;
+ void* memory_;
// Size of the memory segment we can read from.
size_t memory_size_;
// User specified callback & context
LoadCommandCallback callback_;
- void *callback_context_;
+ void* callback_context_;
// Current header, size, and offset. The mach_header_64 is used for both
// 32-bit and 64-bit headers because they only differ in their last field
// (reserved). By adding the |current_header_size_| and the
// |current_header_offset_|, you can determine the offset in the file just
// after the header.
- struct mach_header_64 *current_header_;
+ struct mach_header_64* current_header_;
unsigned long current_header_size_;
off_t current_header_offset_;
private:
- MachoWalker(const MachoWalker &);
- MachoWalker &operator=(const MachoWalker &);
+ MachoWalker(const MachoWalker&);
+ MachoWalker& operator=(const MachoWalker&);
};
} // namespace MacFileUtilities
diff --git a/src/common/mac/minidump_upload.m b/src/common/mac/minidump_upload.m
new file mode 100644
index 00000000..d8e2b24a
--- /dev/null
+++ b/src/common/mac/minidump_upload.m
@@ -0,0 +1,134 @@
+// Copyright 2006 Google LLC
+//
+// 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 LLC 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.
+
+// minidump_upload.m: Upload a minidump to a HTTP server. The upload is sent as
+// a multipart/form-data POST request with the following parameters:
+// prod: the product name
+// ver: the product version
+// symbol_file: the breakpad format symbol file
+
+#import <unistd.h>
+
+#import <Foundation/Foundation.h>
+
+#import "common/mac/HTTPMultipartUpload.h"
+
+typedef struct {
+ NSString* minidumpPath;
+ NSString* uploadURLStr;
+ NSString* product;
+ NSString* version;
+ BOOL success;
+} Options;
+
+//=============================================================================
+static void Start(Options* options) {
+ NSURL* url = [NSURL URLWithString:options->uploadURLStr];
+ HTTPMultipartUpload* ul = [[HTTPMultipartUpload alloc] initWithURL:url];
+ NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
+
+ // Add parameters
+ [parameters setObject:options->product forKey:@"prod"];
+ [parameters setObject:options->version forKey:@"ver"];
+ [ul setParameters:parameters];
+
+ // Add file
+ [ul addFileAtPath:options->minidumpPath name:@"upload_file_minidump"];
+
+ // Send it
+ NSError* error = nil;
+ NSData* data = [ul send:&error];
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+
+ NSLog(@"Send: %@", error ? [error description] : @"No Error");
+ NSLog(@"Response: %ld", (long)[[ul response] statusCode]);
+ NSLog(@"Result: %lu bytes\n%@", (unsigned long)[data length], result);
+
+ [result release];
+ [ul release];
+ options->success = !error;
+}
+
+//=============================================================================
+static void Usage(int argc, const char* argv[]) {
+ fprintf(stderr, "Submit minidump information.\n");
+ fprintf(stderr,
+ "Usage: %s -p <product> -v <version> <minidump> "
+ "<upload-URL>\n",
+ argv[0]);
+ fprintf(stderr, "<minidump> should be a minidump.\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, "p:v:h?")) != -1) {
+ switch (ch) {
+ case 'p':
+ options->product = [NSString stringWithUTF8String:optarg];
+ break;
+ case 'v':
+ options->version = [NSString stringWithUTF8String:optarg];
+ break;
+
+ 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);
+ }
+
+ options->minidumpPath = [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;
+}
diff --git a/src/common/mac/scoped_task_suspend-inl.h b/src/common/mac/scoped_task_suspend-inl.h
index d6d1bef9..a4957d7a 100644
--- a/src/common/mac/scoped_task_suspend-inl.h
+++ b/src/common/mac/scoped_task_suspend-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/string_utilities.cc b/src/common/mac/string_utilities.cc
index 07c0f426..861029d4 100644
--- a/src/common/mac/string_utilities.cc
+++ b/src/common/mac/string_utilities.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -48,12 +47,12 @@ std::string ConvertToString(CFStringRef str) {
CFStringGetBytes(str, CFRangeMake(0, length), kCFStringEncodingUTF8, 0,
false, buffer.get(), maxUTF8Length, &actualUTF8Length);
buffer[actualUTF8Length] = 0;
- result.assign((const char *)buffer.get());
+ result.assign((const char*)buffer.get());
return result;
}
-unsigned int IntegerValueAtIndex(string &str, unsigned int idx) {
+unsigned int IntegerValueAtIndex(string& str, unsigned int idx) {
string digits("0123456789"), temp;
size_t start = 0;
size_t end;
diff --git a/src/common/mac/string_utilities.h b/src/common/mac/string_utilities.h
index 6d89c834..de282a94 100644
--- a/src/common/mac/string_utilities.h
+++ b/src/common/mac/string_utilities.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -45,7 +44,7 @@ string ConvertToString(CFStringRef str);
// Return the idx'th decimal integer in str, separated by non-decimal-digits
// E.g., str = 10.4.8, idx = 1 -> 4
-unsigned int IntegerValueAtIndex(string &str, unsigned int idx);
+unsigned int IntegerValueAtIndex(string& str, unsigned int idx);
} // namespace MacStringUtils
diff --git a/src/common/mac/super_fat_arch.h b/src/common/mac/super_fat_arch.h
index 501c8652..046fe166 100644
--- a/src/common/mac/super_fat_arch.h
+++ b/src/common/mac/super_fat_arch.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2015, Google Inc.
-// All rights reserved.
+// Copyright 2015 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// 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
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -57,7 +56,7 @@ class SuperFatArch {
align(0) {
}
- explicit SuperFatArch(const struct fat_arch &arch) :
+ explicit SuperFatArch(const struct fat_arch& arch) :
cputype(arch.cputype),
cpusubtype(arch.cpusubtype),
offset(arch.offset),
diff --git a/src/common/mac/testing/GTMSenTestCase.h b/src/common/mac/testing/GTMSenTestCase.h
index ce3d9022..cfef3ef1 100644
--- a/src/common/mac/testing/GTMSenTestCase.h
+++ b/src/common/mac/testing/GTMSenTestCase.h
@@ -1,7 +1,7 @@
//
// GTMSenTestCase.h
//
-// Copyright 2007-2008 Google Inc.
+// Copyright 2007-2008 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
diff --git a/src/common/mac/testing/GTMSenTestCase.m b/src/common/mac/testing/GTMSenTestCase.m
index 162f01e9..eb9351bf 100644
--- a/src/common/mac/testing/GTMSenTestCase.m
+++ b/src/common/mac/testing/GTMSenTestCase.m
@@ -1,7 +1,7 @@
//
// GTMSenTestCase.m
//
-// Copyright 2007-2008 Google Inc.
+// Copyright 2007-2008 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy