Bug 368206 - Breakpad client for Mac OS X, patch by dcamp, r=luser+mento
authorbenjamin@smedbergs.us
Tue, 24 Jul 2007 18:06:00 -0700
changeset 3879 c18c348be9079b538234d59990f149941b0f71a4
parent 3878 99695a425dcfa4bd9ce3b6f5815633297f266a1e
child 3880 da8e5fea2d95c63082406f71f430c6f5041b5e0a
push idunknown
push userunknown
push dateunknown
reviewersluser
bugs368206
milestone1.9a7pre
Bug 368206 - Breakpad client for Mac OS X, patch by dcamp, r=luser+mento
toolkit/crashreporter/Makefile.in
toolkit/crashreporter/client/Makefile.in
toolkit/crashreporter/client/crashreporter.ini
toolkit/crashreporter/client/crashreporter_osx.h
toolkit/crashreporter/client/crashreporter_osx.mm
toolkit/crashreporter/client/macbuild/Contents/Info.plist
toolkit/crashreporter/client/macbuild/Contents/PkgInfo
toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in
toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib
toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib
toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
toolkit/crashreporter/google-breakpad/src/client/mac/handler/Makefile.in
toolkit/crashreporter/google-breakpad/src/common/mac/Makefile.in
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/crashreporter/test/Makefile.in
--- a/toolkit/crashreporter/Makefile.in
+++ b/toolkit/crashreporter/Makefile.in
@@ -55,16 +55,22 @@ DIRS = \
 	$(NULL)
 
 ifeq  ($(OS_ARCH),WINNT)
 	DIRS += airbag/src/common/windows \
 		airbag/src/client/windows \
 		$(NULL)
 endif
 
+ifeq ($(OS_ARCH),Darwin)
+	DIRS += airbag/src/common/mac \
+		airbag/src/client/mac/handler \
+		$(NULL)
+endif
+
 DIRS += client
 
 LOCAL_INCLUDES = -I$(srcdir)/airbag/src
 DEFINES += -DUNICODE -D_UNICODE
 
 XPIDLSRCS = \
 	nsICrashReporter.idl \
 	$(NULL)
--- a/toolkit/crashreporter/client/Makefile.in
+++ b/toolkit/crashreporter/client/Makefile.in
@@ -50,18 +50,44 @@ REQUIRES = sender
 
 #XXX: should move to toolkit/locale
 DIST_FILES = crashreporter.ini
 
 LOCAL_INCLUDES = -I$(srcdir)/../airbag/src
 
 ifeq ($(OS_ARCH),WINNT)
 CPPSRCS = crashreporter_win.cpp
-LIBS += $(DEPTH)/toolkit/airbag/airbag/src/client/windows/sender/$(LIB_PREFIX)crash_report_sender_s.$(LIB_SUFFIX)
-LIBS += $(DEPTH)/toolkit/airbag/airbag/src/common/windows/$(LIB_PREFIX)breakpad_windows_common_s.$(LIB_SUFFIX)
+LIBS += \
+	$(DEPTH)/toolkit/airbag/airbag/src/client/windows/sender/$(LIB_PREFIX)crash_report_sender_s.$(LIB_SUFFIX) \
+	$(DEPTH)/toolkit/airbag/airbag/src/common/windows/$(LIB_PREFIX)breakpad_windows_common_s.$(LIB_SUFFIX) \
+	$(NULL)
 LOCAL_INCLUDES += -I$(srcdir)
 RCINCLUDE = crashreporter.rc
 DEFINES += -DUNICODE -D_UNICODE
 OS_LIBS += $(call EXPAND_LIBNAME,comctl32 shell32 wininet shlwapi)
 MOZ_WINCONSOLE = 0
 endif
 
+ifeq ($(OS_ARCH),Darwin)
+CMMSRCS += crashreporter_osx.mm
+OS_LIBS += -framework Cocoa
+LIBS += \
+	$(DEPTH)/toolkit/airbag/airbag/src/client/mac/handler/$(LIB_PREFIX)exception_handler_s.$(LIB_SUFFIX) \
+	$(DEPTH)/toolkit/airbag/airbag/src/common/mac/$(LIB_PREFIX)breakpad_mac_common_s.$(LIB_SUFFIX) \
+	$(NULL)
+
+LOCAL_INCLUDES += -I$(srcdir) -I$(srcdir)/../airbag/src/common/mac/
+endif
+
 include $(topsrcdir)/config/rules.mk
