xref: /aosp_15_r20/external/google-breakpad/src/client/ios/Breakpad.mm (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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, &params, 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                        &params,
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