diff --git a/toolkit/crashreporter/Makefile.in b/toolkit/crashreporter/Makefile.in index 96b9c3d5d1c..82cda6748fe 100644 --- a/toolkit/crashreporter/Makefile.in +++ b/toolkit/crashreporter/Makefile.in @@ -60,6 +60,12 @@ ifeq ($(OS_ARCH),WINNT) $(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 diff --git a/toolkit/crashreporter/client/Makefile.in b/toolkit/crashreporter/client/Makefile.in index 7176d01254a..c9fe393c052 100644 --- a/toolkit/crashreporter/client/Makefile.in +++ b/toolkit/crashreporter/client/Makefile.in @@ -55,8 +55,10 @@ 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 @@ -64,4 +66,28 @@ 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 diff --git a/toolkit/crashreporter/client/crashreporter.ini b/toolkit/crashreporter/client/crashreporter.ini index 28946f445cf..3e1b4af5162 100644 --- a/toolkit/crashreporter/client/crashreporter.ini +++ b/toolkit/crashreporter/client/crashreporter.ini @@ -2,6 +2,9 @@ [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 diff --git a/toolkit/crashreporter/client/crashreporter_osx.h b/toolkit/crashreporter/client/crashreporter_osx.h new file mode 100644 index 00000000000..4271c1c5ef5 --- /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 + * + * 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 +#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 diff --git a/toolkit/crashreporter/client/crashreporter_osx.mm b/toolkit/crashreporter/client/crashreporter_osx.mm new file mode 100644 index 00000000000..959aa606af3 --- /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 + * + * 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 +#include "crashreporter_osx.h" + +#include +#include +#include + +using std::string; +using std::map; +using std::ifstream; + +typedef map StringTable; +typedef map 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 §ions = *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; +} diff --git a/toolkit/crashreporter/client/macbuild/Contents/Info.plist b/toolkit/crashreporter/client/macbuild/Contents/Info.plist new file mode 100644 index 00000000000..e01f08573f9 --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + crashreporter + CFBundleIconFile + + CFBundleIdentifier + org.mozilla.crashreporter + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/toolkit/crashreporter/client/macbuild/Contents/PkgInfo b/toolkit/crashreporter/client/macbuild/Contents/PkgInfo new file mode 100644 index 00000000000..cae6d0a58f2 --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/PkgInfo @@ -0,0 +1,2 @@ +APPL???? + diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in new file mode 100644 index 00000000000..bc4d474d9ca --- /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"; diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib new file mode 100644 index 00000000000..3f5bb620adc --- /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 diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib new file mode 100644 index 00000000000..18dc633857e --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib @@ -0,0 +1,34 @@ + + + + + IBDocumentLocation + 299 87 356 240 0 0 1440 878 + IBEditorPositions + + 282 + 445 520 550 163 0 0 1440 878 + 29 + 447 315 137 44 0 0 1440 878 + 356 + 643 213 551 213 0 0 1440 878 + + IBFramework Version + 446.1 + IBLockedObjects + + 282 + 356 + + IBOldestOS + 2 + IBOpenObjects + + 21 + 29 + 282 + + IBSystem Version + 8P2137 + + diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib new file mode 100644 index 00000000000..5c6535a5771 Binary files /dev/null and b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/toolkit/crashreporter/google-breakpad/src/client/mac/handler/Makefile.in b/toolkit/crashreporter/google-breakpad/src/client/mac/handler/Makefile.in new file mode 100644 index 00000000000..581a1151f41 --- /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 +# 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 diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/Makefile.in b/toolkit/crashreporter/google-breakpad/src/common/mac/Makefile.in new file mode 100644 index 00000000000..d01df8f766e --- /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 +# 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 diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index cf7e62b316b..8d14017dc12 100755 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -37,16 +37,21 @@ #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 +#elif defined(XP_MACOSX) +#include "client/mac/handler/exception_handler.h" +#include +#include +#include #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." @@ -59,72 +64,93 @@ #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 +// "" "" +#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* 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) { @@ -144,51 +170,48 @@ bool MinidumpCallback(const wchar_t *dump_path, 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; -} +#elif defined(XP_UNIX) + if (!crashReporterAPIData->IsEmpty()) { + // write out API data + int fd = open(extraDataPath, + O_WRONLY | O_CREAT | O_TRUNC, + 0666); -static nsresult BuildCommandLine(const nsAString &tempPath) -{ - nsString crashReporterCmdLine_temp = - *crashReporterCmdLine_withoutDumpPath + NS_LITERAL_STRING(" \"") + tempPath; - PRInt32 cmdLineLength = crashReporterCmdLine_temp.Length(); - - // 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; @@ -203,6 +226,55 @@ static nsresult GetExecutablePath(nsString& exePath) 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) @@ -216,14 +288,11 @@ nsresult SetExceptionHandler(nsILocalFile* aXREDirectory) // 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); @@ -247,11 +316,7 @@ nsresult SetExceptionHandler(nsILocalFile* aXREDirectory) 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; @@ -263,18 +328,30 @@ nsresult SetExceptionHandler(nsILocalFile* aXREDirectory) tempPath.SetLength(pathLen); GetTempPath(pathLen, (LPWSTR)tempPath.BeginWriting()); +#elif defined(XP_MACOSX) + FSRef fsRef; + OSErr err = FSFindFolder(kUserDomain, kTemporaryFolderType, + kCreateFolder, &fsRef); + if (err != noErr) + return NS_ERROR_FAILURE; + + 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 - rv = BuildCommandLine(tempPath); - NS_ENSURE_SUCCESS(rv, rv); - // 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; @@ -287,25 +364,8 @@ nsresult SetMinidumpPath(const nsAString& aPath) if (!gExceptionHandler) return NS_ERROR_NOT_INITIALIZED; - if(crashReporterCmdLine != nsnull) { - NS_Free(crashReporterCmdLine); - crashReporterCmdLine = nsnull; - } + gExceptionHandler->set_dump_path(CONVERT_UTF16_TO_XP_CHAR(aPath).BeginReading()); - NS_NAMED_LITERAL_STRING(pathSep, PATH_SEPARATOR); - - nsresult rv; - - 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; } @@ -313,18 +373,14 @@ 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; @@ -332,18 +388,6 @@ nsresult UnsetExceptionHandler() 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; } diff --git a/toolkit/crashreporter/test/Makefile.in b/toolkit/crashreporter/test/Makefile.in index 81094e7f160..3eeca895364 100644 --- a/toolkit/crashreporter/test/Makefile.in +++ b/toolkit/crashreporter/test/Makefile.in @@ -71,9 +71,17 @@ 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)