summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad.mm
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad.mm')
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad.mm916
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, &params, 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,
- &params,
- 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;
- }
-}