toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad.mm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2011, Google Inc.
     2 // All rights reserved.
     3 //
     4 // Redistribution and use in source and binary forms, with or without
     5 // modification, are permitted provided that the following conditions are
     6 // met:
     7 //
     8 //     * Redistributions of source code must retain the above copyright
     9 // notice, this list of conditions and the following disclaimer.
    10 //     * Redistributions in binary form must reproduce the above
    11 // copyright notice, this list of conditions and the following disclaimer
    12 // in the documentation and/or other materials provided with the
    13 // distribution.
    14 //     * Neither the name of Google Inc. nor the names of its
    15 // contributors may be used to endorse or promote products derived from
    16 // this software without specific prior written permission.
    17 //
    18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    30 #define VERBOSE 0
    32 #if VERBOSE
    33   static bool gDebugLog = true;
    34 #else
    35   static bool gDebugLog = false;
    36 #endif
    38 #define DEBUGLOG if (gDebugLog) fprintf
    39 #define IGNORE_DEBUGGER "BREAKPAD_IGNORE_DEBUGGER"
    41 #import "client/ios/Breakpad.h"
    43 #import <Foundation/Foundation.h>
    44 #include <pthread.h>
    45 #include <sys/stat.h>
    46 #include <sys/sysctl.h>
    48 #import "client/mac/crash_generation/ConfigFile.h"
    49 #import "client/mac/handler/exception_handler.h"
    50 #import "client/mac/handler/minidump_generator.h"
    51 #import "client/mac/sender/uploader.h"
    52 #import "common/mac/SimpleStringDictionary.h"
    53 #import "client/ios/handler/ios_exception_minidump_generator.h"
    54 #import "client/mac/handler/protected_memory_allocator.h"
    56 #ifndef __EXCEPTIONS
    57 // This file uses C++ try/catch (but shouldn't). Duplicate the macros from
    58 // <c++/4.2.1/exception_defines.h> allowing this file to work properly with
    59 // exceptions disabled even when other C++ libraries are used. #undef the try
    60 // and catch macros first in case libstdc++ is in use and has already provided
    61 // its own definitions.
    62 #undef try
    63 #define try       if (true)
    64 #undef catch
    65 #define catch(X)  if (false)
    66 #endif  // __EXCEPTIONS
    68 using google_breakpad::ConfigFile;
    69 using google_breakpad::EnsureDirectoryPathExists;
    70 using google_breakpad::KeyValueEntry;
    71 using google_breakpad::SimpleStringDictionary;
    72 using google_breakpad::SimpleStringDictionaryIterator;
    74 //=============================================================================
    75 // We want any memory allocations which are used by breakpad during the
    76 // exception handling process (after a crash has happened) to be read-only
    77 // to prevent them from being smashed before a crash occurs.  Unfortunately
    78 // we cannot protect against smashes to our exception handling thread's
    79 // stack.
    80 //
    81 // NOTE: Any memory allocations which are not used during the exception
    82 // handling process may be allocated in the normal ways.
    83 //
    84 // The ProtectedMemoryAllocator class provides an Allocate() method which
    85 // we'll using in conjunction with placement operator new() to control
    86 // allocation of C++ objects.  Note that we don't use operator delete()
    87 // but instead call the objects destructor directly:  object->~ClassName();
    88 //
    89 ProtectedMemoryAllocator *gMasterAllocator = NULL;
    90 ProtectedMemoryAllocator *gKeyValueAllocator = NULL;
    91 ProtectedMemoryAllocator *gBreakpadAllocator = NULL;
    93 // Mutex for thread-safe access to the key/value dictionary used by breakpad.
    94 // It's a global instead of an instance variable of Breakpad
    95 // since it can't live in a protected memory area.
    96 pthread_mutex_t gDictionaryMutex;
    98 //=============================================================================
    99 // Stack-based object for thread-safe access to a memory-protected region.
   100 // It's assumed that normally the memory block (allocated by the allocator)
   101 // is protected (read-only).  Creating a stack-based instance of
   102 // ProtectedMemoryLocker will unprotect this block after taking the lock.
   103 // Its destructor will first re-protect the memory then release the lock.
   104 class ProtectedMemoryLocker {
   105 public:
   106   // allocator may be NULL, in which case no Protect() or Unprotect() calls
   107   // will be made, but a lock will still be taken
   108   ProtectedMemoryLocker(pthread_mutex_t *mutex,
   109                         ProtectedMemoryAllocator *allocator)
   110   : mutex_(mutex), allocator_(allocator) {
   111     // Lock the mutex
   112     assert(pthread_mutex_lock(mutex_) == 0);
   114     // Unprotect the memory
   115     if (allocator_ ) {
   116       allocator_->Unprotect();
   117     }
   118   }
   120   ~ProtectedMemoryLocker() {
   121     // First protect the memory
   122     if (allocator_) {
   123       allocator_->Protect();
   124     }
   126     // Then unlock the mutex
   127     assert(pthread_mutex_unlock(mutex_) == 0);
   128   };
   130 private:
   131   //  Keep anybody from ever creating one of these things not on the stack.
   132   ProtectedMemoryLocker() { }
   133   ProtectedMemoryLocker(const ProtectedMemoryLocker&);
   134   ProtectedMemoryLocker & operator=(ProtectedMemoryLocker&);
   136   pthread_mutex_t           *mutex_;
   137   ProtectedMemoryAllocator  *allocator_;
   138 };
   140 //=============================================================================
   141 class Breakpad {
   142  public:
   143   // factory method
   144   static Breakpad *Create(NSDictionary *parameters) {
   145     // Allocate from our special allocation pool
   146     Breakpad *breakpad =
   147       new (gBreakpadAllocator->Allocate(sizeof(Breakpad)))
   148         Breakpad();
   150     if (!breakpad)
   151       return NULL;
   153     if (!breakpad->Initialize(parameters)) {
   154       // Don't use operator delete() here since we allocated from special pool
   155       breakpad->~Breakpad();
   156       return NULL;
   157     }
   159     return breakpad;
   160   }
   162   ~Breakpad();
   164   void SetKeyValue(NSString *key, NSString *value);
   165   NSString *KeyValue(NSString *key);
   166   void RemoveKeyValue(NSString *key);
   167   NSString *NextCrashReportToUpload();
   168   void UploadNextReport();
   169   void UploadData(NSData *data, NSString *name,
   170                   NSDictionary *server_parameters);
   171   NSDictionary *GenerateReport(NSDictionary *server_parameters);
   173  private:
   174   Breakpad()
   175     : handler_(NULL),
   176       config_params_(NULL) {}
   178   bool Initialize(NSDictionary *parameters);
   180   bool ExtractParameters(NSDictionary *parameters);
   182   // Dispatches to HandleMinidump()
   183   static bool HandleMinidumpCallback(const char *dump_dir,
   184                                      const char *minidump_id,
   185                                      void *context, bool succeeded);
   187   bool HandleMinidump(const char *dump_dir,
   188                       const char *minidump_id);
   190   // NSException handler
   191   static void UncaughtExceptionHandler(NSException *exception);
   193   // Handle an uncaught NSException.
   194   void HandleUncaughtException(NSException *exception);
   196   // Since ExceptionHandler (w/o namespace) is defined as typedef in OSX's
   197   // MachineExceptions.h, we have to explicitly name the handler.
   198   google_breakpad::ExceptionHandler *handler_; // The actual handler (STRONG)
   200   SimpleStringDictionary  *config_params_; // Create parameters (STRONG)
   202   ConfigFile config_file_;
   204   // A static reference to the current Breakpad instance. Used for handling
   205   // NSException.
   206   static Breakpad *current_breakpad_;
   207 };
   209 Breakpad *Breakpad::current_breakpad_ = NULL;
   211 #pragma mark -
   212 #pragma mark Helper functions
   214 //=============================================================================
   215 // Helper functions
   217 //=============================================================================
   218 static BOOL IsDebuggerActive() {
   219   BOOL result = NO;
   220   NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults];
   222   // We check both defaults and the environment variable here
   224   BOOL ignoreDebugger = [stdDefaults boolForKey:@IGNORE_DEBUGGER];
   226   if (!ignoreDebugger) {
   227     char *ignoreDebuggerStr = getenv(IGNORE_DEBUGGER);
   228     ignoreDebugger =
   229         (ignoreDebuggerStr ? strtol(ignoreDebuggerStr, NULL, 10) : 0) != 0;
   230   }
   232   if (!ignoreDebugger) {
   233     pid_t pid = getpid();
   234     int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
   235     int mibSize = sizeof(mib) / sizeof(int);
   236     size_t actualSize;
   238     if (sysctl(mib, mibSize, NULL, &actualSize, NULL, 0) == 0) {
   239       struct kinfo_proc *info = (struct kinfo_proc *)malloc(actualSize);
   241       if (info) {
   242         // This comes from looking at the Darwin xnu Kernel
   243         if (sysctl(mib, mibSize, info, &actualSize, NULL, 0) == 0)
   244           result = (info->kp_proc.p_flag & P_TRACED) ? YES : NO;
   246         free(info);
   247       }
   248     }
   249   }
   251   return result;
   252 }
   254 //=============================================================================
   255 bool Breakpad::HandleMinidumpCallback(const char *dump_dir,
   256                                       const char *minidump_id,
   257                                       void *context, bool succeeded) {
   258   Breakpad *breakpad = (Breakpad *)context;
   260   // If our context is damaged or something, just return false to indicate that
   261   // the handler should continue without us.
   262   if (!breakpad || !succeeded)
   263     return false;
   265   return breakpad->HandleMinidump(dump_dir, minidump_id);
   266 }
   268 //=============================================================================
   269 void Breakpad::UncaughtExceptionHandler(NSException *exception) {
   270   NSSetUncaughtExceptionHandler(NULL);
   271   if (current_breakpad_) {
   272     current_breakpad_->HandleUncaughtException(exception);
   273   }
   274 }
   276 //=============================================================================
   277 #pragma mark -
   279 //=============================================================================
   280 bool Breakpad::Initialize(NSDictionary *parameters) {
   281   // Initialize
   282   current_breakpad_ = this;
   283   config_params_ = NULL;
   284   handler_ = NULL;
   286   // Gather any user specified parameters
   287   if (!ExtractParameters(parameters)) {
   288     return false;
   289   }
   291   // Check for debugger
   292   if (IsDebuggerActive()) {
   293     DEBUGLOG(stderr, "Debugger is active:  Not installing handler\n");
   294     return true;
   295   }
   297   // Create the handler (allocating it in our special protected pool)
   298   handler_ =
   299       new (gBreakpadAllocator->Allocate(
   300           sizeof(google_breakpad::ExceptionHandler)))
   301           google_breakpad::ExceptionHandler(
   302               config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY),
   303               0, &HandleMinidumpCallback, this, true, 0);
   304   NSSetUncaughtExceptionHandler(&Breakpad::UncaughtExceptionHandler);
   305   return true;
   306 }
   308 //=============================================================================
   309 Breakpad::~Breakpad() {
   310   NSSetUncaughtExceptionHandler(NULL);
   311   current_breakpad_ = NULL;
   312   // Note that we don't use operator delete() on these pointers,
   313   // since they were allocated by ProtectedMemoryAllocator objects.
   314   //
   315   if (config_params_) {
   316     config_params_->~SimpleStringDictionary();
   317   }
   319   if (handler_)
   320     handler_->~ExceptionHandler();
   321 }
   323 //=============================================================================
   324 bool Breakpad::ExtractParameters(NSDictionary *parameters) {
   325   NSString *serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE];
   326   NSString *display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY];
   327   NSString *product = [parameters objectForKey:@BREAKPAD_PRODUCT];
   328   NSString *version = [parameters objectForKey:@BREAKPAD_VERSION];
   329   NSString *urlStr = [parameters objectForKey:@BREAKPAD_URL];
   330   NSString *vendor =
   331       [parameters objectForKey:@BREAKPAD_VENDOR];
   332   NSString *dumpSubdirectory =
   333       [parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY];
   335   NSDictionary *serverParameters =
   336       [parameters objectForKey:@BREAKPAD_SERVER_PARAMETER_DICT];
   338   if (!product)
   339     product = [parameters objectForKey:@"CFBundleName"];
   341   if (!display) {
   342     display = [parameters objectForKey:@"CFBundleDisplayName"];
   343     if (!display) {
   344       display = product;
   345     }
   346   }
   348   if (!version)
   349     version = [parameters objectForKey:@"CFBundleVersion"];
   351   if (!vendor) {
   352     vendor = @"Vendor not specified";
   353   }
   355   if (!dumpSubdirectory) {
   356     NSString *cachePath =
   357         [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
   358                                              NSUserDomainMask,
   359                                              YES)
   360             objectAtIndex:0];
   361     dumpSubdirectory =
   362         [cachePath stringByAppendingPathComponent:@kDefaultLibrarySubdirectory];
   364     EnsureDirectoryPathExists(dumpSubdirectory);
   365   }
   367   // The product, version, and URL are required values.
   368   if (![product length]) {
   369     DEBUGLOG(stderr, "Missing required product key.\n");
   370     return false;
   371   }
   373   if (![version length]) {
   374     DEBUGLOG(stderr, "Missing required version key.\n");
   375     return false;
   376   }
   378   if (![urlStr length]) {
   379     DEBUGLOG(stderr, "Missing required URL key.\n");
   380     return false;
   381   }
   383   config_params_ =
   384       new (gKeyValueAllocator->Allocate(sizeof(SimpleStringDictionary)) )
   385         SimpleStringDictionary();
   387   SimpleStringDictionary &dictionary = *config_params_;
   389   dictionary.SetKeyValue(BREAKPAD_SERVER_TYPE,     [serverType UTF8String]);
   390   dictionary.SetKeyValue(BREAKPAD_PRODUCT_DISPLAY, [display UTF8String]);
   391   dictionary.SetKeyValue(BREAKPAD_PRODUCT,         [product UTF8String]);
   392   dictionary.SetKeyValue(BREAKPAD_VERSION,         [version UTF8String]);
   393   dictionary.SetKeyValue(BREAKPAD_URL,             [urlStr UTF8String]);
   394   dictionary.SetKeyValue(BREAKPAD_VENDOR,          [vendor UTF8String]);
   395   dictionary.SetKeyValue(BREAKPAD_DUMP_DIRECTORY,
   396                          [dumpSubdirectory UTF8String]);
   398   struct timeval tv;
   399   gettimeofday(&tv, NULL);
   400   char timeStartedString[32];
   401   sprintf(timeStartedString, "%zd", tv.tv_sec);
   402   dictionary.SetKeyValue(BREAKPAD_PROCESS_START_TIME, timeStartedString);
   404   if (serverParameters) {
   405     // For each key-value pair, call BreakpadAddUploadParameter()
   406     NSEnumerator *keyEnumerator = [serverParameters keyEnumerator];
   407     NSString *aParameter;
   408     while ((aParameter = [keyEnumerator nextObject])) {
   409       BreakpadAddUploadParameter(this, aParameter,
   410 				 [serverParameters objectForKey:aParameter]);
   411     }
   412   }
   413   return true;
   414 }
   416 //=============================================================================
   417 void Breakpad::SetKeyValue(NSString *key, NSString *value) {
   418   // We allow nil values. This is the same as removing the keyvalue.
   419   if (!config_params_ || !key)
   420     return;
   422   config_params_->SetKeyValue([key UTF8String], [value UTF8String]);
   423 }
   425 //=============================================================================
   426 NSString *Breakpad::KeyValue(NSString *key) {
   427   if (!config_params_ || !key)
   428     return nil;
   430   const char *value = config_params_->GetValueForKey([key UTF8String]);
   431   return value ? [NSString stringWithUTF8String:value] : nil;
   432 }
   434 //=============================================================================
   435 void Breakpad::RemoveKeyValue(NSString *key) {
   436   if (!config_params_ || !key) return;
   438   config_params_->RemoveKey([key UTF8String]);
   439 }
   441 //=============================================================================
   442 NSString *Breakpad::NextCrashReportToUpload() {
   443   NSString *directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
   444   if (!directory)
   445     return nil;
   446   NSArray *dirContents = [[NSFileManager defaultManager]
   447       contentsOfDirectoryAtPath:directory error:nil];
   448   NSArray *configs = [dirContents filteredArrayUsingPredicate:[NSPredicate
   449       predicateWithFormat:@"self BEGINSWITH 'Config-'"]];
   450   NSString *config = [configs lastObject];
   451   if (!config)
   452     return nil;
   453   return [NSString stringWithFormat:@"%@/%@", directory, config];
   454 }
   456 //=============================================================================
   457 void Breakpad::UploadNextReport() {
   458   NSString *configFile = NextCrashReportToUpload();
   459   if (configFile) {
   460     Uploader *uploader = [[[Uploader alloc]
   461         initWithConfigFile:[configFile UTF8String]] autorelease];
   462     if (uploader)
   463       [uploader report];
   464   }
   465 }
   467 //=============================================================================
   468 void Breakpad::UploadData(NSData *data, NSString *name,
   469                           NSDictionary *server_parameters) {
   470   NSMutableDictionary *config = [NSMutableDictionary dictionary];
   472   SimpleStringDictionaryIterator it(*config_params_);
   473   while (const KeyValueEntry *next = it.Next()) {
   474     [config setValue:[NSString stringWithUTF8String:next->GetValue()]
   475               forKey:[NSString stringWithUTF8String:next->GetKey()]];
   476   }
   478   Uploader *uploader =
   479       [[[Uploader alloc] initWithConfig:config] autorelease];
   480   for (NSString *key in server_parameters) {
   481     [uploader addServerParameter:[server_parameters objectForKey:key]
   482                           forKey:key];
   483   }
   484   [uploader uploadData:data name:name];
   485 }
   487 //=============================================================================
   488 NSDictionary *Breakpad::GenerateReport(NSDictionary *server_parameters) {
   489   NSString *dumpDirAsNSString = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
   490   if (!dumpDirAsNSString)
   491     return nil;
   492   const char *dumpDir = [dumpDirAsNSString UTF8String];
   494   google_breakpad::MinidumpGenerator generator(mach_task_self(),
   495                                                MACH_PORT_NULL);
   496   std::string dumpId;
   497   std::string dumpFilename = generator.UniqueNameInDirectory(dumpDir, &dumpId);
   498   bool success = generator.Write(dumpFilename.c_str());
   499   if (!success)
   500     return nil;
   502   SimpleStringDictionary params = *config_params_;
   503   for (NSString *key in server_parameters) {
   504     params.SetKeyValue([key UTF8String],
   505                        [[server_parameters objectForKey:key] UTF8String]);
   506   }
   507   ConfigFile config_file;
   508   config_file.WriteFile(dumpDir, &params, dumpDir, dumpId.c_str());
   510   // Handle results.
   511   NSMutableDictionary *result = [NSMutableDictionary dictionary];
   512   NSString *dumpFullPath = [dumpDirAsNSString stringByAppendingPathComponent:
   513       [NSString stringWithUTF8String:dumpFilename.c_str()]];
   514   [result setValue:dumpFullPath
   515             forKey:@BREAKPAD_OUTPUT_DUMP_FILE];
   516   [result setValue:[NSString stringWithUTF8String:config_file.GetFilePath()]
   517             forKey:@BREAKPAD_OUTPUT_CONFIG_FILE];
   518   return result;
   519 }
   521 //=============================================================================
   522 bool Breakpad::HandleMinidump(const char *dump_dir,
   523                               const char *minidump_id) {
   524   DEBUGLOG(stderr, "Breakpad: a minidump has been created.\n");
   526   config_file_.WriteFile(dump_dir,
   527                          config_params_,
   528                          dump_dir,
   529                          minidump_id);
   531   // Return true here to indicate that we've processed things as much as we
   532   // want.
   533   return true;
   534 }
   536 //=============================================================================
   537 void Breakpad::HandleUncaughtException(NSException *exception) {
   538   // Generate the minidump.
   539   google_breakpad::IosExceptionMinidumpGenerator generator(exception);
   540   const char *minidump_path =
   541       config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY);
   542   std::string minidump_id;
   543   std::string minidump_filename = generator.UniqueNameInDirectory(minidump_path,
   544                                                                   &minidump_id);
   545   generator.Write(minidump_filename.c_str());
   547   // Copy the config params and our custom parameter. This is necessary for 2
   548   // reasons:
   549   // 1- config_params_ is protected.
   550   // 2- If the application crash while trying to handle this exception, a usual
   551   //    report will be generated. This report must not contain these special
   552   //    keys.
   553   SimpleStringDictionary params = *config_params_;
   554   params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "type", "exception");
   555   params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "exceptionName",
   556                      [[exception name] UTF8String]);
   557   params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "exceptionReason",
   558                      [[exception reason] UTF8String]);
   560   // And finally write the config file.
   561   ConfigFile config_file;
   562   config_file.WriteFile(minidump_path,
   563                         &params,
   564                         minidump_path,
   565                         minidump_id.c_str());
   566 }
   568 //=============================================================================
   570 #pragma mark -
   571 #pragma mark Public API
   573 //=============================================================================
   574 BreakpadRef BreakpadCreate(NSDictionary *parameters) {
   575   try {
   576     // This is confusing.  Our two main allocators for breakpad memory are:
   577     //    - gKeyValueAllocator for the key/value memory
   578     //    - gBreakpadAllocator for the Breakpad, ExceptionHandler, and other
   579     //      breakpad allocations which are accessed at exception handling time.
   580     //
   581     // But in order to avoid these two allocators themselves from being smashed,
   582     // we'll protect them as well by allocating them with gMasterAllocator.
   583     //
   584     // gMasterAllocator itself will NOT be protected, but this doesn't matter,
   585     // since once it does its allocations and locks the memory, smashes to
   586     // itself don't affect anything we care about.
   587     gMasterAllocator =
   588         new ProtectedMemoryAllocator(sizeof(ProtectedMemoryAllocator) * 2);
   590     gKeyValueAllocator =
   591         new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator)))
   592             ProtectedMemoryAllocator(sizeof(SimpleStringDictionary));
   594     // Create a mutex for use in accessing the SimpleStringDictionary
   595     int mutexResult = pthread_mutex_init(&gDictionaryMutex, NULL);
   596     if (mutexResult == 0) {
   598       // With the current compiler, gBreakpadAllocator is allocating 1444 bytes.
   599       // Let's round up to the nearest page size.
   600       //
   601       int breakpad_pool_size = 4096;
   603       /*
   604        sizeof(Breakpad)
   605        + sizeof(google_breakpad::ExceptionHandler)
   606        + sizeof( STUFF ALLOCATED INSIDE ExceptionHandler )
   607        */
   609       gBreakpadAllocator =
   610           new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator)))
   611               ProtectedMemoryAllocator(breakpad_pool_size);
   613       // Stack-based autorelease pool for Breakpad::Create() obj-c code.
   614       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   615       Breakpad *breakpad = Breakpad::Create(parameters);
   617       if (breakpad) {
   618         // Make read-only to protect against memory smashers
   619         gMasterAllocator->Protect();
   620         gKeyValueAllocator->Protect();
   621         gBreakpadAllocator->Protect();
   622         // Can uncomment this line to figure out how much space was actually
   623         // allocated using this allocator
   624         //     printf("gBreakpadAllocator allocated size = %d\n",
   625         //         gBreakpadAllocator->GetAllocatedSize() );
   626         [pool release];
   627         return (BreakpadRef)breakpad;
   628       }
   630       [pool release];
   631     }
   632   } catch(...) {    // don't let exceptions leave this C API
   633     fprintf(stderr, "BreakpadCreate() : error\n");
   634   }
   636   if (gKeyValueAllocator) {
   637     gKeyValueAllocator->~ProtectedMemoryAllocator();
   638     gKeyValueAllocator = NULL;
   639   }
   641   if (gBreakpadAllocator) {
   642     gBreakpadAllocator->~ProtectedMemoryAllocator();
   643     gBreakpadAllocator = NULL;
   644   }
   646   delete gMasterAllocator;
   647   gMasterAllocator = NULL;
   649   return NULL;
   650 }
   652 //=============================================================================
   653 void BreakpadRelease(BreakpadRef ref) {
   654   try {
   655     Breakpad *breakpad = (Breakpad *)ref;
   657     if (gMasterAllocator) {
   658       gMasterAllocator->Unprotect();
   659       gKeyValueAllocator->Unprotect();
   660       gBreakpadAllocator->Unprotect();
   662       breakpad->~Breakpad();
   664       // Unfortunately, it's not possible to deallocate this stuff
   665       // because the exception handling thread is still finishing up
   666       // asynchronously at this point...  OK, it could be done with
   667       // locks, etc.  But since BreakpadRelease() should usually only
   668       // be called right before the process exits, it's not worth
   669       // deallocating this stuff.
   670 #if 0
   671       gKeyValueAllocator->~ProtectedMemoryAllocator();
   672       gBreakpadAllocator->~ProtectedMemoryAllocator();
   673       delete gMasterAllocator;
   675       gMasterAllocator = NULL;
   676       gKeyValueAllocator = NULL;
   677       gBreakpadAllocator = NULL;
   678 #endif
   680       pthread_mutex_destroy(&gDictionaryMutex);
   681     }
   682   } catch(...) {    // don't let exceptions leave this C API
   683     fprintf(stderr, "BreakpadRelease() : error\n");
   684   }
   685 }
   687 //=============================================================================
   688 void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value) {
   689   try {
   690     // Not called at exception time
   691     Breakpad *breakpad = (Breakpad *)ref;
   693     if (breakpad && key && gKeyValueAllocator) {
   694       ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
   696       breakpad->SetKeyValue(key, value);
   697     }
   698   } catch(...) {    // don't let exceptions leave this C API
   699     fprintf(stderr, "BreakpadSetKeyValue() : error\n");
   700   }
   701 }
   703 void BreakpadAddUploadParameter(BreakpadRef ref,
   704                                 NSString *key,
   705                                 NSString *value) {
   706   // The only difference, internally, between an upload parameter and
   707   // a key value one that is set with BreakpadSetKeyValue is that we
   708   // prepend the keyname with a special prefix.  This informs the
   709   // crash sender that the parameter should be sent along with the
   710   // POST of the crash dump upload.
   711   try {
   712     Breakpad *breakpad = (Breakpad *)ref;
   714     if (breakpad && key && gKeyValueAllocator) {
   715       ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
   717       NSString *prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX
   718 				stringByAppendingString:key];
   719       breakpad->SetKeyValue(prefixedKey, value);
   720     }
   721   } catch(...) {    // don't let exceptions leave this C API
   722     fprintf(stderr, "BreakpadSetKeyValue() : error\n");
   723   }
   724 }
   726 void BreakpadRemoveUploadParameter(BreakpadRef ref,
   727                                    NSString *key) {
   728   try {
   729     // Not called at exception time
   730     Breakpad *breakpad = (Breakpad *)ref;
   732     if (breakpad && key && gKeyValueAllocator) {
   733       ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
   735       NSString *prefixedKey = [NSString stringWithFormat:@"%@%@",
   736                                         @BREAKPAD_SERVER_PARAMETER_PREFIX, key];
   737       breakpad->RemoveKeyValue(prefixedKey);
   738     }
   739   } catch(...) {    // don't let exceptions leave this C API
   740     fprintf(stderr, "BreakpadRemoveKeyValue() : error\n");
   741   }
   742 }
   743 //=============================================================================
   744 NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key) {
   745   NSString *value = nil;
   747   try {
   748     // Not called at exception time
   749     Breakpad *breakpad = (Breakpad *)ref;
   751     if (!breakpad || !key || !gKeyValueAllocator)
   752       return nil;
   754     ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
   756     value = breakpad->KeyValue(key);
   757   } catch(...) {    // don't let exceptions leave this C API
   758     fprintf(stderr, "BreakpadKeyValue() : error\n");
   759   }
   761   return value;
   762 }
   764 //=============================================================================
   765 void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key) {
   766   try {
   767     // Not called at exception time
   768     Breakpad *breakpad = (Breakpad *)ref;
   770     if (breakpad && key && gKeyValueAllocator) {
   771       ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
   773       breakpad->RemoveKeyValue(key);
   774     }
   775   } catch(...) {    // don't let exceptions leave this C API
   776     fprintf(stderr, "BreakpadRemoveKeyValue() : error\n");
   777   }
   778 }
   780 //=============================================================================
   781 bool BreakpadHasCrashReportToUpload(BreakpadRef ref) {
   782   try {
   783     // Not called at exception time
   784     Breakpad *breakpad = (Breakpad *)ref;
   786     if (breakpad) {
   787        return breakpad->NextCrashReportToUpload() != 0;
   788     }
   789   } catch(...) {    // don't let exceptions leave this C API
   790     fprintf(stderr, "BreakpadHasCrashReportToUpload() : error\n");
   791   }
   792   return false;
   793 }
   795 //=============================================================================
   796 void BreakpadUploadNextReport(BreakpadRef ref) {
   797   try {
   798     // Not called at exception time
   799     Breakpad *breakpad = (Breakpad *)ref;
   801     if (breakpad) {
   802        breakpad->UploadNextReport();
   803     }
   804   } catch(...) {    // don't let exceptions leave this C API
   805     fprintf(stderr, "BreakpadUploadNextReport() : error\n");
   806   }
   807 }
   809 //=============================================================================
   810 void BreakpadUploadData(BreakpadRef ref, NSData *data, NSString *name,
   811                         NSDictionary *server_parameters) {
   812   try {
   813     // Not called at exception time
   814     Breakpad *breakpad = (Breakpad *)ref;
   816     if (breakpad) {
   817       breakpad->UploadData(data, name, server_parameters);
   818     }
   819   } catch(...) {    // don't let exceptions leave this C API
   820     fprintf(stderr, "BreakpadUploadData() : error\n");
   821   }
   822 }
   824 //=============================================================================
   825 NSDictionary *BreakpadGenerateReport(BreakpadRef ref,
   826                                      NSDictionary *server_parameters) {
   827   try {
   828     // Not called at exception time
   829     Breakpad *breakpad = (Breakpad *)ref;
   831     if (breakpad) {
   832       return breakpad->GenerateReport(server_parameters);
   833     } else {
   834       return nil;
   835     }
   836   } catch(...) {    // don't let exceptions leave this C API
   837     fprintf(stderr, "BreakpadGenerateReport() : error\n");
   838     return nil;
   839   }
   840 }

mercurial