diff options
author | Elliott Hughes <enh@google.com> | 2023-08-11 01:56:02 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-08-11 01:56:02 +0000 |
commit | 1317aa642182906c0d8ab5496dd3025632e22022 (patch) | |
tree | f98d11d6a158167e19fc9141c79d877280a616a6 /src/common/mac | |
parent | 8d0176459cfc11e28e9427a7eadcf7a42f654f62 (diff) | |
parent | c9c160dbfd52b61faae9473c1b18c1a0f7869908 (diff) | |
download | google-breakpad-1317aa642182906c0d8ab5496dd3025632e22022.tar.gz |
Upgrade google-breakpad to v2023.01.27 am: 332a4371ed am: c3c25b3748 am: 4e7c6460d7 am: c9c160dbfd
Original change: https://android-review.googlesource.com/c/platform/external/google-breakpad/+/2704174
Change-Id: I95bc0a6692c028156ded7502fadc728415e92f38
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'src/common/mac')
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 §ion, +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, §ion_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 §ion, + 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 §ion, - 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 §ion) { + 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 §ion, - 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 §ion) = 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 §ion, - 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 §ion)); + 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 §ion_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, §ion_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 |