Wed, 31 Dec 2014 06:09:35 +0100
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, ¶ms, 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 ¶ms,
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 }