+
+ifeq ($(OS_ARCH),Darwin)
+libs::
+	$(NSINSTALL) -D $(DIST)/bin/crashreporter.app
+	rsync -a -C --exclude "*.in" $(srcdir)/macbuild/Contents $(DIST)/bin/crashreporter.app 
+	sed -e "s/@APP_NAME@/$(MOZ_APP_DISPLAYNAME)/" $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \
+	  iconv -f UTF-8 -t UTF-16 > $(DIST)/bin/crashreporter.app/Contents/Resources/English.lproj/InfoPlist.strings
+	$(NSINSTALL) -D $(DIST)/bin/crashreporter.app/Contents/MacOS
+	$(NSINSTALL) $(DIST)/bin/crashreporter $(DIST)/bin/crashreporter.app/Contents/MacOS
+	rm -f $(DIST)/bin/crashreporter
+	$(NSINSTALL) $(DIST)/bin/crashreporter.ini $(DIST)/bin/crashreporter.app/Contents/MacOS
+	rm -f $(DIST)/bin/crashreporter.ini
+endif
--- a/toolkit/crashreporter/client/crashreporter.ini
+++ b/toolkit/crashreporter/client/crashreporter.ini
@@ -1,12 +1,15 @@
 ; This file is in the UTF-8 encoding
 [Strings]
 Ok=Ok
 Cancel=Cancel
