1*9712c20fSFrederick Mayle// Copyright 2011 Google LLC 2*9712c20fSFrederick Mayle// 3*9712c20fSFrederick Mayle// Redistribution and use in source and binary forms, with or without 4*9712c20fSFrederick Mayle// modification, are permitted provided that the following conditions are 5*9712c20fSFrederick Mayle// met: 6*9712c20fSFrederick Mayle// 7*9712c20fSFrederick Mayle// * Redistributions of source code must retain the above copyright 8*9712c20fSFrederick Mayle// notice, this list of conditions and the following disclaimer. 9*9712c20fSFrederick Mayle// * Redistributions in binary form must reproduce the above 10*9712c20fSFrederick Mayle// copyright notice, this list of conditions and the following disclaimer 11*9712c20fSFrederick Mayle// in the documentation and/or other materials provided with the 12*9712c20fSFrederick Mayle// distribution. 13*9712c20fSFrederick Mayle// * Neither the name of Google LLC nor the names of its 14*9712c20fSFrederick Mayle// contributors may be used to endorse or promote products derived from 15*9712c20fSFrederick Mayle// this software without specific prior written permission. 16*9712c20fSFrederick Mayle// 17*9712c20fSFrederick Mayle// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18*9712c20fSFrederick Mayle// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19*9712c20fSFrederick Mayle// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20*9712c20fSFrederick Mayle// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21*9712c20fSFrederick Mayle// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22*9712c20fSFrederick Mayle// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23*9712c20fSFrederick Mayle// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24*9712c20fSFrederick Mayle// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25*9712c20fSFrederick Mayle// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26*9712c20fSFrederick Mayle// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27*9712c20fSFrederick Mayle// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28*9712c20fSFrederick Mayle 29*9712c20fSFrederick Mayle#define IGNORE_DEBUGGER "BREAKPAD_IGNORE_DEBUGGER" 30*9712c20fSFrederick Mayle 31*9712c20fSFrederick Mayle#import "client/ios/Breakpad.h" 32*9712c20fSFrederick Mayle 33*9712c20fSFrederick Mayle#include <assert.h> 34*9712c20fSFrederick Mayle#import <Foundation/Foundation.h> 35*9712c20fSFrederick Mayle#include <pthread.h> 36*9712c20fSFrederick Mayle#include <sys/stat.h> 37*9712c20fSFrederick Mayle#include <sys/sysctl.h> 38*9712c20fSFrederick Mayle#include <TargetConditionals.h> 39*9712c20fSFrederick Mayle 40*9712c20fSFrederick Mayle#include <string> 41*9712c20fSFrederick Mayle 42*9712c20fSFrederick Mayle#import "client/ios/handler/ios_exception_minidump_generator.h" 43*9712c20fSFrederick Mayle#import "client/mac/crash_generation/ConfigFile.h" 44*9712c20fSFrederick Mayle#import "client/mac/handler/minidump_generator.h" 45*9712c20fSFrederick Mayle#import "client/mac/handler/protected_memory_allocator.h" 46*9712c20fSFrederick Mayle#import "client/mac/sender/uploader.h" 47*9712c20fSFrederick Mayle#import "common/long_string_dictionary.h" 48*9712c20fSFrederick Mayle 49*9712c20fSFrederick Mayle#if !TARGET_OS_TV && !TARGET_OS_WATCH 50*9712c20fSFrederick Mayle#import "client/mac/handler/exception_handler.h" 51*9712c20fSFrederick Mayle#else 52*9712c20fSFrederick Mayle#import "client/ios/exception_handler_no_mach.h" 53*9712c20fSFrederick Mayle#endif // !TARGET_OS_TV && !TARGET_OS_WATCH 54*9712c20fSFrederick Mayle 55*9712c20fSFrederick Mayle#if !defined(__EXCEPTIONS) || (__clang__ && !__has_feature(cxx_exceptions)) 56*9712c20fSFrederick Mayle// This file uses C++ try/catch (but shouldn't). Duplicate the macros from 57*9712c20fSFrederick Mayle// <c++/4.2.1/exception_defines.h> allowing this file to work properly with 58*9712c20fSFrederick Mayle// exceptions disabled even when other C++ libraries are used. #undef the try 59*9712c20fSFrederick Mayle// and catch macros first in case libstdc++ is in use and has already provided 60*9712c20fSFrederick Mayle// its own definitions. 61*9712c20fSFrederick Mayle#undef try 62*9712c20fSFrederick Mayle#define try if (true) 63*9712c20fSFrederick Mayle#undef catch 64*9712c20fSFrederick Mayle#define catch(X) if (false) 65*9712c20fSFrederick Mayle#endif // __EXCEPTIONS 66*9712c20fSFrederick Mayle 67*9712c20fSFrederick Mayleusing google_breakpad::ConfigFile; 68*9712c20fSFrederick Mayleusing google_breakpad::EnsureDirectoryPathExists; 69*9712c20fSFrederick Mayleusing google_breakpad::LongStringDictionary; 70*9712c20fSFrederick Mayle 71*9712c20fSFrederick Mayle//============================================================================= 72*9712c20fSFrederick Mayle// We want any memory allocations which are used by breakpad during the 73*9712c20fSFrederick Mayle// exception handling process (after a crash has happened) to be read-only 74*9712c20fSFrederick Mayle// to prevent them from being smashed before a crash occurs. Unfortunately 75*9712c20fSFrederick Mayle// we cannot protect against smashes to our exception handling thread's 76*9712c20fSFrederick Mayle// stack. 77*9712c20fSFrederick Mayle// 78*9712c20fSFrederick Mayle// NOTE: Any memory allocations which are not used during the exception 79*9712c20fSFrederick Mayle// handling process may be allocated in the normal ways. 80*9712c20fSFrederick Mayle// 81*9712c20fSFrederick Mayle// The ProtectedMemoryAllocator class provides an Allocate() method which 82*9712c20fSFrederick Mayle// we'll using in conjunction with placement operator new() to control 83*9712c20fSFrederick Mayle// allocation of C++ objects. Note that we don't use operator delete() 84*9712c20fSFrederick Mayle// but instead call the objects destructor directly: object->~ClassName(); 85*9712c20fSFrederick Mayle// 86*9712c20fSFrederick MayleProtectedMemoryAllocator* gMasterAllocator = NULL; 87*9712c20fSFrederick MayleProtectedMemoryAllocator* gKeyValueAllocator = NULL; 88*9712c20fSFrederick MayleProtectedMemoryAllocator* gBreakpadAllocator = NULL; 89*9712c20fSFrederick Mayle 90*9712c20fSFrederick Mayle// Mutex for thread-safe access to the key/value dictionary used by breakpad. 91*9712c20fSFrederick Mayle// It's a global instead of an instance variable of Breakpad 92*9712c20fSFrederick Mayle// since it can't live in a protected memory area. 93*9712c20fSFrederick Maylepthread_mutex_t gDictionaryMutex; 94*9712c20fSFrederick Mayle 95*9712c20fSFrederick Mayle//============================================================================= 96*9712c20fSFrederick Mayle// Stack-based object for thread-safe access to a memory-protected region. 97*9712c20fSFrederick Mayle// It's assumed that normally the memory block (allocated by the allocator) 98*9712c20fSFrederick Mayle// is protected (read-only). Creating a stack-based instance of 99*9712c20fSFrederick Mayle// ProtectedMemoryLocker will unprotect this block after taking the lock. 100*9712c20fSFrederick Mayle// Its destructor will first re-protect the memory then release the lock. 101*9712c20fSFrederick Mayleclass ProtectedMemoryLocker { 102*9712c20fSFrederick Mayle public: 103*9712c20fSFrederick Mayle ProtectedMemoryLocker(pthread_mutex_t* mutex, 104*9712c20fSFrederick Mayle ProtectedMemoryAllocator* allocator) 105*9712c20fSFrederick Mayle : mutex_(mutex), 106*9712c20fSFrederick Mayle allocator_(allocator) { 107*9712c20fSFrederick Mayle // Lock the mutex 108*9712c20fSFrederick Mayle __attribute__((unused)) int rv = pthread_mutex_lock(mutex_); 109*9712c20fSFrederick Mayle assert(rv == 0); 110*9712c20fSFrederick Mayle 111*9712c20fSFrederick Mayle // Unprotect the memory 112*9712c20fSFrederick Mayle allocator_->Unprotect(); 113*9712c20fSFrederick Mayle } 114*9712c20fSFrederick Mayle 115*9712c20fSFrederick Mayle ~ProtectedMemoryLocker() { 116*9712c20fSFrederick Mayle // First protect the memory 117*9712c20fSFrederick Mayle allocator_->Protect(); 118*9712c20fSFrederick Mayle 119*9712c20fSFrederick Mayle // Then unlock the mutex 120*9712c20fSFrederick Mayle __attribute__((unused)) int rv = pthread_mutex_unlock(mutex_); 121*9712c20fSFrederick Mayle assert(rv == 0); 122*9712c20fSFrederick Mayle } 123*9712c20fSFrederick Mayle 124*9712c20fSFrederick Mayle private: 125*9712c20fSFrederick Mayle ProtectedMemoryLocker(); 126*9712c20fSFrederick Mayle ProtectedMemoryLocker(const ProtectedMemoryLocker&); 127*9712c20fSFrederick Mayle ProtectedMemoryLocker& operator=(const ProtectedMemoryLocker&); 128*9712c20fSFrederick Mayle 129*9712c20fSFrederick Mayle pthread_mutex_t* mutex_; 130*9712c20fSFrederick Mayle ProtectedMemoryAllocator* allocator_; 131*9712c20fSFrederick Mayle}; 132*9712c20fSFrederick Mayle 133*9712c20fSFrederick Mayle//============================================================================= 134*9712c20fSFrederick Mayleclass Breakpad { 135*9712c20fSFrederick Mayle public: 136*9712c20fSFrederick Mayle // factory method 137*9712c20fSFrederick Mayle static Breakpad* Create(NSDictionary* parameters) { 138*9712c20fSFrederick Mayle // Allocate from our special allocation pool 139*9712c20fSFrederick Mayle Breakpad* breakpad = 140*9712c20fSFrederick Mayle new (gBreakpadAllocator->Allocate(sizeof(Breakpad))) 141*9712c20fSFrederick Mayle Breakpad(); 142*9712c20fSFrederick Mayle 143*9712c20fSFrederick Mayle if (!breakpad) 144*9712c20fSFrederick Mayle return NULL; 145*9712c20fSFrederick Mayle 146*9712c20fSFrederick Mayle if (!breakpad->Initialize(parameters)) { 147*9712c20fSFrederick Mayle // Don't use operator delete() here since we allocated from special pool 148*9712c20fSFrederick Mayle breakpad->~Breakpad(); 149*9712c20fSFrederick Mayle return NULL; 150*9712c20fSFrederick Mayle } 151*9712c20fSFrederick Mayle 152*9712c20fSFrederick Mayle return breakpad; 153*9712c20fSFrederick Mayle } 154*9712c20fSFrederick Mayle 155*9712c20fSFrederick Mayle ~Breakpad(); 156*9712c20fSFrederick Mayle 157*9712c20fSFrederick Mayle void SetKeyValue(NSString* key, NSString* value); 158*9712c20fSFrederick Mayle NSString* KeyValue(NSString* key); 159*9712c20fSFrederick Mayle void RemoveKeyValue(NSString* key); 160*9712c20fSFrederick Mayle NSArray* CrashReportsToUpload(); 161*9712c20fSFrederick Mayle NSString* NextCrashReportToUpload(); 162*9712c20fSFrederick Mayle NSDictionary* NextCrashReportConfiguration(); 163*9712c20fSFrederick Mayle NSDictionary* FixedUpCrashReportConfiguration(NSDictionary* configuration); 164*9712c20fSFrederick Mayle NSDate* DateOfMostRecentCrashReport(); 165*9712c20fSFrederick Mayle void UploadNextReport(NSDictionary* server_parameters); 166*9712c20fSFrederick Mayle void UploadReportWithConfiguration(NSDictionary* configuration, 167*9712c20fSFrederick Mayle NSDictionary* server_parameters, 168*9712c20fSFrederick Mayle BreakpadUploadCompletionCallback callback); 169*9712c20fSFrederick Mayle void UploadData(NSData* data, NSString* name, 170*9712c20fSFrederick Mayle NSDictionary* server_parameters); 171*9712c20fSFrederick Mayle void HandleNetworkResponse(NSDictionary* configuration, 172*9712c20fSFrederick Mayle NSData* data, 173*9712c20fSFrederick Mayle NSError* error); 174*9712c20fSFrederick Mayle NSDictionary* GenerateReport(NSDictionary* server_parameters); 175*9712c20fSFrederick Mayle 176*9712c20fSFrederick Mayle private: 177*9712c20fSFrederick Mayle Breakpad() 178*9712c20fSFrederick Mayle : handler_(NULL), 179*9712c20fSFrederick Mayle config_params_(NULL) {} 180*9712c20fSFrederick Mayle 181*9712c20fSFrederick Mayle bool Initialize(NSDictionary* parameters); 182*9712c20fSFrederick Mayle 183*9712c20fSFrederick Mayle bool ExtractParameters(NSDictionary* parameters); 184*9712c20fSFrederick Mayle 185*9712c20fSFrederick Mayle // Dispatches to HandleMinidump() 186*9712c20fSFrederick Mayle static bool HandleMinidumpCallback(const char* dump_dir, 187*9712c20fSFrederick Mayle const char* minidump_id, 188*9712c20fSFrederick Mayle void* context, bool succeeded); 189*9712c20fSFrederick Mayle 190*9712c20fSFrederick Mayle bool HandleMinidump(const char* dump_dir, 191*9712c20fSFrederick Mayle const char* minidump_id); 192*9712c20fSFrederick Mayle 193*9712c20fSFrederick Mayle // NSException handler 194*9712c20fSFrederick Mayle static void UncaughtExceptionHandler(NSException* exception); 195*9712c20fSFrederick Mayle 196*9712c20fSFrederick Mayle // Handle an uncaught NSException. 197*9712c20fSFrederick Mayle void HandleUncaughtException(NSException* exception); 198*9712c20fSFrederick Mayle 199*9712c20fSFrederick Mayle // Since ExceptionHandler (w/o namespace) is defined as typedef in OSX's 200*9712c20fSFrederick Mayle // MachineExceptions.h, we have to explicitly name the handler. 201*9712c20fSFrederick Mayle google_breakpad::ExceptionHandler* handler_; // The actual handler (STRONG) 202*9712c20fSFrederick Mayle 203*9712c20fSFrederick Mayle LongStringDictionary* config_params_; // Create parameters (STRONG) 204*9712c20fSFrederick Mayle 205*9712c20fSFrederick Mayle ConfigFile config_file_; 206*9712c20fSFrederick Mayle 207*9712c20fSFrederick Mayle // A static reference to the current Breakpad instance. Used for handling 208*9712c20fSFrederick Mayle // NSException. 209*9712c20fSFrederick Mayle static Breakpad* current_breakpad_; 210*9712c20fSFrederick Mayle}; 211*9712c20fSFrederick Mayle 212*9712c20fSFrederick MayleBreakpad* Breakpad::current_breakpad_ = NULL; 213*9712c20fSFrederick Mayle 214*9712c20fSFrederick Mayle#pragma mark - 215*9712c20fSFrederick Mayle#pragma mark Helper functions 216*9712c20fSFrederick Mayle 217*9712c20fSFrederick Mayle//============================================================================= 218*9712c20fSFrederick Mayle// Helper functions 219*9712c20fSFrederick Mayle 220*9712c20fSFrederick Mayle//============================================================================= 221*9712c20fSFrederick Maylestatic BOOL IsDebuggerActive() { 222*9712c20fSFrederick Mayle BOOL result = NO; 223*9712c20fSFrederick Mayle NSUserDefaults* stdDefaults = [NSUserDefaults standardUserDefaults]; 224*9712c20fSFrederick Mayle 225*9712c20fSFrederick Mayle // We check both defaults and the environment variable here 226*9712c20fSFrederick Mayle 227*9712c20fSFrederick Mayle BOOL ignoreDebugger = [stdDefaults boolForKey:@IGNORE_DEBUGGER]; 228*9712c20fSFrederick Mayle 229*9712c20fSFrederick Mayle if (!ignoreDebugger) { 230*9712c20fSFrederick Mayle char* ignoreDebuggerStr = getenv(IGNORE_DEBUGGER); 231*9712c20fSFrederick Mayle ignoreDebugger = 232*9712c20fSFrederick Mayle (ignoreDebuggerStr ? strtol(ignoreDebuggerStr, NULL, 10) : 0) != 0; 233*9712c20fSFrederick Mayle } 234*9712c20fSFrederick Mayle 235*9712c20fSFrederick Mayle if (!ignoreDebugger) { 236*9712c20fSFrederick Mayle pid_t pid = getpid(); 237*9712c20fSFrederick Mayle int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; 238*9712c20fSFrederick Mayle int mibSize = sizeof(mib) / sizeof(int); 239*9712c20fSFrederick Mayle size_t actualSize; 240*9712c20fSFrederick Mayle 241*9712c20fSFrederick Mayle if (sysctl(mib, mibSize, NULL, &actualSize, NULL, 0) == 0) { 242*9712c20fSFrederick Mayle struct kinfo_proc* info = (struct kinfo_proc*)malloc(actualSize); 243*9712c20fSFrederick Mayle 244*9712c20fSFrederick Mayle if (info) { 245*9712c20fSFrederick Mayle // This comes from looking at the Darwin xnu Kernel 246*9712c20fSFrederick Mayle if (sysctl(mib, mibSize, info, &actualSize, NULL, 0) == 0) 247*9712c20fSFrederick Mayle result = (info->kp_proc.p_flag & P_TRACED) ? YES : NO; 248*9712c20fSFrederick Mayle 249*9712c20fSFrederick Mayle free(info); 250*9712c20fSFrederick Mayle } 251*9712c20fSFrederick Mayle } 252*9712c20fSFrederick Mayle } 253*9712c20fSFrederick Mayle 254*9712c20fSFrederick Mayle return result; 255*9712c20fSFrederick Mayle} 256*9712c20fSFrederick Mayle 257*9712c20fSFrederick Mayle//============================================================================= 258*9712c20fSFrederick Maylebool Breakpad::HandleMinidumpCallback(const char* dump_dir, 259*9712c20fSFrederick Mayle const char* minidump_id, 260*9712c20fSFrederick Mayle void* context, bool succeeded) { 261*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)context; 262*9712c20fSFrederick Mayle 263*9712c20fSFrederick Mayle // If our context is damaged or something, just return false to indicate that 264*9712c20fSFrederick Mayle // the handler should continue without us. 265*9712c20fSFrederick Mayle if (!breakpad || !succeeded) 266*9712c20fSFrederick Mayle return false; 267*9712c20fSFrederick Mayle 268*9712c20fSFrederick Mayle return breakpad->HandleMinidump(dump_dir, minidump_id); 269*9712c20fSFrederick Mayle} 270*9712c20fSFrederick Mayle 271*9712c20fSFrederick Mayle//============================================================================= 272*9712c20fSFrederick Maylevoid Breakpad::UncaughtExceptionHandler(NSException* exception) { 273*9712c20fSFrederick Mayle NSSetUncaughtExceptionHandler(NULL); 274*9712c20fSFrederick Mayle if (current_breakpad_) { 275*9712c20fSFrederick Mayle current_breakpad_->HandleUncaughtException(exception); 276*9712c20fSFrederick Mayle BreakpadRelease(current_breakpad_); 277*9712c20fSFrederick Mayle } 278*9712c20fSFrederick Mayle} 279*9712c20fSFrederick Mayle 280*9712c20fSFrederick Mayle//============================================================================= 281*9712c20fSFrederick Mayle#pragma mark - 282*9712c20fSFrederick Mayle 283*9712c20fSFrederick Mayle//============================================================================= 284*9712c20fSFrederick Maylebool Breakpad::Initialize(NSDictionary* parameters) { 285*9712c20fSFrederick Mayle // Initialize 286*9712c20fSFrederick Mayle current_breakpad_ = this; 287*9712c20fSFrederick Mayle config_params_ = NULL; 288*9712c20fSFrederick Mayle handler_ = NULL; 289*9712c20fSFrederick Mayle 290*9712c20fSFrederick Mayle // Gather any user specified parameters 291*9712c20fSFrederick Mayle if (!ExtractParameters(parameters)) { 292*9712c20fSFrederick Mayle return false; 293*9712c20fSFrederick Mayle } 294*9712c20fSFrederick Mayle 295*9712c20fSFrederick Mayle // Check for debugger 296*9712c20fSFrederick Mayle if (IsDebuggerActive()) { 297*9712c20fSFrederick Mayle return true; 298*9712c20fSFrederick Mayle } 299*9712c20fSFrederick Mayle 300*9712c20fSFrederick Mayle // Create the handler (allocating it in our special protected pool) 301*9712c20fSFrederick Mayle handler_ = 302*9712c20fSFrederick Mayle new (gBreakpadAllocator->Allocate( 303*9712c20fSFrederick Mayle sizeof(google_breakpad::ExceptionHandler))) 304*9712c20fSFrederick Mayle google_breakpad::ExceptionHandler( 305*9712c20fSFrederick Mayle config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY), 306*9712c20fSFrederick Mayle 0, &HandleMinidumpCallback, this, true, 0); 307*9712c20fSFrederick Mayle NSSetUncaughtExceptionHandler(&Breakpad::UncaughtExceptionHandler); 308*9712c20fSFrederick Mayle return true; 309*9712c20fSFrederick Mayle} 310*9712c20fSFrederick Mayle 311*9712c20fSFrederick Mayle//============================================================================= 312*9712c20fSFrederick MayleBreakpad::~Breakpad() { 313*9712c20fSFrederick Mayle NSSetUncaughtExceptionHandler(NULL); 314*9712c20fSFrederick Mayle current_breakpad_ = NULL; 315*9712c20fSFrederick Mayle // Note that we don't use operator delete() on these pointers, 316*9712c20fSFrederick Mayle // since they were allocated by ProtectedMemoryAllocator objects. 317*9712c20fSFrederick Mayle // 318*9712c20fSFrederick Mayle if (config_params_) { 319*9712c20fSFrederick Mayle config_params_->~LongStringDictionary(); 320*9712c20fSFrederick Mayle } 321*9712c20fSFrederick Mayle 322*9712c20fSFrederick Mayle if (handler_) 323*9712c20fSFrederick Mayle handler_->~ExceptionHandler(); 324*9712c20fSFrederick Mayle} 325*9712c20fSFrederick Mayle 326*9712c20fSFrederick Mayle//============================================================================= 327*9712c20fSFrederick Maylebool Breakpad::ExtractParameters(NSDictionary* parameters) { 328*9712c20fSFrederick Mayle NSString* serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE]; 329*9712c20fSFrederick Mayle NSString* display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY]; 330*9712c20fSFrederick Mayle NSString* product = [parameters objectForKey:@BREAKPAD_PRODUCT]; 331*9712c20fSFrederick Mayle NSString* version = [parameters objectForKey:@BREAKPAD_VERSION]; 332*9712c20fSFrederick Mayle NSString* urlStr = [parameters objectForKey:@BREAKPAD_URL]; 333*9712c20fSFrederick Mayle NSString* vendor = 334*9712c20fSFrederick Mayle [parameters objectForKey:@BREAKPAD_VENDOR]; 335*9712c20fSFrederick Mayle // We check both parameters and the environment variable here. 336*9712c20fSFrederick Mayle char* envVarDumpSubdirectory = getenv(BREAKPAD_DUMP_DIRECTORY); 337*9712c20fSFrederick Mayle NSString* dumpSubdirectory = envVarDumpSubdirectory ? 338*9712c20fSFrederick Mayle [NSString stringWithUTF8String:envVarDumpSubdirectory] : 339*9712c20fSFrederick Mayle [parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY]; 340*9712c20fSFrederick Mayle 341*9712c20fSFrederick Mayle NSDictionary* serverParameters = 342*9712c20fSFrederick Mayle [parameters objectForKey:@BREAKPAD_SERVER_PARAMETER_DICT]; 343*9712c20fSFrederick Mayle 344*9712c20fSFrederick Mayle if (!product) 345*9712c20fSFrederick Mayle product = [parameters objectForKey:@"CFBundleName"]; 346*9712c20fSFrederick Mayle 347*9712c20fSFrederick Mayle if (!display) { 348*9712c20fSFrederick Mayle display = [parameters objectForKey:@"CFBundleDisplayName"]; 349*9712c20fSFrederick Mayle if (!display) { 350*9712c20fSFrederick Mayle display = product; 351*9712c20fSFrederick Mayle } 352*9712c20fSFrederick Mayle } 353*9712c20fSFrederick Mayle 354*9712c20fSFrederick Mayle if (!version.length) // Default nil or empty string to CFBundleVersion 355*9712c20fSFrederick Mayle version = [parameters objectForKey:@"CFBundleVersion"]; 356*9712c20fSFrederick Mayle 357*9712c20fSFrederick Mayle if (!vendor) { 358*9712c20fSFrederick Mayle vendor = @"Vendor not specified"; 359*9712c20fSFrederick Mayle } 360*9712c20fSFrederick Mayle 361*9712c20fSFrederick Mayle if (!dumpSubdirectory) { 362*9712c20fSFrederick Mayle NSString* cachePath = 363*9712c20fSFrederick Mayle [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, 364*9712c20fSFrederick Mayle NSUserDomainMask, 365*9712c20fSFrederick Mayle YES) 366*9712c20fSFrederick Mayle objectAtIndex:0]; 367*9712c20fSFrederick Mayle dumpSubdirectory = 368*9712c20fSFrederick Mayle [cachePath stringByAppendingPathComponent:@kDefaultLibrarySubdirectory]; 369*9712c20fSFrederick Mayle 370*9712c20fSFrederick Mayle EnsureDirectoryPathExists(dumpSubdirectory); 371*9712c20fSFrederick Mayle } 372*9712c20fSFrederick Mayle 373*9712c20fSFrederick Mayle // The product, version, and URL are required values. 374*9712c20fSFrederick Mayle if (![product length]) { 375*9712c20fSFrederick Mayle return false; 376*9712c20fSFrederick Mayle } 377*9712c20fSFrederick Mayle 378*9712c20fSFrederick Mayle if (![version length]) { 379*9712c20fSFrederick Mayle return false; 380*9712c20fSFrederick Mayle } 381*9712c20fSFrederick Mayle 382*9712c20fSFrederick Mayle if (![urlStr length]) { 383*9712c20fSFrederick Mayle return false; 384*9712c20fSFrederick Mayle } 385*9712c20fSFrederick Mayle 386*9712c20fSFrederick Mayle config_params_ = 387*9712c20fSFrederick Mayle new (gKeyValueAllocator->Allocate(sizeof(LongStringDictionary))) 388*9712c20fSFrederick Mayle LongStringDictionary(); 389*9712c20fSFrederick Mayle 390*9712c20fSFrederick Mayle LongStringDictionary& dictionary = *config_params_; 391*9712c20fSFrederick Mayle 392*9712c20fSFrederick Mayle dictionary.SetKeyValue(BREAKPAD_SERVER_TYPE, [serverType UTF8String]); 393*9712c20fSFrederick Mayle dictionary.SetKeyValue(BREAKPAD_PRODUCT_DISPLAY, [display UTF8String]); 394*9712c20fSFrederick Mayle dictionary.SetKeyValue(BREAKPAD_PRODUCT, [product UTF8String]); 395*9712c20fSFrederick Mayle dictionary.SetKeyValue(BREAKPAD_VERSION, [version UTF8String]); 396*9712c20fSFrederick Mayle dictionary.SetKeyValue(BREAKPAD_URL, [urlStr UTF8String]); 397*9712c20fSFrederick Mayle dictionary.SetKeyValue(BREAKPAD_VENDOR, [vendor UTF8String]); 398*9712c20fSFrederick Mayle dictionary.SetKeyValue(BREAKPAD_DUMP_DIRECTORY, 399*9712c20fSFrederick Mayle [dumpSubdirectory UTF8String]); 400*9712c20fSFrederick Mayle 401*9712c20fSFrederick Mayle struct timeval tv; 402*9712c20fSFrederick Mayle gettimeofday(&tv, NULL); 403*9712c20fSFrederick Mayle char timeStartedString[32]; 404*9712c20fSFrederick Mayle sprintf(timeStartedString, "%zd", tv.tv_sec); 405*9712c20fSFrederick Mayle dictionary.SetKeyValue(BREAKPAD_PROCESS_START_TIME, timeStartedString); 406*9712c20fSFrederick Mayle 407*9712c20fSFrederick Mayle if (serverParameters) { 408*9712c20fSFrederick Mayle // For each key-value pair, call BreakpadAddUploadParameter() 409*9712c20fSFrederick Mayle NSEnumerator* keyEnumerator = [serverParameters keyEnumerator]; 410*9712c20fSFrederick Mayle NSString* aParameter; 411*9712c20fSFrederick Mayle while ((aParameter = [keyEnumerator nextObject])) { 412*9712c20fSFrederick Mayle BreakpadAddUploadParameter(this, aParameter, 413*9712c20fSFrederick Mayle [serverParameters objectForKey:aParameter]); 414*9712c20fSFrederick Mayle } 415*9712c20fSFrederick Mayle } 416*9712c20fSFrederick Mayle return true; 417*9712c20fSFrederick Mayle} 418*9712c20fSFrederick Mayle 419*9712c20fSFrederick Mayle//============================================================================= 420*9712c20fSFrederick Maylevoid Breakpad::SetKeyValue(NSString* key, NSString* value) { 421*9712c20fSFrederick Mayle // We allow nil values. This is the same as removing the keyvalue. 422*9712c20fSFrederick Mayle if (!config_params_ || !key) 423*9712c20fSFrederick Mayle return; 424*9712c20fSFrederick Mayle 425*9712c20fSFrederick Mayle config_params_->SetKeyValue([key UTF8String], [value UTF8String]); 426*9712c20fSFrederick Mayle} 427*9712c20fSFrederick Mayle 428*9712c20fSFrederick Mayle//============================================================================= 429*9712c20fSFrederick MayleNSString* Breakpad::KeyValue(NSString* key) { 430*9712c20fSFrederick Mayle if (!config_params_ || !key) 431*9712c20fSFrederick Mayle return nil; 432*9712c20fSFrederick Mayle 433*9712c20fSFrederick Mayle const std::string value = config_params_->GetValueForKey([key UTF8String]); 434*9712c20fSFrederick Mayle return value.empty() ? nil : [NSString stringWithUTF8String:value.c_str()]; 435*9712c20fSFrederick Mayle} 436*9712c20fSFrederick Mayle 437*9712c20fSFrederick Mayle//============================================================================= 438*9712c20fSFrederick Maylevoid Breakpad::RemoveKeyValue(NSString* key) { 439*9712c20fSFrederick Mayle if (!config_params_ || !key) return; 440*9712c20fSFrederick Mayle 441*9712c20fSFrederick Mayle config_params_->RemoveKey([key UTF8String]); 442*9712c20fSFrederick Mayle} 443*9712c20fSFrederick Mayle 444*9712c20fSFrederick Mayle//============================================================================= 445*9712c20fSFrederick MayleNSArray* Breakpad::CrashReportsToUpload() { 446*9712c20fSFrederick Mayle NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); 447*9712c20fSFrederick Mayle if (!directory) 448*9712c20fSFrederick Mayle return nil; 449*9712c20fSFrederick Mayle NSArray* dirContents = [[NSFileManager defaultManager] 450*9712c20fSFrederick Mayle contentsOfDirectoryAtPath:directory error:nil]; 451*9712c20fSFrederick Mayle NSArray* configs = [dirContents filteredArrayUsingPredicate:[NSPredicate 452*9712c20fSFrederick Mayle predicateWithFormat:@"self BEGINSWITH 'Config-'"]]; 453*9712c20fSFrederick Mayle return configs; 454*9712c20fSFrederick Mayle} 455*9712c20fSFrederick Mayle 456*9712c20fSFrederick Mayle//============================================================================= 457*9712c20fSFrederick MayleNSString* Breakpad::NextCrashReportToUpload() { 458*9712c20fSFrederick Mayle NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); 459*9712c20fSFrederick Mayle if (!directory) 460*9712c20fSFrederick Mayle return nil; 461*9712c20fSFrederick Mayle NSString* config = [CrashReportsToUpload() lastObject]; 462*9712c20fSFrederick Mayle if (!config) 463*9712c20fSFrederick Mayle return nil; 464*9712c20fSFrederick Mayle return [NSString stringWithFormat:@"%@/%@", directory, config]; 465*9712c20fSFrederick Mayle} 466*9712c20fSFrederick Mayle 467*9712c20fSFrederick Mayle//============================================================================= 468*9712c20fSFrederick MayleNSDictionary* Breakpad::NextCrashReportConfiguration() { 469*9712c20fSFrederick Mayle NSDictionary* configuration = [Uploader readConfigurationDataFromFile:NextCrashReportToUpload()]; 470*9712c20fSFrederick Mayle return FixedUpCrashReportConfiguration(configuration); 471*9712c20fSFrederick Mayle} 472*9712c20fSFrederick Mayle 473*9712c20fSFrederick Mayle//============================================================================= 474*9712c20fSFrederick MayleNSDictionary* Breakpad::FixedUpCrashReportConfiguration(NSDictionary* configuration) { 475*9712c20fSFrederick Mayle NSMutableDictionary* fixedConfiguration = [[configuration mutableCopy] autorelease]; 476*9712c20fSFrederick Mayle // kReporterMinidumpDirectoryKey can become stale because the app's data container path includes 477*9712c20fSFrederick Mayle // an UUID that is not guaranteed to stay the same over time. 478*9712c20fSFrederick Mayle [fixedConfiguration setObject:KeyValue(@BREAKPAD_DUMP_DIRECTORY) 479*9712c20fSFrederick Mayle forKey:@kReporterMinidumpDirectoryKey]; 480*9712c20fSFrederick Mayle return fixedConfiguration; 481*9712c20fSFrederick Mayle} 482*9712c20fSFrederick Mayle 483*9712c20fSFrederick Mayle//============================================================================= 484*9712c20fSFrederick MayleNSDate* Breakpad::DateOfMostRecentCrashReport() { 485*9712c20fSFrederick Mayle NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); 486*9712c20fSFrederick Mayle if (!directory) { 487*9712c20fSFrederick Mayle return nil; 488*9712c20fSFrederick Mayle } 489*9712c20fSFrederick Mayle NSFileManager* fileManager = [NSFileManager defaultManager]; 490*9712c20fSFrederick Mayle NSArray* dirContents = [fileManager contentsOfDirectoryAtPath:directory error:nil]; 491*9712c20fSFrederick Mayle NSArray* dumps = [dirContents filteredArrayUsingPredicate:[NSPredicate 492*9712c20fSFrederick Mayle predicateWithFormat:@"self ENDSWITH '.dmp'"]]; 493*9712c20fSFrederick Mayle NSDate* mostRecentCrashReportDate = nil; 494*9712c20fSFrederick Mayle for (NSString* dump in dumps) { 495*9712c20fSFrederick Mayle NSString* filePath = [directory stringByAppendingPathComponent:dump]; 496*9712c20fSFrederick Mayle NSDate* crashReportDate = 497*9712c20fSFrederick Mayle [[fileManager attributesOfItemAtPath:filePath error:nil] fileCreationDate]; 498*9712c20fSFrederick Mayle if (!mostRecentCrashReportDate) { 499*9712c20fSFrederick Mayle mostRecentCrashReportDate = crashReportDate; 500*9712c20fSFrederick Mayle } else if (crashReportDate) { 501*9712c20fSFrederick Mayle mostRecentCrashReportDate = [mostRecentCrashReportDate laterDate:crashReportDate]; 502*9712c20fSFrederick Mayle } 503*9712c20fSFrederick Mayle } 504*9712c20fSFrederick Mayle return mostRecentCrashReportDate; 505*9712c20fSFrederick Mayle} 506*9712c20fSFrederick Mayle 507*9712c20fSFrederick Mayle//============================================================================= 508*9712c20fSFrederick Maylevoid Breakpad::HandleNetworkResponse(NSDictionary* configuration, 509*9712c20fSFrederick Mayle NSData* data, 510*9712c20fSFrederick Mayle NSError* error) { 511*9712c20fSFrederick Mayle Uploader* uploader = [[[Uploader alloc] 512*9712c20fSFrederick Mayle initWithConfig:configuration] autorelease]; 513*9712c20fSFrederick Mayle [uploader handleNetworkResponse:data withError:error]; 514*9712c20fSFrederick Mayle} 515*9712c20fSFrederick Mayle 516*9712c20fSFrederick Mayle//============================================================================= 517*9712c20fSFrederick Maylevoid Breakpad::UploadReportWithConfiguration( 518*9712c20fSFrederick Mayle NSDictionary* configuration, 519*9712c20fSFrederick Mayle NSDictionary* server_parameters, 520*9712c20fSFrederick Mayle BreakpadUploadCompletionCallback callback) { 521*9712c20fSFrederick Mayle Uploader* uploader = [[[Uploader alloc] 522*9712c20fSFrederick Mayle initWithConfig:configuration] autorelease]; 523*9712c20fSFrederick Mayle if (!uploader) 524*9712c20fSFrederick Mayle return; 525*9712c20fSFrederick Mayle for (NSString* key in server_parameters) { 526*9712c20fSFrederick Mayle [uploader addServerParameter:[server_parameters objectForKey:key] 527*9712c20fSFrederick Mayle forKey:key]; 528*9712c20fSFrederick Mayle } 529*9712c20fSFrederick Mayle if (callback) { 530*9712c20fSFrederick Mayle [uploader setUploadCompletionBlock:^(NSString* report_id, NSError* error) { 531*9712c20fSFrederick Mayle dispatch_async(dispatch_get_main_queue(), ^{ 532*9712c20fSFrederick Mayle callback(report_id, error); 533*9712c20fSFrederick Mayle }); 534*9712c20fSFrederick Mayle }]; 535*9712c20fSFrederick Mayle } 536*9712c20fSFrederick Mayle [uploader report]; 537*9712c20fSFrederick Mayle} 538*9712c20fSFrederick Mayle 539*9712c20fSFrederick Mayle//============================================================================= 540*9712c20fSFrederick Maylevoid Breakpad::UploadNextReport(NSDictionary* server_parameters) { 541*9712c20fSFrederick Mayle NSDictionary* configuration = NextCrashReportConfiguration(); 542*9712c20fSFrederick Mayle if (configuration) { 543*9712c20fSFrederick Mayle return UploadReportWithConfiguration(configuration, server_parameters, 544*9712c20fSFrederick Mayle nullptr); 545*9712c20fSFrederick Mayle } 546*9712c20fSFrederick Mayle} 547*9712c20fSFrederick Mayle 548*9712c20fSFrederick Mayle//============================================================================= 549*9712c20fSFrederick Maylevoid Breakpad::UploadData(NSData* data, NSString* name, 550*9712c20fSFrederick Mayle NSDictionary* server_parameters) { 551*9712c20fSFrederick Mayle NSMutableDictionary* config = [NSMutableDictionary dictionary]; 552*9712c20fSFrederick Mayle 553*9712c20fSFrederick Mayle LongStringDictionary::Iterator it(*config_params_); 554*9712c20fSFrederick Mayle while (const LongStringDictionary::Entry* next = it.Next()) { 555*9712c20fSFrederick Mayle [config setValue:[NSString stringWithUTF8String:next->value] 556*9712c20fSFrederick Mayle forKey:[NSString stringWithUTF8String:next->key]]; 557*9712c20fSFrederick Mayle } 558*9712c20fSFrederick Mayle 559*9712c20fSFrederick Mayle Uploader* uploader = 560*9712c20fSFrederick Mayle [[[Uploader alloc] initWithConfig:config] autorelease]; 561*9712c20fSFrederick Mayle for (NSString* key in server_parameters) { 562*9712c20fSFrederick Mayle [uploader addServerParameter:[server_parameters objectForKey:key] 563*9712c20fSFrederick Mayle forKey:key]; 564*9712c20fSFrederick Mayle } 565*9712c20fSFrederick Mayle [uploader uploadData:data name:name]; 566*9712c20fSFrederick Mayle} 567*9712c20fSFrederick Mayle 568*9712c20fSFrederick Mayle//============================================================================= 569*9712c20fSFrederick MayleNSDictionary* Breakpad::GenerateReport(NSDictionary* server_parameters) { 570*9712c20fSFrederick Mayle NSString* dumpDirAsNSString = KeyValue(@BREAKPAD_DUMP_DIRECTORY); 571*9712c20fSFrederick Mayle if (!dumpDirAsNSString) 572*9712c20fSFrederick Mayle return nil; 573*9712c20fSFrederick Mayle const char* dumpDir = [dumpDirAsNSString UTF8String]; 574*9712c20fSFrederick Mayle 575*9712c20fSFrederick Mayle google_breakpad::MinidumpGenerator generator(mach_task_self(), 576*9712c20fSFrederick Mayle MACH_PORT_NULL); 577*9712c20fSFrederick Mayle std::string dumpId; 578*9712c20fSFrederick Mayle std::string dumpFilename = generator.UniqueNameInDirectory(dumpDir, &dumpId); 579*9712c20fSFrederick Mayle bool success = generator.Write(dumpFilename.c_str()); 580*9712c20fSFrederick Mayle if (!success) 581*9712c20fSFrederick Mayle return nil; 582*9712c20fSFrederick Mayle 583*9712c20fSFrederick Mayle LongStringDictionary params = *config_params_; 584*9712c20fSFrederick Mayle for (NSString* key in server_parameters) { 585*9712c20fSFrederick Mayle params.SetKeyValue([key UTF8String], 586*9712c20fSFrederick Mayle [[server_parameters objectForKey:key] UTF8String]); 587*9712c20fSFrederick Mayle } 588*9712c20fSFrederick Mayle ConfigFile config_file; 589*9712c20fSFrederick Mayle config_file.WriteFile(dumpDir, ¶ms, dumpDir, dumpId.c_str()); 590*9712c20fSFrederick Mayle 591*9712c20fSFrederick Mayle // Handle results. 592*9712c20fSFrederick Mayle NSMutableDictionary* result = [NSMutableDictionary dictionary]; 593*9712c20fSFrederick Mayle NSString* dumpFullPath = [NSString stringWithUTF8String:dumpFilename.c_str()]; 594*9712c20fSFrederick Mayle [result setValue:dumpFullPath 595*9712c20fSFrederick Mayle forKey:@BREAKPAD_OUTPUT_DUMP_FILE]; 596*9712c20fSFrederick Mayle [result setValue:[NSString stringWithUTF8String:config_file.GetFilePath()] 597*9712c20fSFrederick Mayle forKey:@BREAKPAD_OUTPUT_CONFIG_FILE]; 598*9712c20fSFrederick Mayle return result; 599*9712c20fSFrederick Mayle} 600*9712c20fSFrederick Mayle 601*9712c20fSFrederick Mayle//============================================================================= 602*9712c20fSFrederick Maylebool Breakpad::HandleMinidump(const char* dump_dir, 603*9712c20fSFrederick Mayle const char* minidump_id) { 604*9712c20fSFrederick Mayle config_file_.WriteFile(dump_dir, 605*9712c20fSFrederick Mayle config_params_, 606*9712c20fSFrederick Mayle dump_dir, 607*9712c20fSFrederick Mayle minidump_id); 608*9712c20fSFrederick Mayle 609*9712c20fSFrederick Mayle // Return true here to indicate that we've processed things as much as we 610*9712c20fSFrederick Mayle // want. 611*9712c20fSFrederick Mayle return true; 612*9712c20fSFrederick Mayle} 613*9712c20fSFrederick Mayle 614*9712c20fSFrederick Mayle//============================================================================= 615*9712c20fSFrederick Maylevoid Breakpad::HandleUncaughtException(NSException* exception) { 616*9712c20fSFrederick Mayle // Generate the minidump. 617*9712c20fSFrederick Mayle google_breakpad::IosExceptionMinidumpGenerator generator(exception); 618*9712c20fSFrederick Mayle const std::string minidump_path = 619*9712c20fSFrederick Mayle config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY); 620*9712c20fSFrederick Mayle std::string minidump_id; 621*9712c20fSFrederick Mayle std::string minidump_filename = generator.UniqueNameInDirectory(minidump_path, 622*9712c20fSFrederick Mayle &minidump_id); 623*9712c20fSFrederick Mayle generator.Write(minidump_filename.c_str()); 624*9712c20fSFrederick Mayle 625*9712c20fSFrederick Mayle // Copy the config params and our custom parameter. This is necessary for 2 626*9712c20fSFrederick Mayle // reasons: 627*9712c20fSFrederick Mayle // 1- config_params_ is protected. 628*9712c20fSFrederick Mayle // 2- If the application crash while trying to handle this exception, a usual 629*9712c20fSFrederick Mayle // report will be generated. This report must not contain these special 630*9712c20fSFrederick Mayle // keys. 631*9712c20fSFrederick Mayle LongStringDictionary params = *config_params_; 632*9712c20fSFrederick Mayle params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "type", "exception"); 633*9712c20fSFrederick Mayle params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "exceptionName", 634*9712c20fSFrederick Mayle [[exception name] UTF8String]); 635*9712c20fSFrederick Mayle params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "exceptionReason", 636*9712c20fSFrederick Mayle [[exception reason] UTF8String]); 637*9712c20fSFrederick Mayle 638*9712c20fSFrederick Mayle // And finally write the config file. 639*9712c20fSFrederick Mayle ConfigFile config_file; 640*9712c20fSFrederick Mayle config_file.WriteFile(minidump_path.c_str(), 641*9712c20fSFrederick Mayle ¶ms, 642*9712c20fSFrederick Mayle minidump_path.c_str(), 643*9712c20fSFrederick Mayle minidump_id.c_str()); 644*9712c20fSFrederick Mayle} 645*9712c20fSFrederick Mayle 646*9712c20fSFrederick Mayle//============================================================================= 647*9712c20fSFrederick Mayle 648*9712c20fSFrederick Mayle#pragma mark - 649*9712c20fSFrederick Mayle#pragma mark Public API 650*9712c20fSFrederick Mayle 651*9712c20fSFrederick Mayle//============================================================================= 652*9712c20fSFrederick MayleBreakpadRef BreakpadCreate(NSDictionary* parameters) { 653*9712c20fSFrederick Mayle try { 654*9712c20fSFrederick Mayle // This is confusing. Our two main allocators for breakpad memory are: 655*9712c20fSFrederick Mayle // - gKeyValueAllocator for the key/value memory 656*9712c20fSFrederick Mayle // - gBreakpadAllocator for the Breakpad, ExceptionHandler, and other 657*9712c20fSFrederick Mayle // breakpad allocations which are accessed at exception handling time. 658*9712c20fSFrederick Mayle // 659*9712c20fSFrederick Mayle // But in order to avoid these two allocators themselves from being smashed, 660*9712c20fSFrederick Mayle // we'll protect them as well by allocating them with gMasterAllocator. 661*9712c20fSFrederick Mayle // 662*9712c20fSFrederick Mayle // gMasterAllocator itself will NOT be protected, but this doesn't matter, 663*9712c20fSFrederick Mayle // since once it does its allocations and locks the memory, smashes to 664*9712c20fSFrederick Mayle // itself don't affect anything we care about. 665*9712c20fSFrederick Mayle gMasterAllocator = 666*9712c20fSFrederick Mayle new ProtectedMemoryAllocator(sizeof(ProtectedMemoryAllocator) * 2); 667*9712c20fSFrederick Mayle 668*9712c20fSFrederick Mayle gKeyValueAllocator = 669*9712c20fSFrederick Mayle new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator))) 670*9712c20fSFrederick Mayle ProtectedMemoryAllocator(sizeof(LongStringDictionary)); 671*9712c20fSFrederick Mayle 672*9712c20fSFrederick Mayle // Create a mutex for use in accessing the LongStringDictionary 673*9712c20fSFrederick Mayle int mutexResult = pthread_mutex_init(&gDictionaryMutex, NULL); 674*9712c20fSFrederick Mayle if (mutexResult == 0) { 675*9712c20fSFrederick Mayle 676*9712c20fSFrederick Mayle // With the current compiler, gBreakpadAllocator is allocating 1444 bytes. 677*9712c20fSFrederick Mayle // Let's round up to the nearest page size. 678*9712c20fSFrederick Mayle // 679*9712c20fSFrederick Mayle int breakpad_pool_size = 4096; 680*9712c20fSFrederick Mayle 681*9712c20fSFrederick Mayle /* 682*9712c20fSFrederick Mayle sizeof(Breakpad) 683*9712c20fSFrederick Mayle + sizeof(google_breakpad::ExceptionHandler) 684*9712c20fSFrederick Mayle + sizeof( STUFF ALLOCATED INSIDE ExceptionHandler ) 685*9712c20fSFrederick Mayle */ 686*9712c20fSFrederick Mayle 687*9712c20fSFrederick Mayle gBreakpadAllocator = 688*9712c20fSFrederick Mayle new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator))) 689*9712c20fSFrederick Mayle ProtectedMemoryAllocator(breakpad_pool_size); 690*9712c20fSFrederick Mayle 691*9712c20fSFrederick Mayle // Stack-based autorelease pool for Breakpad::Create() obj-c code. 692*9712c20fSFrederick Mayle NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 693*9712c20fSFrederick Mayle Breakpad* breakpad = Breakpad::Create(parameters); 694*9712c20fSFrederick Mayle 695*9712c20fSFrederick Mayle if (breakpad) { 696*9712c20fSFrederick Mayle // Make read-only to protect against memory smashers 697*9712c20fSFrederick Mayle gMasterAllocator->Protect(); 698*9712c20fSFrederick Mayle gKeyValueAllocator->Protect(); 699*9712c20fSFrederick Mayle gBreakpadAllocator->Protect(); 700*9712c20fSFrederick Mayle // Can uncomment this line to figure out how much space was actually 701*9712c20fSFrederick Mayle // allocated using this allocator 702*9712c20fSFrederick Mayle // printf("gBreakpadAllocator allocated size = %d\n", 703*9712c20fSFrederick Mayle // gBreakpadAllocator->GetAllocatedSize() ); 704*9712c20fSFrederick Mayle [pool release]; 705*9712c20fSFrederick Mayle return (BreakpadRef)breakpad; 706*9712c20fSFrederick Mayle } 707*9712c20fSFrederick Mayle 708*9712c20fSFrederick Mayle [pool release]; 709*9712c20fSFrederick Mayle } 710*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 711*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadCreate() : error\n"); 712*9712c20fSFrederick Mayle } 713*9712c20fSFrederick Mayle 714*9712c20fSFrederick Mayle if (gKeyValueAllocator) { 715*9712c20fSFrederick Mayle gKeyValueAllocator->~ProtectedMemoryAllocator(); 716*9712c20fSFrederick Mayle gKeyValueAllocator = NULL; 717*9712c20fSFrederick Mayle } 718*9712c20fSFrederick Mayle 719*9712c20fSFrederick Mayle if (gBreakpadAllocator) { 720*9712c20fSFrederick Mayle gBreakpadAllocator->~ProtectedMemoryAllocator(); 721*9712c20fSFrederick Mayle gBreakpadAllocator = NULL; 722*9712c20fSFrederick Mayle } 723*9712c20fSFrederick Mayle 724*9712c20fSFrederick Mayle delete gMasterAllocator; 725*9712c20fSFrederick Mayle gMasterAllocator = NULL; 726*9712c20fSFrederick Mayle 727*9712c20fSFrederick Mayle return NULL; 728*9712c20fSFrederick Mayle} 729*9712c20fSFrederick Mayle 730*9712c20fSFrederick Mayle//============================================================================= 731*9712c20fSFrederick Maylevoid BreakpadRelease(BreakpadRef ref) { 732*9712c20fSFrederick Mayle try { 733*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 734*9712c20fSFrederick Mayle 735*9712c20fSFrederick Mayle if (gMasterAllocator) { 736*9712c20fSFrederick Mayle gMasterAllocator->Unprotect(); 737*9712c20fSFrederick Mayle gKeyValueAllocator->Unprotect(); 738*9712c20fSFrederick Mayle gBreakpadAllocator->Unprotect(); 739*9712c20fSFrederick Mayle 740*9712c20fSFrederick Mayle breakpad->~Breakpad(); 741*9712c20fSFrederick Mayle 742*9712c20fSFrederick Mayle // Unfortunately, it's not possible to deallocate this stuff 743*9712c20fSFrederick Mayle // because the exception handling thread is still finishing up 744*9712c20fSFrederick Mayle // asynchronously at this point... OK, it could be done with 745*9712c20fSFrederick Mayle // locks, etc. But since BreakpadRelease() should usually only 746*9712c20fSFrederick Mayle // be called right before the process exits, it's not worth 747*9712c20fSFrederick Mayle // deallocating this stuff. 748*9712c20fSFrederick Mayle#if 0 749*9712c20fSFrederick Mayle gKeyValueAllocator->~ProtectedMemoryAllocator(); 750*9712c20fSFrederick Mayle gBreakpadAllocator->~ProtectedMemoryAllocator(); 751*9712c20fSFrederick Mayle delete gMasterAllocator; 752*9712c20fSFrederick Mayle 753*9712c20fSFrederick Mayle gMasterAllocator = NULL; 754*9712c20fSFrederick Mayle gKeyValueAllocator = NULL; 755*9712c20fSFrederick Mayle gBreakpadAllocator = NULL; 756*9712c20fSFrederick Mayle#endif 757*9712c20fSFrederick Mayle 758*9712c20fSFrederick Mayle pthread_mutex_destroy(&gDictionaryMutex); 759*9712c20fSFrederick Mayle } 760*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 761*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadRelease() : error\n"); 762*9712c20fSFrederick Mayle } 763*9712c20fSFrederick Mayle} 764*9712c20fSFrederick Mayle 765*9712c20fSFrederick Mayle//============================================================================= 766*9712c20fSFrederick Maylevoid BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value) { 767*9712c20fSFrederick Mayle try { 768*9712c20fSFrederick Mayle // Not called at exception time 769*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 770*9712c20fSFrederick Mayle 771*9712c20fSFrederick Mayle if (breakpad && key && gKeyValueAllocator) { 772*9712c20fSFrederick Mayle ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); 773*9712c20fSFrederick Mayle 774*9712c20fSFrederick Mayle breakpad->SetKeyValue(key, value); 775*9712c20fSFrederick Mayle } 776*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 777*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadSetKeyValue() : error\n"); 778*9712c20fSFrederick Mayle } 779*9712c20fSFrederick Mayle} 780*9712c20fSFrederick Mayle 781*9712c20fSFrederick Maylevoid BreakpadAddUploadParameter(BreakpadRef ref, 782*9712c20fSFrederick Mayle NSString* key, 783*9712c20fSFrederick Mayle NSString* value) { 784*9712c20fSFrederick Mayle // The only difference, internally, between an upload parameter and 785*9712c20fSFrederick Mayle // a key value one that is set with BreakpadSetKeyValue is that we 786*9712c20fSFrederick Mayle // prepend the keyname with a special prefix. This informs the 787*9712c20fSFrederick Mayle // crash sender that the parameter should be sent along with the 788*9712c20fSFrederick Mayle // POST of the crash dump upload. 789*9712c20fSFrederick Mayle try { 790*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 791*9712c20fSFrederick Mayle 792*9712c20fSFrederick Mayle if (breakpad && key && gKeyValueAllocator) { 793*9712c20fSFrederick Mayle ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); 794*9712c20fSFrederick Mayle 795*9712c20fSFrederick Mayle NSString* prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX 796*9712c20fSFrederick Mayle stringByAppendingString:key]; 797*9712c20fSFrederick Mayle breakpad->SetKeyValue(prefixedKey, value); 798*9712c20fSFrederick Mayle } 799*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 800*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadSetKeyValue() : error\n"); 801*9712c20fSFrederick Mayle } 802*9712c20fSFrederick Mayle} 803*9712c20fSFrederick Mayle 804*9712c20fSFrederick Maylevoid BreakpadRemoveUploadParameter(BreakpadRef ref, 805*9712c20fSFrederick Mayle NSString* key) { 806*9712c20fSFrederick Mayle try { 807*9712c20fSFrederick Mayle // Not called at exception time 808*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 809*9712c20fSFrederick Mayle 810*9712c20fSFrederick Mayle if (breakpad && key && gKeyValueAllocator) { 811*9712c20fSFrederick Mayle ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); 812*9712c20fSFrederick Mayle 813*9712c20fSFrederick Mayle NSString* prefixedKey = [NSString stringWithFormat:@"%@%@", 814*9712c20fSFrederick Mayle @BREAKPAD_SERVER_PARAMETER_PREFIX, key]; 815*9712c20fSFrederick Mayle breakpad->RemoveKeyValue(prefixedKey); 816*9712c20fSFrederick Mayle } 817*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 818*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadRemoveKeyValue() : error\n"); 819*9712c20fSFrederick Mayle } 820*9712c20fSFrederick Mayle} 821*9712c20fSFrederick Mayle//============================================================================= 822*9712c20fSFrederick MayleNSString* BreakpadKeyValue(BreakpadRef ref, NSString* key) { 823*9712c20fSFrederick Mayle NSString* value = nil; 824*9712c20fSFrederick Mayle 825*9712c20fSFrederick Mayle try { 826*9712c20fSFrederick Mayle // Not called at exception time 827*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 828*9712c20fSFrederick Mayle 829*9712c20fSFrederick Mayle if (!breakpad || !key || !gKeyValueAllocator) 830*9712c20fSFrederick Mayle return nil; 831*9712c20fSFrederick Mayle 832*9712c20fSFrederick Mayle ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); 833*9712c20fSFrederick Mayle 834*9712c20fSFrederick Mayle value = breakpad->KeyValue(key); 835*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 836*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadKeyValue() : error\n"); 837*9712c20fSFrederick Mayle } 838*9712c20fSFrederick Mayle 839*9712c20fSFrederick Mayle return value; 840*9712c20fSFrederick Mayle} 841*9712c20fSFrederick Mayle 842*9712c20fSFrederick Mayle//============================================================================= 843*9712c20fSFrederick Maylevoid BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key) { 844*9712c20fSFrederick Mayle try { 845*9712c20fSFrederick Mayle // Not called at exception time 846*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 847*9712c20fSFrederick Mayle 848*9712c20fSFrederick Mayle if (breakpad && key && gKeyValueAllocator) { 849*9712c20fSFrederick Mayle ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); 850*9712c20fSFrederick Mayle 851*9712c20fSFrederick Mayle breakpad->RemoveKeyValue(key); 852*9712c20fSFrederick Mayle } 853*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 854*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadRemoveKeyValue() : error\n"); 855*9712c20fSFrederick Mayle } 856*9712c20fSFrederick Mayle} 857*9712c20fSFrederick Mayle 858*9712c20fSFrederick Mayle//============================================================================= 859*9712c20fSFrederick Mayleint BreakpadGetCrashReportCount(BreakpadRef ref) { 860*9712c20fSFrederick Mayle try { 861*9712c20fSFrederick Mayle // Not called at exception time 862*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 863*9712c20fSFrederick Mayle 864*9712c20fSFrederick Mayle if (breakpad) { 865*9712c20fSFrederick Mayle return static_cast<int>([breakpad->CrashReportsToUpload() count]); 866*9712c20fSFrederick Mayle } 867*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 868*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadGetCrashReportCount() : error\n"); 869*9712c20fSFrederick Mayle } 870*9712c20fSFrederick Mayle return false; 871*9712c20fSFrederick Mayle} 872*9712c20fSFrederick Mayle 873*9712c20fSFrederick Mayle//============================================================================= 874*9712c20fSFrederick Maylevoid BreakpadUploadNextReport(BreakpadRef ref) { 875*9712c20fSFrederick Mayle BreakpadUploadNextReportWithParameters(ref, nil, nullptr); 876*9712c20fSFrederick Mayle} 877*9712c20fSFrederick Mayle 878*9712c20fSFrederick Mayle//============================================================================= 879*9712c20fSFrederick MayleNSDictionary* BreakpadGetNextReportConfiguration(BreakpadRef ref) { 880*9712c20fSFrederick Mayle try { 881*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 882*9712c20fSFrederick Mayle if (breakpad) 883*9712c20fSFrederick Mayle return breakpad->NextCrashReportConfiguration(); 884*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 885*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadGetNextReportConfiguration() : error\n"); 886*9712c20fSFrederick Mayle } 887*9712c20fSFrederick Mayle return nil; 888*9712c20fSFrederick Mayle} 889*9712c20fSFrederick Mayle 890*9712c20fSFrederick Mayle//============================================================================= 891*9712c20fSFrederick MayleNSDate* BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref) { 892*9712c20fSFrederick Mayle try { 893*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 894*9712c20fSFrederick Mayle if (breakpad) { 895*9712c20fSFrederick Mayle return breakpad->DateOfMostRecentCrashReport(); 896*9712c20fSFrederick Mayle } 897*9712c20fSFrederick Mayle } catch (...) { // don't let exceptions leave this C API 898*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadGetDateOfMostRecentCrashReport() : error\n"); 899*9712c20fSFrederick Mayle } 900*9712c20fSFrederick Mayle return nil; 901*9712c20fSFrederick Mayle} 902*9712c20fSFrederick Mayle 903*9712c20fSFrederick Mayle//============================================================================= 904*9712c20fSFrederick Maylevoid BreakpadUploadReportWithParametersAndConfiguration( 905*9712c20fSFrederick Mayle BreakpadRef ref, 906*9712c20fSFrederick Mayle NSDictionary* server_parameters, 907*9712c20fSFrederick Mayle NSDictionary* configuration, 908*9712c20fSFrederick Mayle BreakpadUploadCompletionCallback callback) { 909*9712c20fSFrederick Mayle try { 910*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 911*9712c20fSFrederick Mayle if (!breakpad || !configuration) 912*9712c20fSFrederick Mayle return; 913*9712c20fSFrederick Mayle breakpad->UploadReportWithConfiguration(configuration, server_parameters, 914*9712c20fSFrederick Mayle callback); 915*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 916*9712c20fSFrederick Mayle fprintf(stderr, 917*9712c20fSFrederick Mayle "BreakpadUploadReportWithParametersAndConfiguration() : error\n"); 918*9712c20fSFrederick Mayle } 919*9712c20fSFrederick Mayle} 920*9712c20fSFrederick Mayle 921*9712c20fSFrederick Mayle//============================================================================= 922*9712c20fSFrederick Maylevoid BreakpadUploadNextReportWithParameters( 923*9712c20fSFrederick Mayle BreakpadRef ref, 924*9712c20fSFrederick Mayle NSDictionary* server_parameters, 925*9712c20fSFrederick Mayle BreakpadUploadCompletionCallback callback) { 926*9712c20fSFrederick Mayle try { 927*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 928*9712c20fSFrederick Mayle if (!breakpad) 929*9712c20fSFrederick Mayle return; 930*9712c20fSFrederick Mayle NSDictionary* configuration = breakpad->NextCrashReportConfiguration(); 931*9712c20fSFrederick Mayle if (!configuration) 932*9712c20fSFrederick Mayle return; 933*9712c20fSFrederick Mayle return BreakpadUploadReportWithParametersAndConfiguration( 934*9712c20fSFrederick Mayle ref, server_parameters, configuration, callback); 935*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 936*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadUploadNextReportWithParameters() : error\n"); 937*9712c20fSFrederick Mayle } 938*9712c20fSFrederick Mayle} 939*9712c20fSFrederick Mayle 940*9712c20fSFrederick Maylevoid BreakpadHandleNetworkResponse(BreakpadRef ref, 941*9712c20fSFrederick Mayle NSDictionary* configuration, 942*9712c20fSFrederick Mayle NSData* data, 943*9712c20fSFrederick Mayle NSError* error) { 944*9712c20fSFrederick Mayle try { 945*9712c20fSFrederick Mayle // Not called at exception time 946*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 947*9712c20fSFrederick Mayle if (breakpad && configuration) 948*9712c20fSFrederick Mayle breakpad->HandleNetworkResponse(configuration,data, error); 949*9712c20fSFrederick Mayle 950*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 951*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadHandleNetworkResponse() : error\n"); 952*9712c20fSFrederick Mayle } 953*9712c20fSFrederick Mayle} 954*9712c20fSFrederick Mayle 955*9712c20fSFrederick Mayle//============================================================================= 956*9712c20fSFrederick Maylevoid BreakpadUploadData(BreakpadRef ref, NSData* data, NSString* name, 957*9712c20fSFrederick Mayle NSDictionary* server_parameters) { 958*9712c20fSFrederick Mayle try { 959*9712c20fSFrederick Mayle // Not called at exception time 960*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 961*9712c20fSFrederick Mayle 962*9712c20fSFrederick Mayle if (breakpad) { 963*9712c20fSFrederick Mayle breakpad->UploadData(data, name, server_parameters); 964*9712c20fSFrederick Mayle } 965*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 966*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadUploadData() : error\n"); 967*9712c20fSFrederick Mayle } 968*9712c20fSFrederick Mayle} 969*9712c20fSFrederick Mayle 970*9712c20fSFrederick Mayle//============================================================================= 971*9712c20fSFrederick MayleNSDictionary* BreakpadGenerateReport(BreakpadRef ref, 972*9712c20fSFrederick Mayle NSDictionary* server_parameters) { 973*9712c20fSFrederick Mayle try { 974*9712c20fSFrederick Mayle // Not called at exception time 975*9712c20fSFrederick Mayle Breakpad* breakpad = (Breakpad*)ref; 976*9712c20fSFrederick Mayle 977*9712c20fSFrederick Mayle if (breakpad) { 978*9712c20fSFrederick Mayle return breakpad->GenerateReport(server_parameters); 979*9712c20fSFrederick Mayle } else { 980*9712c20fSFrederick Mayle return nil; 981*9712c20fSFrederick Mayle } 982*9712c20fSFrederick Mayle } catch(...) { // don't let exceptions leave this C API 983*9712c20fSFrederick Mayle fprintf(stderr, "BreakpadGenerateReport() : error\n"); 984*9712c20fSFrederick Mayle return nil; 985*9712c20fSFrederick Mayle } 986*9712c20fSFrederick Mayle} 987