diff options
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad.mm')
-rw-r--r-- | toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad.mm | 916 |
1 files changed, 0 insertions, 916 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad.mm b/toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad.mm deleted file mode 100644 index ce635bd27..000000000 --- a/toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad.mm +++ /dev/null @@ -1,916 +0,0 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#define IGNORE_DEBUGGER "BREAKPAD_IGNORE_DEBUGGER" - -#import "client/ios/Breakpad.h" - -#include <assert.h> -#import <Foundation/Foundation.h> -#include <pthread.h> -#include <sys/stat.h> -#include <sys/sysctl.h> - -#import "client/ios/handler/ios_exception_minidump_generator.h" -#import "client/mac/crash_generation/ConfigFile.h" -#import "client/mac/handler/exception_handler.h" -#import "client/mac/handler/minidump_generator.h" -#import "client/mac/sender/uploader.h" -#import "client/mac/handler/protected_memory_allocator.h" -#import "common/simple_string_dictionary.h" - -#if !defined(__EXCEPTIONS) || (__clang__ && !__has_feature(cxx_exceptions)) -// This file uses C++ try/catch (but shouldn't). Duplicate the macros from -// <c++/4.2.1/exception_defines.h> allowing this file to work properly with -// exceptions disabled even when other C++ libraries are used. #undef the try -// and catch macros first in case libstdc++ is in use and has already provided -// its own definitions. -#undef try -#define try if (true) -#undef catch -#define catch(X) if (false) -#endif // __EXCEPTIONS - -using google_breakpad::ConfigFile; -using google_breakpad::EnsureDirectoryPathExists; -using google_breakpad::SimpleStringDictionary; - -//============================================================================= -// We want any memory allocations which are used by breakpad during the -// exception handling process (after a crash has happened) to be read-only -// to prevent them from being smashed before a crash occurs. Unfortunately -// we cannot protect against smashes to our exception handling thread's -// stack. -// -// NOTE: Any memory allocations which are not used during the exception -// handling process may be allocated in the normal ways. -// -// The ProtectedMemoryAllocator class provides an Allocate() method which -// we'll using in conjunction with placement operator new() to control -// allocation of C++ objects. Note that we don't use operator delete() -// but instead call the objects destructor directly: object->~ClassName(); -// -ProtectedMemoryAllocator *gMasterAllocator = NULL; -ProtectedMemoryAllocator *gKeyValueAllocator = NULL; -ProtectedMemoryAllocator *gBreakpadAllocator = NULL; - -// Mutex for thread-safe access to the key/value dictionary used by breakpad. -// It's a global instead of an instance variable of Breakpad -// since it can't live in a protected memory area. -pthread_mutex_t gDictionaryMutex; - -//============================================================================= -// Stack-based object for thread-safe access to a memory-protected region. -// It's assumed that normally the memory block (allocated by the allocator) -// is protected (read-only). Creating a stack-based instance of -// ProtectedMemoryLocker will unprotect this block after taking the lock. -// Its destructor will first re-protect the memory then release the lock. -class ProtectedMemoryLocker { - public: - ProtectedMemoryLocker(pthread_mutex_t *mutex, - ProtectedMemoryAllocator *allocator) - : mutex_(mutex), - allocator_(allocator) { - // Lock the mutex - __attribute__((unused)) int rv = pthread_mutex_lock(mutex_); - assert(rv == 0); - - // Unprotect the memory - allocator_->Unprotect(); - } - - ~ProtectedMemoryLocker() { - // First protect the memory - allocator_->Protect(); - - // Then unlock the mutex - __attribute__((unused)) int rv = pthread_mutex_unlock(mutex_); - assert(rv == 0); - }; - - private: - ProtectedMemoryLocker(); - ProtectedMemoryLocker(const ProtectedMemoryLocker&); - ProtectedMemoryLocker& operator=(const ProtectedMemoryLocker&); - - pthread_mutex_t *mutex_; - ProtectedMemoryAllocator *allocator_; -}; - -//============================================================================= -class Breakpad { - public: - // factory method - static Breakpad *Create(NSDictionary *parameters) { - // Allocate from our special allocation pool - Breakpad *breakpad = - new (gBreakpadAllocator->Allocate(sizeof(Breakpad))) - Breakpad(); - - if (!breakpad) - return NULL; - - if (!breakpad->Initialize(parameters)) { - // Don't use operator delete() here since we allocated from special pool - breakpad->~Breakpad(); - return NULL; - } - - return breakpad; - } - - ~Breakpad(); - - void SetKeyValue(NSString *key, NSString *value); - NSString *KeyValue(NSString *key); - void RemoveKeyValue(NSString *key); - NSArray *CrashReportsToUpload(); - NSString *NextCrashReportToUpload(); - NSDictionary *NextCrashReportConfiguration(); - void UploadNextReport(NSDictionary *server_parameters); - void UploadReportWithConfiguration(NSDictionary *configuration, - NSDictionary *server_parameters); - void UploadData(NSData *data, NSString *name, - NSDictionary *server_parameters); - void HandleNetworkResponse(NSDictionary *configuration, - NSData *data, - NSError *error); - NSDictionary *GenerateReport(NSDictionary *server_parameters); - - private: - Breakpad() - : handler_(NULL), - config_params_(NULL) {} - - bool Initialize(NSDictionary *parameters); - - bool ExtractParameters(NSDictionary *parameters); - - // Dispatches to HandleMinidump() - static bool HandleMinidumpCallback(const char *dump_dir, - const char *minidump_id, - void *context, bool succeeded); - - bool HandleMinidump(const char *dump_dir, - const char *minidump_id); - - // NSException handler - static void UncaughtExceptionHandler(NSException *exception); - - // Handle an uncaught NSException. - void HandleUncaughtException(NSException *exception); - - // Since ExceptionHandler (w/o namespace) is defined as typedef in OSX's - // MachineExceptions.h, we have to explicitly name the handler. - google_breakpad::ExceptionHandler *handler_; // The actual handler (STRONG) - - SimpleStringDictionary *config_params_; // Create parameters (STRONG) - - ConfigFile config_file_; - - // A static reference to the current Breakpad instance. Used for handling - // NSException. - static Breakpad *current_breakpad_; -}; - -Breakpad *Breakpad::current_breakpad_ = NULL; - -#pragma mark - -#pragma mark Helper functions - -//============================================================================= -// Helper functions - -//============================================================================= -static BOOL IsDebuggerActive() { - BOOL result = NO; - NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults]; - - // We check both defaults and the environment variable here - - BOOL ignoreDebugger = [stdDefaults boolForKey:@IGNORE_DEBUGGER]; - - if (!ignoreDebugger) { - char *ignoreDebuggerStr = getenv(IGNORE_DEBUGGER); - ignoreDebugger = - (ignoreDebuggerStr ? strtol(ignoreDebuggerStr, NULL, 10) : 0) != 0; - } - - if (!ignoreDebugger) { - pid_t pid = getpid(); - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; - int mibSize = sizeof(mib) / sizeof(int); - size_t actualSize; - - if (sysctl(mib, mibSize, NULL, &actualSize, NULL, 0) == 0) { - struct kinfo_proc *info = (struct kinfo_proc *)malloc(actualSize); - - if (info) { - // This comes from looking at the Darwin xnu Kernel - if (sysctl(mib, mibSize, info, &actualSize, NULL, 0) == 0) - result = (info->kp_proc.p_flag & P_TRACED) ? YES : NO; - - free(info); - } - } - } - - return result; -} - -//============================================================================= -bool Breakpad::HandleMinidumpCallback(const char *dump_dir, - const char *minidump_id, - void *context, bool succeeded) { - Breakpad *breakpad = (Breakpad *)context; - - // If our context is damaged or something, just return false to indicate that - // the handler should continue without us. - if (!breakpad || !succeeded) - return false; - - return breakpad->HandleMinidump(dump_dir, minidump_id); -} - -//============================================================================= -void Breakpad::UncaughtExceptionHandler(NSException *exception) { - NSSetUncaughtExceptionHandler(NULL); - if (current_breakpad_) { - current_breakpad_->HandleUncaughtException(exception); - BreakpadRelease(current_breakpad_); - } -} - -//============================================================================= -#pragma mark - - -//============================================================================= -bool Breakpad::Initialize(NSDictionary *parameters) { - // Initialize - current_breakpad_ = this; - config_params_ = NULL; - handler_ = NULL; - - // Gather any user specified parameters - if (!ExtractParameters(parameters)) { - return false; - } - - // Check for debugger - if (IsDebuggerActive()) { - return true; - } - - // Create the handler (allocating it in our special protected pool) - handler_ = - new (gBreakpadAllocator->Allocate( - sizeof(google_breakpad::ExceptionHandler))) - google_breakpad::ExceptionHandler( - config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY), - 0, &HandleMinidumpCallback, this, true, 0); - NSSetUncaughtExceptionHandler(&Breakpad::UncaughtExceptionHandler); - return true; -} - -//============================================================================= -Breakpad::~Breakpad() { - NSSetUncaughtExceptionHandler(NULL); - current_breakpad_ = NULL; - // Note that we don't use operator delete() on these pointers, - // since they were allocated by ProtectedMemoryAllocator objects. - // - if (config_params_) { - config_params_->~SimpleStringDictionary(); - } - - if (handler_) - handler_->~ExceptionHandler(); -} - -//============================================================================= -bool Breakpad::ExtractParameters(NSDictionary *parameters) { - NSString *serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE]; - NSString *display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY]; - NSString *product = [parameters objectForKey:@BREAKPAD_PRODUCT]; - NSString *version = [parameters objectForKey:@BREAKPAD_VERSION]; - NSString *urlStr = [parameters objectForKey:@BREAKPAD_URL]; - NSString *vendor = - [parameters objectForKey:@BREAKPAD_VENDOR]; - // We check both parameters and the environment variable here. - char *envVarDumpSubdirectory = getenv(BREAKPAD_DUMP_DIRECTORY); - NSString *dumpSubdirectory = envVarDumpSubdirectory ? - [NSString stringWithUTF8String:envVarDumpSubdirectory] : - [parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY]; - - NSDictionary *serverParameters = - [parameters objectForKey:@BREAKPAD_SERVER_PARAMETER_DICT]; - - if (!product) - product = [parameters objectForKey:@"CFBundleName"]; - - if (!display) { - display = [parameters objectForKey:@"CFBundleDisplayName"]; - if (!display) { - display = product; - } - } - - if (!version.length) // Default nil or empty string to CFBundleVersion - version = [parameters objectForKey:@"CFBundleVersion"]; - - if (!vendor) { - vendor = @"Vendor not specified"; - } - - if (!dumpSubdirectory) { - NSString *cachePath = - [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, - NSUserDomainMask, - YES) - objectAtIndex:0]; - dumpSubdirectory = - [cachePath stringByAppendingPathComponent:@kDefaultLibrarySubdirectory]; - - EnsureDirectoryPathExists(dumpSubdirectory); - } - - // The product, version, and URL are required values. - if (![product length]) { - return false; - } - - if (![version length]) { - return false; - } - - if (![urlStr length]) { - return false; - } - - config_params_ = - new (gKeyValueAllocator->Allocate(sizeof(SimpleStringDictionary)) ) - SimpleStringDictionary(); - - SimpleStringDictionary &dictionary = *config_params_; - - dictionary.SetKeyValue(BREAKPAD_SERVER_TYPE, [serverType UTF8String]); - dictionary.SetKeyValue(BREAKPAD_PRODUCT_DISPLAY, [display UTF8String]); - dictionary.SetKeyValue(BREAKPAD_PRODUCT, [product UTF8String]); - dictionary.SetKeyValue(BREAKPAD_VERSION, [version UTF8String]); - dictionary.SetKeyValue(BREAKPAD_URL, [urlStr UTF8String]); - dictionary.SetKeyValue(BREAKPAD_VENDOR, [vendor UTF8String]); - dictionary.SetKeyValue(BREAKPAD_DUMP_DIRECTORY, - [dumpSubdirectory UTF8String]); - - struct timeval tv; - gettimeofday(&tv, NULL); - char timeStartedString[32]; - sprintf(timeStartedString, "%zd", tv.tv_sec); - dictionary.SetKeyValue(BREAKPAD_PROCESS_START_TIME, timeStartedString); - - if (serverParameters) { - // For each key-value pair, call BreakpadAddUploadParameter() - NSEnumerator *keyEnumerator = [serverParameters keyEnumerator]; - NSString *aParameter; - while ((aParameter = [keyEnumerator nextObject])) { - BreakpadAddUploadParameter(this, aParameter, - [serverParameters objectForKey:aParameter]); - } - } - return true; -} - -//============================================================================= -void Breakpad::SetKeyValue(NSString *key, NSString *value) { - // We allow nil values. This is the same as removing the keyvalue. - if (!config_params_ || !key) - return; - - config_params_->SetKeyValue([key UTF8String], [value UTF8String]); -} - -//============================================================================= -NSString *Breakpad::KeyValue(NSString *key) { - if (!config_params_ || !key) - return nil; - - const char *value = config_params_->GetValueForKey([key UTF8String]); - return value ? [NSString stringWithUTF8String:value] : nil; -} - -//============================================================================= -void Breakpad::RemoveKeyValue(NSString *key) { - if (!config_params_ || !key) return; - - config_params_->RemoveKey([key UTF8String]); -} - -//============================================================================= -NSArray *Breakpad::CrashReportsToUpload() { - NSString *directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); - if (!directory) - return nil; - NSArray *dirContents = [[NSFileManager defaultManager] - contentsOfDirectoryAtPath:directory error:nil]; - NSArray *configs = [dirContents filteredArrayUsingPredicate:[NSPredicate - predicateWithFormat:@"self BEGINSWITH 'Config-'"]]; - return configs; -} - -//============================================================================= -NSString *Breakpad::NextCrashReportToUpload() { - NSString *directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); - if (!directory) - return nil; - NSString *config = [CrashReportsToUpload() lastObject]; - if (!config) - return nil; - return [NSString stringWithFormat:@"%@/%@", directory, config]; -} - -//============================================================================= -NSDictionary *Breakpad::NextCrashReportConfiguration() { - return [Uploader readConfigurationDataFromFile:NextCrashReportToUpload()]; -} - -//============================================================================= -void Breakpad::HandleNetworkResponse(NSDictionary *configuration, - NSData *data, - NSError *error) { - Uploader *uploader = [[[Uploader alloc] - initWithConfig:configuration] autorelease]; - [uploader handleNetworkResponse:data withError:error]; -} - -//============================================================================= -void Breakpad::UploadReportWithConfiguration(NSDictionary *configuration, - NSDictionary *server_parameters) { - Uploader *uploader = [[[Uploader alloc] - initWithConfig:configuration] autorelease]; - if (!uploader) - return; - for (NSString *key in server_parameters) { - [uploader addServerParameter:[server_parameters objectForKey:key] - forKey:key]; - } - [uploader report]; -} - -//============================================================================= -void Breakpad::UploadNextReport(NSDictionary *server_parameters) { - NSDictionary *configuration = NextCrashReportConfiguration(); - if (configuration) { - return UploadReportWithConfiguration(configuration, server_parameters); - } -} - -//============================================================================= -void Breakpad::UploadData(NSData *data, NSString *name, - NSDictionary *server_parameters) { - NSMutableDictionary *config = [NSMutableDictionary dictionary]; - - SimpleStringDictionary::Iterator it(*config_params_); - while (const SimpleStringDictionary::Entry *next = it.Next()) { - [config setValue:[NSString stringWithUTF8String:next->value] - forKey:[NSString stringWithUTF8String:next->key]]; - } - - Uploader *uploader = - [[[Uploader alloc] initWithConfig:config] autorelease]; - for (NSString *key in server_parameters) { - [uploader addServerParameter:[server_parameters objectForKey:key] - forKey:key]; - } - [uploader uploadData:data name:name]; -} - -//============================================================================= -NSDictionary *Breakpad::GenerateReport(NSDictionary *server_parameters) { - NSString *dumpDirAsNSString = KeyValue(@BREAKPAD_DUMP_DIRECTORY); - if (!dumpDirAsNSString) - return nil; - const char *dumpDir = [dumpDirAsNSString UTF8String]; - - google_breakpad::MinidumpGenerator generator(mach_task_self(), - MACH_PORT_NULL); - std::string dumpId; - std::string dumpFilename = generator.UniqueNameInDirectory(dumpDir, &dumpId); - bool success = generator.Write(dumpFilename.c_str()); - if (!success) - return nil; - - SimpleStringDictionary params = *config_params_; - for (NSString *key in server_parameters) { - params.SetKeyValue([key UTF8String], - [[server_parameters objectForKey:key] UTF8String]); - } - ConfigFile config_file; - config_file.WriteFile(dumpDir, ¶ms, dumpDir, dumpId.c_str()); - - // Handle results. - NSMutableDictionary *result = [NSMutableDictionary dictionary]; - NSString *dumpFullPath = [NSString stringWithUTF8String:dumpFilename.c_str()]; - [result setValue:dumpFullPath - forKey:@BREAKPAD_OUTPUT_DUMP_FILE]; - [result setValue:[NSString stringWithUTF8String:config_file.GetFilePath()] - forKey:@BREAKPAD_OUTPUT_CONFIG_FILE]; - return result; -} - -//============================================================================= -bool Breakpad::HandleMinidump(const char *dump_dir, - const char *minidump_id) { - config_file_.WriteFile(dump_dir, - config_params_, - dump_dir, - minidump_id); - - // Return true here to indicate that we've processed things as much as we - // want. - return true; -} - -//============================================================================= -void Breakpad::HandleUncaughtException(NSException *exception) { - // Generate the minidump. - google_breakpad::IosExceptionMinidumpGenerator generator(exception); - const char *minidump_path = - config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY); - std::string minidump_id; - std::string minidump_filename = generator.UniqueNameInDirectory(minidump_path, - &minidump_id); - generator.Write(minidump_filename.c_str()); - - // Copy the config params and our custom parameter. This is necessary for 2 - // reasons: - // 1- config_params_ is protected. - // 2- If the application crash while trying to handle this exception, a usual - // report will be generated. This report must not contain these special - // keys. - SimpleStringDictionary params = *config_params_; - params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "type", "exception"); - params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "exceptionName", - [[exception name] UTF8String]); - params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "exceptionReason", - [[exception reason] UTF8String]); - - // And finally write the config file. - ConfigFile config_file; - config_file.WriteFile(minidump_path, - ¶ms, - minidump_path, - minidump_id.c_str()); -} - -//============================================================================= - -#pragma mark - -#pragma mark Public API - -//============================================================================= -BreakpadRef BreakpadCreate(NSDictionary *parameters) { - try { - // This is confusing. Our two main allocators for breakpad memory are: - // - gKeyValueAllocator for the key/value memory - // - gBreakpadAllocator for the Breakpad, ExceptionHandler, and other - // breakpad allocations which are accessed at exception handling time. - // - // But in order to avoid these two allocators themselves from being smashed, - // we'll protect them as well by allocating them with gMasterAllocator. - // - // gMasterAllocator itself will NOT be protected, but this doesn't matter, - // since once it does its allocations and locks the memory, smashes to - // itself don't affect anything we care about. - gMasterAllocator = - new ProtectedMemoryAllocator(sizeof(ProtectedMemoryAllocator) * 2); - - gKeyValueAllocator = - new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator))) - ProtectedMemoryAllocator(sizeof(SimpleStringDictionary)); - - // Create a mutex for use in accessing the SimpleStringDictionary - int mutexResult = pthread_mutex_init(&gDictionaryMutex, NULL); - if (mutexResult == 0) { - - // With the current compiler, gBreakpadAllocator is allocating 1444 bytes. - // Let's round up to the nearest page size. - // - int breakpad_pool_size = 4096; - - /* - sizeof(Breakpad) - + sizeof(google_breakpad::ExceptionHandler) - + sizeof( STUFF ALLOCATED INSIDE ExceptionHandler ) - */ - - gBreakpadAllocator = - new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator))) - ProtectedMemoryAllocator(breakpad_pool_size); - - // Stack-based autorelease pool for Breakpad::Create() obj-c code. - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - Breakpad *breakpad = Breakpad::Create(parameters); - - if (breakpad) { - // Make read-only to protect against memory smashers - gMasterAllocator->Protect(); - gKeyValueAllocator->Protect(); - gBreakpadAllocator->Protect(); - // Can uncomment this line to figure out how much space was actually - // allocated using this allocator - // printf("gBreakpadAllocator allocated size = %d\n", - // gBreakpadAllocator->GetAllocatedSize() ); - [pool release]; - return (BreakpadRef)breakpad; - } - - [pool release]; - } - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadCreate() : error\n"); - } - - if (gKeyValueAllocator) { - gKeyValueAllocator->~ProtectedMemoryAllocator(); - gKeyValueAllocator = NULL; - } - - if (gBreakpadAllocator) { - gBreakpadAllocator->~ProtectedMemoryAllocator(); - gBreakpadAllocator = NULL; - } - - delete gMasterAllocator; - gMasterAllocator = NULL; - - return NULL; -} - -//============================================================================= -void BreakpadRelease(BreakpadRef ref) { - try { - Breakpad *breakpad = (Breakpad *)ref; - - if (gMasterAllocator) { - gMasterAllocator->Unprotect(); - gKeyValueAllocator->Unprotect(); - gBreakpadAllocator->Unprotect(); - - breakpad->~Breakpad(); - - // Unfortunately, it's not possible to deallocate this stuff - // because the exception handling thread is still finishing up - // asynchronously at this point... OK, it could be done with - // locks, etc. But since BreakpadRelease() should usually only - // be called right before the process exits, it's not worth - // deallocating this stuff. -#if 0 - gKeyValueAllocator->~ProtectedMemoryAllocator(); - gBreakpadAllocator->~ProtectedMemoryAllocator(); - delete gMasterAllocator; - - gMasterAllocator = NULL; - gKeyValueAllocator = NULL; - gBreakpadAllocator = NULL; -#endif - - pthread_mutex_destroy(&gDictionaryMutex); - } - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadRelease() : error\n"); - } -} - -//============================================================================= -void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value) { - try { - // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; - - if (breakpad && key && gKeyValueAllocator) { - ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); - - breakpad->SetKeyValue(key, value); - } - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadSetKeyValue() : error\n"); - } -} - -void BreakpadAddUploadParameter(BreakpadRef ref, - NSString *key, - NSString *value) { - // The only difference, internally, between an upload parameter and - // a key value one that is set with BreakpadSetKeyValue is that we - // prepend the keyname with a special prefix. This informs the - // crash sender that the parameter should be sent along with the - // POST of the crash dump upload. - try { - Breakpad *breakpad = (Breakpad *)ref; - - if (breakpad && key && gKeyValueAllocator) { - ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); - - NSString *prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX - stringByAppendingString:key]; - breakpad->SetKeyValue(prefixedKey, value); - } - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadSetKeyValue() : error\n"); - } -} - -void BreakpadRemoveUploadParameter(BreakpadRef ref, - NSString *key) { - try { - // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; - - if (breakpad && key && gKeyValueAllocator) { - ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); - - NSString *prefixedKey = [NSString stringWithFormat:@"%@%@", - @BREAKPAD_SERVER_PARAMETER_PREFIX, key]; - breakpad->RemoveKeyValue(prefixedKey); - } - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadRemoveKeyValue() : error\n"); - } -} -//============================================================================= -NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key) { - NSString *value = nil; - - try { - // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; - - if (!breakpad || !key || !gKeyValueAllocator) - return nil; - - ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); - - value = breakpad->KeyValue(key); - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadKeyValue() : error\n"); - } - - return value; -} - -//============================================================================= -void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key) { - try { - // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; - - if (breakpad && key && gKeyValueAllocator) { - ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); - - breakpad->RemoveKeyValue(key); - } - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadRemoveKeyValue() : error\n"); - } -} - -//============================================================================= -int BreakpadGetCrashReportCount(BreakpadRef ref) { - try { - // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; - - if (breakpad) { - return static_cast<int>([breakpad->CrashReportsToUpload() count]); - } - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadGetCrashReportCount() : error\n"); - } - return false; -} - -//============================================================================= -void BreakpadUploadNextReport(BreakpadRef ref) { - BreakpadUploadNextReportWithParameters(ref, nil); -} - -//============================================================================= -NSDictionary *BreakpadGetNextReportConfiguration(BreakpadRef ref) { - try { - Breakpad *breakpad = (Breakpad *)ref; - if (breakpad) - return breakpad->NextCrashReportConfiguration(); - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadGetNextReportConfiguration() : error\n"); - } - return nil; -} - -//============================================================================= -void BreakpadUploadReportWithParametersAndConfiguration( - BreakpadRef ref, - NSDictionary *server_parameters, - NSDictionary *configuration) { - try { - Breakpad *breakpad = (Breakpad *)ref; - if (!breakpad || !configuration) - return; - breakpad->UploadReportWithConfiguration(configuration, server_parameters); - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, - "BreakpadUploadReportWithParametersAndConfiguration() : error\n"); - } - -} - -//============================================================================= -void BreakpadUploadNextReportWithParameters(BreakpadRef ref, - NSDictionary *server_parameters) { - try { - Breakpad *breakpad = (Breakpad *)ref; - if (!breakpad) - return; - NSDictionary *configuration = breakpad->NextCrashReportConfiguration(); - if (!configuration) - return; - return BreakpadUploadReportWithParametersAndConfiguration(ref, - server_parameters, - configuration); - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadUploadNextReportWithParameters() : error\n"); - } -} - -void BreakpadHandleNetworkResponse(BreakpadRef ref, - NSDictionary *configuration, - NSData *data, - NSError *error) { - try { - // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; - if (breakpad && configuration) - breakpad->HandleNetworkResponse(configuration,data, error); - - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadHandleNetworkResponse() : error\n"); - } -} - -//============================================================================= -void BreakpadUploadData(BreakpadRef ref, NSData *data, NSString *name, - NSDictionary *server_parameters) { - try { - // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; - - if (breakpad) { - breakpad->UploadData(data, name, server_parameters); - } - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadUploadData() : error\n"); - } -} - -//============================================================================= -NSDictionary *BreakpadGenerateReport(BreakpadRef ref, - NSDictionary *server_parameters) { - try { - // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; - - if (breakpad) { - return breakpad->GenerateReport(server_parameters); - } else { - return nil; - } - } catch(...) { // don't let exceptions leave this C API - fprintf(stderr, "BreakpadGenerateReport() : error\n"); - return nil; - } -} |