summaryrefslogtreecommitdiffstats
path: root/chrome/app/breakpad_mac.mm
blob: a301e86f6bb982103467c40f17fe5a4da46a41eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "chrome/app/breakpad_mac.h"

#import <dlfcn.h>
#import <Foundation/Foundation.h>

#import "base/basictypes.h"
#import "base/logging.h"
#import "base/scoped_nsautorelease_pool.h"

// For definition of SetActiveRendererURL().
#import "chrome/renderer/renderer_logging.h"
#import "googleurl/src/gurl.h"

// TODO(jeremy): On Windows we store the current URL when a process crashes
// we probably want to do the same on OS X.

namespace {

// TODO(jeremy): Remove this block once we include the breakpad sources
// in the public tree.
typedef void* GoogleBreakpadRef;

typedef void (*GoogleBreakpadSetKeyValuePtr) (GoogleBreakpadRef, NSString*,
                                              NSString*);
typedef void (*GoogleBreakpadRemoveKeyValuePtr) (GoogleBreakpadRef, NSString*);
typedef GoogleBreakpadRef (*GoogleBreakPadCreatePtr) (NSDictionary*);
typedef void (*GoogleBreakPadReleasePtr) (GoogleBreakpadRef);


GoogleBreakpadRef gBreakpadRef = NULL;
GoogleBreakPadCreatePtr gBreakPadCreateFunc = NULL;
GoogleBreakPadReleasePtr gBreakPadReleaseFunc = NULL;
GoogleBreakpadSetKeyValuePtr gBreakpadSetKeyValueFunc = NULL;
GoogleBreakpadRemoveKeyValuePtr gBreakpadRemoveKeyValueFunc = NULL;

// Did the user optin for reporting stats.
bool IsStatsReportingAllowed() {
  NOTIMPLEMENTED();
  return true;
}

} // namespace

bool IsCrashReporterEnabled() {
  return gBreakpadRef == NULL;
}

void DestructCrashReporter() {
  if (gBreakpadRef) {
    DCHECK(gBreakPadReleaseFunc != NULL);
    gBreakPadReleaseFunc(gBreakpadRef);
    gBreakpadRef = NULL;
  }
}

void InitCrashReporter() {
  DCHECK(gBreakpadRef == NULL);
  base::ScopedNSAutoreleasePool autorelease_pool;

  // Check for Send stats preference. If preference is not specifically turned
  // on then disable crash reporting.
  if (!IsStatsReportingAllowed()) {
    LOG(WARNING) << "Breakpad disabled";
    return;
  }

  NSBundle* main_bundle = [NSBundle mainBundle];

  // Get location of breakpad.
  NSString* breakpadBundlePath = [[main_bundle privateFrameworksPath]
      stringByAppendingPathComponent:@"GoogleBreakpad.framework"];

  BOOL is_dir = NO;
  if (![[NSFileManager defaultManager] fileExistsAtPath:breakpadBundlePath
                                            isDirectory:&is_dir] || !is_dir) {
    return;
  }

  NSBundle* breakpad_bundle = [NSBundle bundleWithPath:breakpadBundlePath];
  if (![breakpad_bundle load]) {
     LOG(ERROR) << "Failed to load Breakpad framework.";
    return;
  }

  // Retrieve Breakpad interface functions.
  gBreakPadCreateFunc = reinterpret_cast<GoogleBreakPadCreatePtr>(
      dlsym(RTLD_DEFAULT, "GoogleBreakpadCreate"));
  gBreakPadReleaseFunc = reinterpret_cast<GoogleBreakPadReleasePtr>(
      dlsym(RTLD_DEFAULT, "GoogleBreakpadRelease"));
  gBreakpadSetKeyValueFunc = reinterpret_cast<GoogleBreakpadSetKeyValuePtr>(
      dlsym(RTLD_DEFAULT, "GoogleBreakpadSetKeyValue"));
  gBreakpadRemoveKeyValueFunc =
      reinterpret_cast<GoogleBreakpadRemoveKeyValuePtr>(
          dlsym(RTLD_DEFAULT, "GoogleBreakpadRemoveKeyValue"));

  if (!gBreakPadCreateFunc || !gBreakPadReleaseFunc
      || !gBreakpadSetKeyValueFunc || !gBreakpadRemoveKeyValueFunc) {
    LOG(ERROR) << "Failed to find Breakpad wrapper classes.";
    return;
  }

  NSDictionary* info_dictionary = [main_bundle infoDictionary];
  GoogleBreakpadRef breakpad = NULL;
  breakpad = gBreakPadCreateFunc(info_dictionary);
  if (!breakpad) {
    LOG(ERROR) << "Breakpad init failed.";
    return;
  }

  // TODO(jeremy): determine whether we're running in the browser or
  // renderer processes.
  bool is_renderer = false;

  // This needs to be set before calling SetCrashKeyValue().
  gBreakpadRef = breakpad;

  // Set breakpad MetaData values.
  NSString* version_str = [info_dictionary objectForKey:@"CFBundleVersion"];
  SetCrashKeyValue(@"ver", version_str);
  NSString* prod_name_str = [info_dictionary objectForKey:@"CFBundleExecutable"];
  SetCrashKeyValue(@"prod", prod_name_str);
  SetCrashKeyValue(@"plat", @"OS X");
  NSString *product_type = is_renderer ? @"renderer" : @"browser";
  SetCrashKeyValue(@"ptype", product_type);
}

void SetCrashKeyValue(NSString* key, NSString* value) {
  // Comment repeated from header to prevent confusion:
  // IMPORTANT: On OS X, the key/value pairs are sent to the crash server
  // out of bounds and not recorded on disk in the minidump, this means
  // that if you look at the minidump file locally you won't see them!
  if (gBreakpadRef == NULL) {
    return;
  }

  DCHECK(gBreakpadSetKeyValueFunc != NULL);
  gBreakpadSetKeyValueFunc(gBreakpadRef, key, value);
}

void ClearCrashKeyValue(NSString* key) {
  if (gBreakpadRef == NULL) {
    return;
  }

  DCHECK(gBreakpadRemoveKeyValueFunc != NULL);
  gBreakpadRemoveKeyValueFunc(gBreakpadRef, key);
}