+Send=Send
+DontSend=Don't Send
+Close=Close
 CrashReporterTitle=Mozilla Crash Reporter
 CrashReporterDescription=Crash reporting blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
 RadioEnable=Enable Crash Reporting
 RadioDisable=Disable Crash Reporting
 SendTitle=Sending Crash Report...
 SubmitSuccess=Crash report submitted successfully
 SubmitFailed=Failed to submit crash report
 CrashID=Crash ID: %s
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/client/crashreporter_osx.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Toolkit Crash Reporter
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dave Camp <dcamp@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef CRASHREPORTER_OSX_H__
+#define CRASHREPORTER_OSX_H__
+
+#include <Cocoa/Cocoa.h>
+#include "HTTPMultipartUpload.h"
+
+@interface CrashReporterUI : NSObject
+{
+    /* Enabled view */
+    IBOutlet NSView *enableView;
+
+    IBOutlet NSTextField *descriptionLabel;
+    IBOutlet NSButton *disableReportingButton;
+    IBOutlet NSButton *dontSendButton;
+    IBOutlet NSButton *sendButton;
+
+    /* Upload progress view */
+    IBOutlet NSView *uploadingView;
+
+    IBOutlet NSTextField *progressLabel;
+    IBOutlet NSProgressIndicator *progressBar;
+    IBOutlet NSButton *closeButton;
+
+    HTTPMultipartUpload *mPost;
+}
+
+- (IBAction)closeClicked:(id)sender;
+- (IBAction)sendClicked:(id)sender;
+
+- (void)setView:(NSWindow *)w newView: (NSView *)v animate: (BOOL) animate;
+- (void)setupPost;
+- (void)uploadThread:(id)post;
+- (void)uploadComplete:(id)error;
+
+@end
+
+#endif
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/client/crashreporter_osx.mm
@@ -0,0 +1,273 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Toolkit Crash Reporter
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dave Camp <dcamp@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#import <Cocoa/Cocoa.h>
+#include "crashreporter_osx.h"
+
+#include <string>
+#include <map>
+#include <fstream>
+
+using std::string;
+using std::map;
+using std::ifstream;
+
+typedef map<string,string> StringTable;
+typedef map<string,StringTable> StringTableSections;
+
+static string               kExtraDataExtension = ".extra";
+
+static string               gMinidumpPath;
+static string               gExtraDataPath;
+static StringTableSections  gStrings;
+static StringTable          gExtraData;
+
+static BOOL                 gSendFailed;
+
+static NSString *
+Str(const char *aName, const char *aSection="Strings")
+{
+  string str = gStrings[aSection][aName];
+  if (str.empty()) str = "?";
+  return [NSString stringWithUTF8String:str.c_str()];
+}
+
+static bool
+ReadStrings(const string &aPath, StringTableSections *aSections)
+{
+  StringTableSections &sections = *aSections;
+
+  ifstream f(aPath.c_str());
+  if (!f.is_open()) return false;
+
+  string currentSection;
+  while (!f.eof()) {
+    string line;
+    std::getline(f, line);
+    if (line[0] == ';') continue;
+
+    if (line[0] == '[') {
+      int close = line.find(']');
+      if (close >= 0)
+        currentSection = line.substr(1, close - 1);
+      continue;
+    }
+
+    int sep = line.find('=');
+    if (sep >= 0)
+      sections[currentSection][line.substr(0, sep)] = line.substr(sep + 1);
+  }
+
+  return f.eof();
+}
+
+@implementation CrashReporterUI
+
+-(void)awakeFromNib
+{
+  NSWindow *w = [descriptionLabel window];
+  [w center];
+
+  [w setTitle:[[NSBundle mainBundle]
+                objectForInfoDictionaryKey:@"CFBundleName"]];
+  [descriptionLabel setStringValue:Str("CrashReporterDescription")];
+  [disableReportingButton setTitle:Str("RadioDisable")];
+
+  if (!gMinidumpPath.empty()) {
+    [sendButton setTitle:Str("Send")];
+    [sendButton setKeyEquivalent:@"\r"];
+    [dontSendButton setTitle:Str("DontSend")];
+  } else {
+    [dontSendButton setFrame:[sendButton frame]];
+    [dontSendButton setTitle:Str("Close")];
+    [dontSendButton setKeyEquivalent:@"\r"];
+    [sendButton removeFromSuperview];
+  }
+
+  [closeButton setTitle:Str("Close")];
+
+  [w makeKeyAndOrderFront:nil];
+}
+
+-(IBAction)closeClicked:(id)sender
+{
+  [NSApp terminate: self];
+}
+
+-(IBAction)sendClicked:(id)sender
+{
+  NSWindow *w = [descriptionLabel window];
+
+  [progressBar startAnimation: self];
+  [progressLabel setStringValue:Str("SendTitle")];
+
+  [self setupPost];
+
+  if (mPost) {
+    [self setView: w newView: uploadingView animate: YES];
+    [progressBar startAnimation: self];
+
+    [NSThread detachNewThreadSelector:@selector(uploadThread:)
+              toTarget:self
+              withObject:nil];
+  }
+}
+
+-(void)setView:(NSWindow *)w newView: (NSView *)v animate: (BOOL)animate
+{
+  NSRect frame = [w frame];
+
+  NSRect oldViewFrame = [[w contentView] frame];
+  NSRect newViewFrame = [uploadingView frame];
+
+  frame.origin.y += oldViewFrame.size.height - newViewFrame.size.height;
+  frame.size.height -= oldViewFrame.size.height - newViewFrame.size.height;
+
+  frame.origin.x += oldViewFrame.size.width - newViewFrame.size.width;
+  frame.size.width -= oldViewFrame.size.width - newViewFrame.size.width;
+
+  [w setContentView: v];
+  [w setFrame: frame display: true animate: animate];
+}
+
+-(void)setupPost
+{
+  NSURL *url = [NSURL URLWithString:Str("URL", "Settings")];
+  if (!url) return;
+
+  mPost = [[HTTPMultipartUpload alloc] initWithURL: url];
+  if (!mPost) return;
+
+  NSMutableDictionary *parameters =
+    [[NSMutableDictionary alloc] initWithCapacity: gExtraData.size()];
+
+  StringTable::const_iterator end = gExtraData.end();
+  for (StringTable::const_iterator i = gExtraData.begin(); i != end; i++) {
+    NSString *key = [NSString stringWithUTF8String: i->first.c_str()];
+    NSString *value = [NSString stringWithUTF8String: i->second.c_str()];
+    [parameters setObject: value forKey: key];
+  }
+
+  [mPost setParameters: parameters];
+
+  [mPost addFileAtPath: [NSString stringWithUTF8String: gMinidumpPath.c_str()]
+        name: @"upload_file_minidump"];
+}
+
+-(void)uploadComplete:(id)error
+{
+  [progressBar stopAnimation: self];
+
+  NSHTTPURLResponse *response = [mPost response];
+
+  NSString *status;
+  if (error || !response || [response statusCode] != 200) {
+    status = Str("SubmitFailed");
+    gSendFailed = YES;
+  } else
+    status = Str("SubmitSuccess");
+
+  [progressLabel setStringValue: status];
+  [closeButton setEnabled: true];
+  [closeButton setKeyEquivalent:@"\r"];
+}
+
+-(void)uploadThread:(id)post
+{
+  NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
+  NSError *error = nil;
+  [mPost send: &error];
+
+  [self performSelectorOnMainThread: @selector(uploadComplete:)
+        withObject: error
+        waitUntilDone: nil];
+
+  [autoreleasepool release];
+}
+
+@end
+
+string
+GetExtraDataFilename(const string& dumpfile)
+{
+  string filename(dumpfile);
+  int dot = filename.rfind('.');
+  if (dot < 0)
+    return "";
+
+  filename.replace(dot, filename.length() - dot, kExtraDataExtension);
+  return filename;
+}
+
+int
+main(int argc, char *argv[])
+{
+  NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
+  string iniPath(argv[0]);
+  iniPath.append(".ini");
+  if (!ReadStrings(iniPath, &gStrings)) {
+    printf("couldn't read strings\n");
+    return -1;
+  }
+
+  if (argc > 1) {
+    gMinidumpPath = argv[1];
+    gExtraDataPath = GetExtraDataFilename(gMinidumpPath);
+    if (!gExtraDataPath.empty()) {
+      StringTableSections table;
+      ReadStrings(gExtraDataPath, &table);
+      gExtraData = table[""];
+    }
+  }
+
+  gSendFailed = NO;
+
+  int ret = NSApplicationMain(argc,  (const char **) argv);
+
+  string deleteSetting = gStrings["Settings"]["Delete"];
+  if (!gSendFailed &&
+      (deleteSetting.empty() || atoi(deleteSetting.c_str()) > 0)) {
+    remove(gMinidumpPath.c_str());
+    if (!gExtraDataPath.empty())
+      remove(gExtraDataPath.c_str());
+  }
+
+  [autoreleasepool release];
+
+  return ret;
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/client/macbuild/Contents/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>crashreporter</string>
+	<key>CFBundleIconFile</key>
+	<string></string>
+	<key>CFBundleIdentifier</key>
+	<string>org.mozilla.crashreporter</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>NSMainNibFile</key>
+	<string>MainMenu</string>
+	<key>NSPrincipalClass</key>
+	<string>NSApplication</string>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/client/macbuild/Contents/PkgInfo
@@ -0,0 +1,2 @@
+APPL????
+
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in
@@ -0,0 +1,4 @@
+/* Localized versions of Info.plist keys */
+
+CFBundleName = "@APP_NAME@ Crash Reporter";
+NSHumanReadableCopyright = "Copyright © 2007 Mozilla Foundation";
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib
@@ -0,0 +1,23 @@
+{
+    IBClasses = (
+        {
+            ACTIONS = {closeClicked = id; sendClicked = id; }; 
+            CLASS = CrashReporterUI; 
+            LANGUAGE = ObjC; 
+            OUTLETS = {
+                closeButton = NSButton; 
+                descriptionLabel = NSTextField; 
+                disableReportingButton = NSButton; 
+                dontSendButton = NSButton; 
+                enableView = NSView; 
+                progressBar = NSProgressIndicator; 
+                progressLabel = NSTextField; 
+                sendButton = NSButton; 
+                uploadingView = NSView; 
+            }; 
+            SUPERCLASS = NSObject; 
+        }, 
+        {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }
+    ); 
+    IBVersion = 1; 
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IBDocumentLocation</key>
+	<string>299 87 356 240 0 0 1440 878 </string>
+	<key>IBEditorPositions</key>
+	<dict>
+		<key>282</key>
+		<string>445 520 550 163 0 0 1440 878 </string>
+		<key>29</key>
+		<string>447 315 137 44 0 0 1440 878 </string>
+		<key>356</key>
+		<string>643 213 551 213 0 0 1440 878 </string>
+	</dict>
+	<key>IBFramework Version</key>
+	<string>446.1</string>
+	<key>IBLockedObjects</key>
+	<array>
+		<integer>282</integer>
+		<integer>356</integer>
+	</array>
+	<key>IBOldestOS</key>
+	<integer>2</integer>
+	<key>IBOpenObjects</key>
+	<array>
+		<integer>21</integer>
+		<integer>29</integer>
+		<integer>282</integer>
+	</array>
+	<key>IBSystem Version</key>
+	<string>8P2137</string>
+</dict>
+</plist>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5c6535a57719dc2acc1aa92a744f4ac3b3781088
GIT binary patch
literal 9153
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
E055y%O8@`>
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/handler/Makefile.in
@@ -0,0 +1,59 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla Breakpad integration
+#
+# The Initial Developer of the Original Code is
+# Ted Mielczarek <ted.mielczarek@gmail.com>
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../../../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= handler
+LIBRARY_NAME	= exception_handler_s
+XPI_NAME 	= crashreporter
+
+LOCAL_INCLUDES 	= -I$(srcdir)/../../..
+
+CPPSRCS		= \
+		exception_handler.cc \
+		minidump_generator.cc \
+		../../minidump_file_writer.cc \
+		$(NULL)
+
+# need static lib
+FORCE_STATIC_LIB = 1
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/common/mac/Makefile.in
@@ -0,0 +1,68 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla Breakpad integration
+#
+# The Initial Developer of the Original Code is
+# Ted Mielczarek <ted.mielczarek@gmail.com>
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= breakpad_mac_common
+LIBRARY_NAME	= breakpad_mac_common_s
+
+LOCAL_INCLUDES 	= -I$(srcdir)/../..
+
+CPPSRCS		= \
+		file_id.cc \
+		macho_id.cc \
+		macho_walker.cc \
+		string_utilities.cc \
+		../string_conversion.cc \
+		$(NULL)
+
+CMSRCS		= \
+		HTTPMultipartUpload.m \
+		$(NULL)
+
+CSRCS           = \
+		../convert_UTF.c
+
+
+# need static lib
+FORCE_STATIC_LIB = 1
+
+include $(topsrcdir)/config/rules.mk
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -32,104 +32,130 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsAirbagExceptionHandler.h"
 
-#ifdef XP_WIN32
+#if defined(XP_WIN32)
 #ifdef WIN32_LEAN_AND_MEAN
 #undef WIN32_LEAN_AND_MEAN
 #endif
 
 #include "client/windows/handler/exception_handler.h"
 #include <string.h>
+#elif defined(XP_MACOSX)
+#include "client/mac/handler/exception_handler.h"
+#include <string>
+#include <Carbon/Carbon.h>
+#include <fcntl.h>
 #else
 #error "Not yet implemented for this platform"
-#endif // XP_WIN32
+#endif // defined(XP_WIN32)
 
 #ifndef HAVE_CPP_2BYTE_WCHAR_T
 #error "This code expects a 2 byte wchar_t.  You should --disable-airbag."
 #endif
 
 #include <stdlib.h>
 #include <prenv.h>
 #include "nsDebug.h"
 #include "nsCRT.h"
 #include "nsILocalFile.h"
 #include "nsDataHashtable.h"
 
-#ifdef XP_WIN32
-#define CRASH_REPORTER_FILENAME "crashreporter.exe"
-#define PATH_SEPARATOR "\\"
-#else
-#define CRASH_REPORTER_FILENAME "crashreporter"
-#define PATH_SEPARATOR "/"
-#endif
-
 namespace CrashReporter {
 
-using std::wstring;
+#ifdef XP_WIN32
+typedef wchar_t XP_CHAR;
+#define TO_NEW_XP_CHAR(x) ToNewUnicode(x)
+#define CONVERT_UTF16_TO_XP_CHAR(x) x
+#define XP_STRLEN(x) wcslen(x)
+#define CRASH_REPORTER_FILENAME "crashreporter.exe"
+#define PATH_SEPARATOR "\\"
+#define XP_PATH_SEPARATOR L"\\"
+// sort of arbitrary, but MAX_PATH is kinda small
+#define XP_PATH_MAX 4096
+// "<reporter path>" "<minidump path>"
+#define CMDLINE_SIZE ((XP_PATH_MAX * 2) + 6)
+#else
+typedef char XP_CHAR;
+#define TO_NEW_XP_CHAR(x) ToNewUTF8String(x)
+#define CONVERT_UTF16_TO_XP_CHAR(x) NS_ConvertUTF16toUTF8(x)
+#define XP_STRLEN(x) strlen(x)
+#define CRASH_REPORTER_FILENAME "crashreporter"
+#define PATH_SEPARATOR "/"
+#define XP_PATH_SEPARATOR "/"
+#define XP_PATH_MAX PATH_MAX
+#endif // XP_WIN32
 
-static const PRUnichar dumpFileExtension[] = {'.', 'd', 'm', 'p',
-                                              '\"', '\0'}; // .dmp"
-static const PRUnichar extraFileExtension[] = {'.', 'e', 'x', 't',
-                                              'r', 'a', '\0'}; // .extra
-
-// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-static const PRInt32 kGUIDLength = 36;
-// length of a GUID + .dmp" (yes, trailing double quote)
-static const PRInt32 kMinidumpFilenameLength =
-  kGUIDLength + sizeof(dumpFileExtension) / sizeof(dumpFileExtension[0]);
+static const XP_CHAR dumpFileExtension[] = {'.', 'd', 'm', 'p',
+                                            '\0'}; // .dmp
+static const XP_CHAR extraFileExtension[] = {'.', 'e', 'x', 't',
+                                             'r', 'a', '\0'}; // .extra
 
 static google_breakpad::ExceptionHandler* gExceptionHandler = nsnull;
 
-// for ease of replacing the dump path when someone
-// calls SetMinidumpPath
-static nsString* crashReporterCmdLine_withoutDumpPath = nsnull;
-// this is set up so we don't have to do heap allocation in the handler
-static PRUnichar* crashReporterCmdLine = nsnull;
-// points at the end of the previous string
-// so we can append the minidump filename
-static PRUnichar* crashReporterCmdLineEnd = nsnull;
-// space to hold a filename for the API data
-static PRUnichar* crashReporterAPIDataFilename = nsnull;
-static PRUnichar* crashReporterAPIDataFilenameEnd = nsnull;
+static XP_CHAR* crashReporterPath;
 
 // this holds additional data sent via the API
 static nsDataHashtable<nsCStringHashKey,nsCString>* crashReporterAPIData_Hash;
 static nsCString* crashReporterAPIData = nsnull;
 
-bool MinidumpCallback(const wchar_t *dump_path,
-                      const wchar_t *minidump_id,
-                      void *context,
-                      EXCEPTION_POINTERS *exinfo,
-                      MDRawAssertionInfo *assertion,
+static XP_CHAR*
+Concat(XP_CHAR* str, const XP_CHAR* toAppend, int* size)
+{
+  int appendLen = XP_STRLEN(toAppend);
+  if (appendLen >= *size) appendLen = *size - 1;
+
+  memcpy(str, toAppend, appendLen * sizeof(XP_CHAR));
+  str += appendLen;
+  *str = '\0';
+  *size -= appendLen;
+
+  return str;
+}
+
+bool MinidumpCallback(const XP_CHAR* dump_path,
+                      const XP_CHAR* minidump_id,
+                      void* context,
+#ifdef XP_WIN32
+                      EXCEPTION_POINTERS* exinfo,
+                      MDRawAssertionInfo* assertion,
+#endif
                       bool succeeded)
 {
-  // append minidump filename to command line
-  memcpy(crashReporterCmdLineEnd, minidump_id,
-         kGUIDLength * sizeof(PRUnichar));
-  // this will copy the null terminator as well
-  memcpy(crashReporterCmdLineEnd + kGUIDLength,
-         dumpFileExtension, sizeof(dumpFileExtension));
+  XP_CHAR minidumpPath[XP_PATH_MAX];
+  int size = XP_PATH_MAX;
+  XP_CHAR* p = Concat(minidumpPath, dump_path, &size);
+  p = Concat(p, XP_PATH_SEPARATOR, &size);
+  p = Concat(p, minidump_id, &size);
+  Concat(p, dumpFileExtension, &size);
 
-  // append minidump filename to API data filename
-  memcpy(crashReporterAPIDataFilenameEnd, minidump_id,
-         kGUIDLength * sizeof(PRUnichar));
-  // this will copy the null terminator as well
-  memcpy(crashReporterAPIDataFilenameEnd + kGUIDLength,
-         extraFileExtension, sizeof(extraFileExtension));
+  XP_CHAR extraDataPath[XP_PATH_MAX];
+  size = XP_PATH_MAX;
+  p = Concat(extraDataPath, dump_path, &size);
+  p = Concat(p, XP_PATH_SEPARATOR, &size);
+  p = Concat(p, minidump_id, &size);
+  Concat(p, extraFileExtension, &size);
 
 #ifdef XP_WIN32
+  XP_CHAR cmdLine[CMDLINE_SIZE];
+  size = CMDLINE_SIZE;
+  p = Concat(cmdLine, L"\"", &size);
+  p = Concat(p, crashReporterPath, &size);
+  p = Concat(p, L"\" \"", &size);
+  p = Concat(p, minidumpPath, &size);
+  Concat(p, L"\"", &size);
+
   if (!crashReporterAPIData->IsEmpty()) {
     // write out API data
-    HANDLE hFile = CreateFile(crashReporterAPIDataFilename, GENERIC_WRITE, 0,
+    HANDLE hFile = CreateFile(extraDataPath, GENERIC_WRITE, 0,
                               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
                               NULL);
     if(hFile != INVALID_HANDLE_VALUE) {
       DWORD nBytes;
       WriteFile(hFile, crashReporterAPIData->get(),
                 crashReporterAPIData->Length(), &nBytes, NULL);
       CloseHandle(hFile);
     }
@@ -139,96 +165,139 @@ bool MinidumpCallback(const wchar_t *dum
   PROCESS_INFORMATION pi;
 
   ZeroMemory(&si, sizeof(si));
   si.cb = sizeof(si);
   si.dwFlags = STARTF_USESHOWWINDOW;
   si.wShowWindow = SW_SHOWNORMAL;
   ZeroMemory(&pi, sizeof(pi));
 
-  if (CreateProcess(NULL, (LPWSTR)crashReporterCmdLine, NULL, NULL, FALSE, 0,
+  if (CreateProcess(NULL, (LPWSTR)cmdLine, NULL, NULL, FALSE, 0,
                     NULL, NULL, &si, &pi)) {
     CloseHandle( pi.hProcess );
     CloseHandle( pi.hThread );
   }
   // we're not really in a position to do anything if the CreateProcess fails
   TerminateProcess(GetCurrentProcess(), 1);
-#endif
-  return succeeded;
-}
-
-static nsresult BuildCommandLine(const nsAString &tempPath)
-{
-  nsString crashReporterCmdLine_temp =
-    *crashReporterCmdLine_withoutDumpPath + NS_LITERAL_STRING(" \"") + tempPath;
-  PRInt32 cmdLineLength = crashReporterCmdLine_temp.Length();
+#elif defined(XP_UNIX)
+  if (!crashReporterAPIData->IsEmpty()) {
+    // write out API data
+    int fd = open(extraDataPath,
+                  O_WRONLY | O_CREAT | O_TRUNC,
+                  0666);
 
-  // allocate extra space for minidump file name
-  crashReporterCmdLine_temp.SetLength(cmdLineLength + kMinidumpFilenameLength
-                                      + 1);
-  crashReporterCmdLine = ToNewUnicode(crashReporterCmdLine_temp);
-  crashReporterCmdLineEnd = crashReporterCmdLine + cmdLineLength;
-
-  // build API data filename
-  if(crashReporterAPIDataFilename != nsnull) {
-    NS_Free(crashReporterAPIDataFilename);
-    crashReporterAPIDataFilename = nsnull;
+    if (fd != -1) {
+      // not much we can do in case of error
+      write(fd, crashReporterAPIData->get(), crashReporterAPIData->Length());
+      close (fd);
+    }
   }
 
-  nsString apiDataFilename_temp(tempPath);
-  PRInt32 filenameLength = apiDataFilename_temp.Length();
-  apiDataFilename_temp.SetLength(filenameLength + kMinidumpFilenameLength + 1);
-  crashReporterAPIDataFilename = ToNewUnicode(apiDataFilename_temp);
-  crashReporterAPIDataFilenameEnd =
-    crashReporterAPIDataFilename + filenameLength;
+  pid_t pid = fork();
 
-  return NS_OK;
+  if (pid == -1)
+    return false;
+  else if (pid == 0) {
+    (void) execl(crashReporterPath,
+                 crashReporterPath, minidumpPath, (char*)0);
+    _exit(1);
+  }
+#endif
+
+ return succeeded;
 }
 
 static nsresult GetExecutablePath(nsString& exePath)
 {
+#if !defined(XP_MACOSX)
+
 #ifdef XP_WIN32
-  // sort of arbitrary, but MAX_PATH is kinda small
-  exePath.SetLength(4096);
-  if (!GetModuleFileName(NULL, (LPWSTR)exePath.BeginWriting(), 4096))
+  exePath.SetLength(XP_PATH_MAX);
+  if (!GetModuleFileName(NULL, (LPWSTR)exePath.BeginWriting(), XP_PATH_MAX))
     return NS_ERROR_FAILURE;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif
 
   NS_NAMED_LITERAL_STRING(pathSep, PATH_SEPARATOR);
 
   PRInt32 lastSlash = exePath.RFind(pathSep);
   if (lastSlash < 0)
     return NS_ERROR_FAILURE;
 
   exePath.Truncate(lastSlash + 1);
 
   return NS_OK;
+
+#else // !defined(XP_MACOSX)
+
+  CFBundleRef appBundle = CFBundleGetMainBundle();
+  if (!appBundle)
+    return NS_ERROR_FAILURE;
+
+  CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
+  if (!executableURL)
+    return NS_ERROR_FAILURE;
+
+  CFURLRef bundleURL = CFURLCreateCopyDeletingLastPathComponent(NULL,
+                                                                executableURL);
+  CFRelease(executableURL);
+
+  if (!bundleURL)
+    return NS_ERROR_FAILURE;
+
+  CFURLRef reporterURL = CFURLCreateCopyAppendingPathComponent(
+    NULL,
+    bundleURL,
+    CFSTR("crashreporter.app/Contents/MacOS/"),
+    false);
+  CFRelease(bundleURL);
+
+  if (!reporterURL)
+    return NS_ERROR_FAILURE;
+
+  FSRef fsRef;
+  if (!CFURLGetFSRef(reporterURL, &fsRef)) {
+    CFRelease(reporterURL);
+    return NS_ERROR_FAILURE;
+  }
+
+  CFRelease(reporterURL);
+
+  char path[PATH_MAX + 1];
+  OSStatus status = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX);
+  if (status != noErr)
+    return NS_ERROR_FAILURE;
+
+  int len = strlen(path);
+  path[len] = '/';
+  path[len + 1] = '\0';
+
+  exePath = NS_ConvertUTF8toUTF16(path);
+
+  return NS_OK;
+#endif
 }
 
 nsresult SetExceptionHandler(nsILocalFile* aXREDirectory)
 {
   nsresult rv;
 
   if (gExceptionHandler)
     return NS_ERROR_ALREADY_INITIALIZED;
 
   // check environment var to see if we're enabled.
   // we're off by default until we sort out the
   // rest of the infrastructure,
   // so it must exist and be set to a non-zero value.
-  const char *airbagEnv = PR_GetEnv("MOZ_AIRBAG");
+  const char* airbagEnv = PR_GetEnv("MOZ_AIRBAG");
   if (airbagEnv == NULL || atoi(airbagEnv) == 0)
     return NS_ERROR_NOT_AVAILABLE;
 
   // allocate our strings
-  crashReporterCmdLine_withoutDumpPath = new nsString();
-  NS_ENSURE_TRUE(crashReporterCmdLine_withoutDumpPath, NS_ERROR_OUT_OF_MEMORY);
-
   crashReporterAPIData = new nsCString();
   NS_ENSURE_TRUE(crashReporterAPIData, NS_ERROR_OUT_OF_MEMORY);
 
   crashReporterAPIData_Hash =
     new nsDataHashtable<nsCStringHashKey,nsCString>();
   NS_ENSURE_TRUE(crashReporterAPIData_Hash, NS_ERROR_OUT_OF_MEMORY);
 
   rv = crashReporterAPIData_Hash->Init();
@@ -242,113 +311,88 @@ nsresult SetExceptionHandler(nsILocalFil
   }
   else {
     rv = GetExecutablePath(exePath);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   NS_NAMED_LITERAL_STRING(crashReporterFilename, CRASH_REPORTER_FILENAME);
 
-  // note that we enclose the exe filename in double quotes
-  crashReporterCmdLine_withoutDumpPath->Assign(NS_LITERAL_STRING("\"") +
-                                               exePath +
-                                               crashReporterFilename +
-                                               NS_LITERAL_STRING("\""));
+  crashReporterPath = TO_NEW_XP_CHAR(exePath + crashReporterFilename);
 
   // get temp path to use for minidump path
   nsString tempPath;
 #ifdef XP_WIN32
   // first figure out buffer size
   int pathLen = GetTempPath(0, NULL);
   if (pathLen == 0)
     return NS_ERROR_FAILURE;
 
   tempPath.SetLength(pathLen);
   GetTempPath(pathLen, (LPWSTR)tempPath.BeginWriting());
-#endif
+#elif defined(XP_MACOSX)
+  FSRef fsRef;
+  OSErr err = FSFindFolder(kUserDomain, kTemporaryFolderType,
+                           kCreateFolder, &fsRef);
+  if (err != noErr)
+    return NS_ERROR_FAILURE;
 
-  rv = BuildCommandLine(tempPath);
-  NS_ENSURE_SUCCESS(rv, rv);
+  tempPath.SetLength(PATH_MAX);
+  OSStatus status = FSRefMakePath(&fsRef,
+                                  (UInt8*)tempPath.BeginWriting(), PATH_MAX);
+  if (status != noErr)
+    return NS_ERROR_FAILURE;
+#else
+  //XXX: implement get temp path on other platforms
+  return NS_ERROR_NOT_IMPLEMENTED;
+#endif
 
   // finally, set the exception handler
-  gExceptionHandler = new google_breakpad::ExceptionHandler(
-                                            PromiseFlatString(tempPath).get(),
-                                            nsnull,
-                                            MinidumpCallback,
-                                            nsnull,
-                                            true);
+  gExceptionHandler = new google_breakpad::
+    ExceptionHandler(CONVERT_UTF16_TO_XP_CHAR(tempPath).get(),
+                     nsnull,
+                     MinidumpCallback,
+                     nsnull,
+                     true);
 
   if (!gExceptionHandler)
     return NS_ERROR_OUT_OF_MEMORY;
 
   return NS_OK;
 }
 
 nsresult SetMinidumpPath(const nsAString& aPath)
 {
   if (!gExceptionHandler)
     return NS_ERROR_NOT_INITIALIZED;
 
-  if(crashReporterCmdLine != nsnull) {
-    NS_Free(crashReporterCmdLine);
-    crashReporterCmdLine = nsnull;
-  }
-
-  NS_NAMED_LITERAL_STRING(pathSep, PATH_SEPARATOR);
-
-  nsresult rv;
+  gExceptionHandler->set_dump_path(CONVERT_UTF16_TO_XP_CHAR(aPath).BeginReading());
 
-  if(!StringEndsWith(aPath, pathSep)) {
-    rv = BuildCommandLine(aPath + pathSep);
-  }
-  else {
-    rv = BuildCommandLine(aPath);
-  }
-
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  gExceptionHandler->set_dump_path(PromiseFlatString(aPath).get());
   return NS_OK;
 }
 
 nsresult UnsetExceptionHandler()
 {
   // do this here in the unlikely case that we succeeded in allocating
   // our strings but failed to allocate gExceptionHandler.
-  if (crashReporterCmdLine_withoutDumpPath) {
-    delete crashReporterCmdLine_withoutDumpPath;
-    crashReporterCmdLine_withoutDumpPath = nsnull;
-  }
-  if (crashReporterAPIData) {
-    delete crashReporterAPIData;
-    crashReporterAPIData = nsnull;
-  }
   if (crashReporterAPIData_Hash) {
     delete crashReporterAPIData_Hash;
     crashReporterAPIData_Hash = nsnull;
   }
+  if (crashReporterPath) {
+    NS_Free(crashReporterPath);
+    crashReporterPath = nsnull;
+  }
 
   if (!gExceptionHandler)
     return NS_ERROR_NOT_INITIALIZED;
 
   delete gExceptionHandler;
   gExceptionHandler = nsnull;
 
-  if(crashReporterCmdLine != nsnull) {
-    NS_Free(crashReporterCmdLine);
-    crashReporterCmdLine = nsnull;
-  }
-
-  if(crashReporterAPIDataFilename != nsnull) {
-    NS_Free(crashReporterAPIDataFilename);
-    crashReporterAPIDataFilename = nsnull;
-  }
-
-  crashReporterCmdLineEnd = nsnull;
-
   return NS_OK;
 }
 
 static void ReplaceChar(nsCString& str, const nsACString& character,
                         const nsACString& replacement)
 {
   nsCString::const_iterator start, end;
   
--- a/toolkit/crashreporter/test/Makefile.in
+++ b/toolkit/crashreporter/test/Makefile.in
@@ -66,16 +66,24 @@ MOZILLA_INTERNAL_API = 1
 
 include $(topsrcdir)/config/rules.mk
 
 ifeq ($(OS_ARCH),WINNT)
 LIBS += \
 	$(DEPTH)/toolkit/airbag/airbag/src/client/windows/handler/$(LIB_PREFIX)exception_handler_s.$(LIB_SUFFIX) \
 	$(DEPTH)/toolkit/airbag/airbag/src/common/windows/$(LIB_PREFIX)breakpad_windows_common_s.$(LIB_SUFFIX)
 LIBS += $(call expand_libname shell32)
+OS_LIBS += $(call EXPAND_LIBNAME,ole32)
 endif
 
-OS_LIBS += $(call EXPAND_LIBNAME,ole32)
+ifeq ($(OS_ARCH),Darwin)
+OS_LIBS += -framework Cocoa -lcrypto
+LIBS += \
+	$(DEPTH)/toolkit/airbag/airbag/src/client/mac/handler/$(LIB_PREFIX)exception_handler_s.$(LIB_SUFFIX) \
+	$(DEPTH)/toolkit/airbag/airbag/src/common/mac/$(LIB_PREFIX)breakpad_mac_common_s.$(LIB_SUFFIX) \
+	$(NULL)
+LOCAL_INCLUDES += -I$(srcdir) -I$(srcdir)/../airbag/src/common/mac/
+endif
 
 ifndef MOZ_ENABLE_LIBXUL
 check:: $(PROGRAM)
 	$(RUN_TEST_PROGRAM) $(DIST)/bin/TestCrashReporterAPI
 endif