--- a/toolkit/airbag/Makefile.in
+++ b/toolkit/airbag/Makefile.in
@@ -43,16 +43,17 @@ include $(DEPTH)/config/autoconf.mk
MODULE = airbag
LIBXUL_LIBRARY = 1
LIBRARY_NAME = airbagexception_s
REQUIRES = \
xpcom \
string \
+ xulapp \
$(NULL)
DIRS = \
$(NULL)
ifeq ($(OS_ARCH),WINNT)
DIRS += airbag/src/common/windows \
airbag/src/client/windows \
--- a/toolkit/airbag/client/Makefile.in
+++ b/toolkit/airbag/client/Makefile.in
@@ -56,11 +56,12 @@ LOCAL_INCLUDES = -I$(srcdir)/../airbag/s
ifeq ($(OS_ARCH),WINNT)
CPPSRCS = crashreporter_win.cpp
LIBS += $(DEPTH)/toolkit/airbag/airbag/src/client/windows/sender/$(LIB_PREFIX)crash_report_sender.$(LIB_SUFFIX)
LIBS += $(DEPTH)/toolkit/airbag/airbag/src/common/windows/$(LIB_PREFIX)airbag_common_s.$(LIB_SUFFIX)
LOCAL_INCLUDES += -I$(srcdir)
RCINCLUDE = crashreporter.rc
DEFINES += -DUNICODE -D_UNICODE
OS_LIBS += $(call EXPAND_LIBNAME,comctl32 shell32 wininet)
+MOZ_WINCONSOLE = 0
endif
include $(topsrcdir)/config/rules.mk
--- a/toolkit/airbag/client/crashreporter_win.cpp
+++ b/toolkit/airbag/client/crashreporter_win.cpp
@@ -40,37 +40,44 @@
#endif
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include <shellapi.h>
#include "resource.h"
#include "client/windows/sender/crash_report_sender.h"
+#include <fstream>
#define CRASH_REPORTER_KEY L"Software\\Mozilla\\Crash Reporter"
#define CRASH_REPORTER_VALUE L"Enabled"
#define WM_UPLOADCOMPLETE WM_APP
+using std::string;
using std::wstring;
using std::map;
+using std::ifstream;
bool ReadConfig();
-BOOL CALLBACK EnableDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam);
-BOOL CALLBACK SendDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK EnableDialogProc(HWND hwndDlg, UINT message, WPARAM wParam,
+ LPARAM lParam);
+BOOL CALLBACK SendDialogProc(HWND hwndDlg, UINT message, WPARAM wParam,
+ LPARAM lParam);
HANDLE CreateSendThread(HWND hDlg, LPCTSTR dumpFile);
bool CheckCrashReporterEnabled(bool* enabled);
void SetCrashReporterEnabled(bool enabled);
-bool SendCrashReport(HINSTANCE hInstance, LPCTSTR dumpFile);
+bool SendCrashReport(wstring dumpFile,
+ const map<wstring,wstring> *query_parameters);
DWORD WINAPI SendThreadProc(LPVOID param);
typedef struct {
HWND hDlg;
- LPCTSTR dumpFile;
+ wstring dumpFile;
+ const map<wstring,wstring> *query_parameters;
} SENDTHREADDATA;
TCHAR sendURL[2048] = L"\0";
bool deleteDump = true;
// Sort of a hack to get l10n
enum {
ST_OK,
@@ -94,16 +101,18 @@ LPCTSTR stringNames[] = {
L"RadioDisable",
L"SendTitle",
L"SubmitSuccess",
L"SubmitFailed"
};
LPTSTR strings[NUM_STRINGS];
+const wchar_t* kExtraDataExtension = L".extra";
+
void DoInitCommonControls()
{
INITCOMMONCONTROLSEX ic;
ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
ic.dwICC = ICC_PROGRESS_CLASS;
InitCommonControlsEx(&ic);
// also get the rich edit control
LoadLibrary(L"riched20.dll");
@@ -138,62 +147,16 @@ bool ReadConfig()
deleteDump = _wtoi(tmp) > 0;
return LoadStrings(fileName);
}
}
return false;
}
-int WINAPI WinMain(HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPSTR lpCmdLine,
- int nCmdShow)
-
-{
- bool enabled;
- LPTSTR* argv = NULL;
- int argc = 0;
-
- DoInitCommonControls();
- if (!ReadConfig()) {
- MessageBox(NULL, L"Missing crashreporter.ini file", L"Crash Reporter Error", MB_OK | MB_ICONSTOP);
- return 0;
- }
-
- argv = CommandLineToArgvW(GetCommandLine(), &argc);
-
- if (argc == 1) {
- // nothing specified, just ask about enabling
- if (!CheckCrashReporterEnabled(&enabled))
- enabled = true;
-
- enabled = (1 == DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_ENABLEDIALOG), NULL, (DLGPROC)EnableDialogProc, (LPARAM)enabled));
- SetCrashReporterEnabled(enabled);
- }
- else {
- if (!CheckCrashReporterEnabled(&enabled)) {
- //ask user if crash reporter should be enabled
- enabled = (1 == DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_ENABLEDIALOG), NULL, (DLGPROC)EnableDialogProc, (LPARAM)true));
- SetCrashReporterEnabled(enabled);
- }
- // if enabled, send crash report
- if (enabled) {
- if (SendCrashReport(hInstance, argv[1]) && deleteDump)
- DeleteFile(argv[1]);
- //TODO: show details?
- }
- }
-
- if (argv)
- LocalFree(argv);
-
- return 0;
-}
-
BOOL CALLBACK EnableDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_INITDIALOG:
SetWindowText(hwndDlg, strings[ST_CRASHREPORTERTITLE]);
SetDlgItemText(hwndDlg, IDOK, strings[ST_OK]);
SetDlgItemText(hwndDlg, IDC_RADIOENABLE, strings[ST_RADIOENABLE]);
SetDlgItemText(hwndDlg, IDC_RADIODISABLE, strings[ST_RADIODISABLE]);
@@ -281,18 +244,19 @@ BOOL CALLBACK SendDialogProc(HWND hwndDl
{
//init strings
SetWindowText(hwndDlg, strings[ST_SENDTITLE]);
SetDlgItemText(hwndDlg, IDCANCEL, strings[ST_CANCEL]);
// init progressmeter
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETPOS, 0, 0);
// now create a thread to actually do the sending
- LPCTSTR dumpFile = (LPCTSTR)lParam;
- hThread = CreateSendThread(hwndDlg, dumpFile);
+ SENDTHREADDATA* td = (SENDTHREADDATA*)lParam;
+ td->hDlg = hwndDlg;
+ CreateThread(NULL, 0, SendThreadProc, td, 0, NULL);
}
return TRUE;
case WM_UPLOADCOMPLETE:
WaitForSingleObject(hThread, INFINITE);
finishedOk = (wParam == 1);
if (finishedOk) {
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETPOS, 100, 0);
@@ -310,42 +274,160 @@ BOOL CALLBACK SendDialogProc(HWND hwndDl
}
return TRUE;
default:
return FALSE;
}
}
-bool SendCrashReport(HINSTANCE hInstance, LPCTSTR dumpFile)
+bool SendCrashReport(wstring dumpFile,
+ const map<wstring,wstring> *query_parameters)
{
- int res = (int)DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_SENDDIALOG), NULL, (DLGPROC)SendDialogProc, (LPARAM)dumpFile);
+ SENDTHREADDATA td;
+ td.hDlg = NULL;
+ td.dumpFile = dumpFile;
+ td.query_parameters = query_parameters;
+
+ int res = (int)DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_SENDDIALOG), NULL,
+ (DLGPROC)SendDialogProc, (LPARAM)&td);
+
return (res >= 0);
}
DWORD WINAPI SendThreadProc(LPVOID param)
{
bool finishedOk;
SENDTHREADDATA* td = (SENDTHREADDATA*)param;
- //XXX: send some extra params?
- map<wstring, wstring> params;
+
wstring url(sendURL);
if (url.empty()) {
finishedOk = false;
}
else {
finishedOk = google_airbag::CrashReportSender
::SendCrashReport(url,
- params,
- wstring(td->dumpFile));
+ *(td->query_parameters),
+ td->dumpFile);
}
PostMessage(td->hDlg, WM_UPLOADCOMPLETE, finishedOk ? 1 : 0, 0);
delete td;
return 0;
}
-HANDLE CreateSendThread(HWND hDlg, LPCTSTR dumpFile)
+//XXX: change this to use Breakpad's string conversion functions
+// when we update to latest SVN
+bool ConvertString(const char* utf8_string, wstring& ucs2_string)
+{
+ wchar_t *buffer = NULL;
+ int buffer_size = MultiByteToWideChar(CP_ACP, 0, utf8_string,
+ -1, NULL, 0);
+ if(buffer_size == 0)
+ return false;
+
+ buffer = new wchar_t[buffer_size];
+ if(buffer == NULL)
+ return false;
+
+ MultiByteToWideChar(CP_ACP, 0, utf8_string,
+ -1, buffer, buffer_size);
+ ucs2_string = buffer;
+ delete [] buffer;
+ return true;
+}
+
+void ReadExtraData(const wstring& filename,
+ map<wstring, wstring>& query_parameters)
+{
+#if _MSC_VER >= 1400 // MSVC 2005/8
+ ifstream file;
+ file.open(filename.c_str(), std::ios::in);
+#else // _MSC_VER >= 1400
+ ifstream file(_wfopen(filename.c_str(), L"rb"));
+#endif // _MSC_VER >= 1400
+ if (file.is_open()) {
+ do {
+ string in_line;
+ std::getline(file, in_line);
+ if (!in_line.empty()) {
+ int pos = in_line.find('=');
+ if (pos >= 0) {
+ wstring key, value;
+ ConvertString(in_line.substr(0, pos).c_str(), key);
+ ConvertString(in_line.substr(pos + 1,
+ in_line.length() - pos - 1).c_str(),
+ value);
+ query_parameters[key] = value;
+ }
+ }
+ } while(!file.eof());
+ file.close();
+ }
+}
+
+wstring GetExtraDataFilename(const wstring& dumpfile)
{
- SENDTHREADDATA* td = new SENDTHREADDATA;
- td->hDlg = hDlg;
- td->dumpFile = dumpFile;
- return CreateThread(NULL, 0, SendThreadProc, td, 0, NULL);
+ wstring filename(dumpfile);
+ int dot = filename.rfind('.');
+ if (dot < 0)
+ return L"";
+
+ filename.replace(dot, filename.length() - dot, kExtraDataExtension);
+ return filename;
}
+
+int main(int argc, char **argv)
+{
+ map<wstring,wstring> query_parameters;
+
+ DoInitCommonControls();
+ if (!ReadConfig()) {
+ MessageBox(NULL, L"Missing crashreporter.ini file", L"Crash Reporter Error", MB_OK | MB_ICONSTOP);
+ return 0;
+ }
+
+ wstring dumpfile;
+ bool enabled = false;
+
+ if (argc > 1) {
+ if (!ConvertString(argv[1], dumpfile))
+ return 0;
+ }
+
+ if (dumpfile.empty()) {
+ // no dump file specified, just ask about enabling
+ if (!CheckCrashReporterEnabled(&enabled))
+ enabled = true;
+
+ enabled = (1 == DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_ENABLEDIALOG), NULL, (DLGPROC)EnableDialogProc, (LPARAM)enabled));
+ SetCrashReporterEnabled(enabled);
+ }
+ else {
+ wstring extrafile = GetExtraDataFilename(dumpfile);
+ if (!extrafile.empty())
+ ReadExtraData(extrafile, query_parameters);
+
+ if (!CheckCrashReporterEnabled(&enabled)) {
+ //ask user if crash reporter should be enabled
+ enabled = (1 == DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_ENABLEDIALOG), NULL, (DLGPROC)EnableDialogProc, (LPARAM)true));
+ SetCrashReporterEnabled(enabled);
+ }
+ // if enabled, send crash report
+ if (enabled) {
+ if (SendCrashReport(dumpfile, &query_parameters) && deleteDump) {
+ DeleteFile(dumpfile.c_str());
+ if (!extrafile.empty())
+ DeleteFile(extrafile.c_str());
+ }
+ //TODO: show details?
+ }
+ }
+}
+
+#if defined(XP_WIN) && !defined(DEBUG) && !defined(__GNUC__)
+// We need WinMain in order to not be a console app. This function is unused
+// if we are a console application.
+int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR args, int )
+{
+ // Do the real work.
+ return main(__argc, __argv);
+}
+#endif
--- a/toolkit/airbag/nsAirbagExceptionHandler.cpp
+++ b/toolkit/airbag/nsAirbagExceptionHandler.cpp
@@ -39,120 +39,327 @@
#ifdef XP_WIN32
#ifdef WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#endif
#include "client/windows/handler/exception_handler.h"
#include <string.h>
+#else
+#error "Not yet implemented for this platform"
+#endif // 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"
-static google_airbag::ExceptionHandler* gAirbagExceptionHandler = nsnull;
+namespace CrashReporter {
+
+using std::wstring;
+
+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]);
#ifdef XP_WIN32
-static TCHAR crashReporterExe[MAX_PATH] = L"\0";
-static TCHAR minidumpPath[MAX_PATH] = L"\0";
+NS_NAMED_LITERAL_STRING(crashReporterFilename, "crashreporter.exe");
+#else
+NS_NAMED_LITERAL_STRING(crashReporterFilename, "crashreporter");
#endif
-void AirbagMinidumpCallback(const std::wstring &minidump_id,
- void *context, bool succeeded)
+static google_airbag::ExceptionHandler* gExceptionHandler = nsnull;
+
+// for ease of replacing the dump path when someone
+// calls SetMinidumpPath
+static nsString crashReporterCmdLine_withoutDumpPath;
+// 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;
+
+// this holds additional data sent via the API
+static nsCString crashReporterAPIData;
+
+static void MinidumpCallback(const wstring &minidump_id,
+ void *context, bool succeeded)
{
+ // append minidump filename to command line
+ memcpy(crashReporterCmdLineEnd, minidump_id.c_str(),
+ kGUIDLength * sizeof(PRUnichar));
+ // this will copy the null terminator as well
+ memcpy(crashReporterCmdLineEnd + kGUIDLength,
+ dumpFileExtension, sizeof(dumpFileExtension));
+
+ // append minidump filename to API data filename
+ memcpy(crashReporterAPIDataFilenameEnd, minidump_id.c_str(),
+ kGUIDLength * sizeof(PRUnichar));
+ // this will copy the null terminator as well
+ memcpy(crashReporterAPIDataFilenameEnd + kGUIDLength,
+ extraFileExtension, sizeof(extraFileExtension));
+
#ifdef XP_WIN32
+ if (!crashReporterAPIData.IsEmpty()) {
+ // write out API data
+ HANDLE hFile = CreateFile(crashReporterAPIDataFilename, 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);
+ }
+ }
+
STARTUPINFO si;
PROCESS_INFORMATION pi;
- TCHAR cmdLine[2*MAX_PATH];
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
ZeroMemory(&pi, sizeof(pi));
- wcscat(minidumpPath, minidump_id.c_str());
- wcscat(minidumpPath, L".dmp");
- wsprintf(cmdLine, L"\"%s\" \"%s\"", crashReporterExe, minidumpPath);
-
- if (CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
+ if (CreateProcess(NULL, (LPWSTR)crashReporterCmdLine, 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
}
-nsresult SetAirbagExceptionHandler()
+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;
+ }
+
+ nsString apiDataFilename_temp(tempPath);
+ PRInt32 filenameLength = apiDataFilename_temp.Length();
+ apiDataFilename_temp.SetLength(filenameLength + kMinidumpFilenameLength + 1);
+ crashReporterAPIDataFilename = ToNewUnicode(apiDataFilename_temp);
+ crashReporterAPIDataFilenameEnd =
+ crashReporterAPIDataFilename + filenameLength;
+
+ return NS_OK;
+}
+
+static nsresult GetExecutablePath(nsString& exePath)
{
- if (gAirbagExceptionHandler)
+#ifdef XP_WIN32
+ // sort of arbitrary, but MAX_PATH is kinda small
+ exePath.SetLength(4096);
+ if (!GetModuleFileName(NULL, (LPWSTR)exePath.BeginWriting(), 4096))
+ return NS_ERROR_FAILURE;
+#else
+ return NS_ERROR_NOT_IMPLEMENTED;
+#endif
+
+#ifdef XP_WIN32
+ NS_NAMED_LITERAL_STRING(pathSep, "\\");
+#else
+ NS_NAMED_LITERAL_STRING(pathSep, "/");
+#endif
+
+ PRInt32 lastSlash = exePath.RFind(pathSep);
+ if (lastSlash < 0)
+ return NS_ERROR_FAILURE;
+
+ exePath.Truncate(lastSlash + 1);
+
+ return NS_OK;
+}
+
+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");
if (airbagEnv == NULL || atoi(airbagEnv) == 0)
- return NS_OK;
+ return NS_ERROR_NOT_AVAILABLE;
+
+ // locate crashreporter executable
+ nsString exePath;
+ if (aXREDirectory) {
+ aXREDirectory->GetPath(exePath);
+ }
+ else {
+ rv = GetExecutablePath(exePath);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ // note that we enclose the exe filename in double quotes
+ crashReporterCmdLine_withoutDumpPath = NS_LITERAL_STRING("\"") +
+ exePath + crashReporterFilename + NS_LITERAL_STRING("\"");
+
+ // get temp path to use for minidump path
+ nsString tempPath;
#ifdef XP_WIN32
- //TODO: check registry to see if crash reporting is enabled
- if (!GetTempPath(MAX_PATH, minidumpPath))
+ // first figure out buffer size
+ int pathLen = GetTempPath(0, NULL);
+ if (pathLen == 0)
return NS_ERROR_FAILURE;
- std::wstring tempStr(minidumpPath);
- gAirbagExceptionHandler = new google_airbag::ExceptionHandler(tempStr,
- AirbagMinidumpCallback,
- nsnull,
- true);
- if (GetModuleFileName(NULL, crashReporterExe, MAX_PATH)) {
- // get crashreporter exe
- LPTSTR s = wcsrchr(crashReporterExe, '\\');
- if (s) {
- s++;
- wcscpy(s, L"crashreporter.exe");
- }
- }
-#else
- return NS_ERROR_NOT_IMPLEMENTED;
+ tempPath.SetLength(pathLen);
+ GetTempPath(pathLen, (LPWSTR)tempPath.BeginWriting());
#endif
- if (!gAirbagExceptionHandler)
+ rv = BuildCommandLine(tempPath);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // finally, set the exception handler
+ gExceptionHandler = new google_airbag::ExceptionHandler(
+ PromiseFlatString(tempPath).get(),
+ MinidumpCallback,
+ nsnull,
+ true);
+
+ if (!gExceptionHandler)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
-nsresult SetAirbagMinidumpPath(const nsAString* aPath)
+nsresult SetMinidumpPath(const nsAString& aPath)
{
- NS_ENSURE_ARG_POINTER(aPath);
-
- if (!gAirbagExceptionHandler)
+ if (!gExceptionHandler)
return NS_ERROR_NOT_INITIALIZED;
- std::wstring path;
+ if(crashReporterCmdLine != nsnull) {
+ NS_Free(crashReporterCmdLine);
+ crashReporterCmdLine = nsnull;
+ }
+
#ifdef XP_WIN32
- wcsncpy(minidumpPath, PromiseFlatString(*aPath).get(), MAX_PATH);
- path = std::wstring(minidumpPath);
- int l = wcslen(minidumpPath);
- if (minidumpPath[l-1] != '\\' && l < MAX_PATH - 1) {
- minidumpPath[l] = '\\';
- minidumpPath[l+1] = '\0';
+ NS_NAMED_LITERAL_STRING(pathSep, "\\");
+#else
+ NS_NAMED_LITERAL_STRING(pathSep, "/");
+#endif
+
+ nsresult rv;
+
+ if(!StringEndsWith(aPath, pathSep)) {
+ rv = BuildCommandLine(aPath + pathSep);
}
-#endif
- gAirbagExceptionHandler->set_dump_path(path);
+ else {
+ rv = BuildCommandLine(aPath);
+ }
+
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ gExceptionHandler->set_dump_path(PromiseFlatString(aPath).get());
return NS_OK;
}
-nsresult UnsetAirbagExceptionHandler()
+nsresult UnsetExceptionHandler()
{
- if (!gAirbagExceptionHandler)
+ if (!gExceptionHandler)
return NS_ERROR_NOT_INITIALIZED;
- delete gAirbagExceptionHandler;
- gAirbagExceptionHandler = nsnull;
+ 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;
+
+ str.BeginReading(start);
+ str.EndReading(end);
+
+ while (FindInReadable(character, start, end)) {
+ PRInt32 pos = end.size_backward();
+ str.Replace(pos - 1, 1, replacement);
+
+ str.BeginReading(start);
+ start.advance(pos + replacement.Length() - 1);
+ str.EndReading(end);
+ }
+}
+
+static PRBool DoFindInReadable(const nsACString& str, const nsACString& value)
+{
+ nsACString::const_iterator start, end;
+ str.BeginReading(start);
+ str.EndReading(end);
+
+ return FindInReadable(value, start, end);
+}
+
+nsresult AnnotateCrashReport(const nsACString &key, const nsACString &data)
+{
+ if (!gExceptionHandler)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ if (DoFindInReadable(key, NS_LITERAL_CSTRING("=")) ||
+ DoFindInReadable(key, NS_LITERAL_CSTRING("\n")))
+ return NS_ERROR_INVALID_ARG;
+
+ nsCString escapedData(data);
+
+ // escape backslashes
+ ReplaceChar(escapedData, NS_LITERAL_CSTRING("\\"),
+ NS_LITERAL_CSTRING("\\\\"));
+ // escape newlines
+ ReplaceChar(escapedData, NS_LITERAL_CSTRING("\n"),
+ NS_LITERAL_CSTRING("\\n"));
+
+ crashReporterAPIData.Append(key + NS_LITERAL_CSTRING("=") + escapedData +
+ NS_LITERAL_CSTRING("\n"));
+ return NS_OK;
+}
+
+} // namespace CrashReporter
--- a/toolkit/airbag/nsAirbagExceptionHandler.h
+++ b/toolkit/airbag/nsAirbagExceptionHandler.h
@@ -37,13 +37,16 @@
#ifndef nsAirbagExceptionHandler_h__
#define nsAirbagExceptionHandler_h__
#include "nscore.h"
#include "nsXPCOM.h"
#include "nsStringGlue.h"
-nsresult SetAirbagExceptionHandler();
-nsresult SetAirbagMinidumpPath(const nsAString* aPath);
-nsresult UnsetAirbagExceptionHandler();
+namespace CrashReporter {
+nsresult SetExceptionHandler(nsILocalFile* aXREDirectory);
+nsresult SetMinidumpPath(const nsAString& aPath);
+nsresult UnsetExceptionHandler();
+nsresult AnnotateCrashReport(const nsACString &key, const nsACString &data);
+}
#endif /* nsAirbagExceptionHandler_h__ */
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -2104,17 +2104,17 @@ static void MakeOrSetMinidumpPath(nsIFil
dumpD->Append(NS_LITERAL_STRING("minidumps"));
rv = dumpD->Exists(&fileExists);
if(!fileExists) {
dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700);
}
nsAutoString pathStr;
if(NS_SUCCEEDED(dumpD->GetPath(pathStr)))
- SetAirbagMinidumpPath(&pathStr);
+ CrashReporter::SetMinidumpPath(pathStr);
}
}
#endif
const nsXREAppData* gAppData = nsnull;
#if defined(XP_OS2)
// because we use early returns, we use a stack-based helper to un-set the OS2 FP handler
@@ -2200,18 +2200,32 @@ XRE_main(int argc, char* argv[], const n
NS_TIMELINE_MARK("enter main");
#ifdef DEBUG
if (PR_GetEnv("XRE_MAIN_BREAK"))
NS_BREAK();
#endif
#ifdef MOZ_AIRBAG
- //XXX: check failure?
- SetAirbagExceptionHandler();
+ if (NS_SUCCEEDED(
+ CrashReporter::SetExceptionHandler(aAppData->xreDirectory))) {
+ // pass some basic info from the app data
+ if (aAppData->vendor)
+ CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"),
+ nsDependentCString(aAppData->vendor));
+ if (aAppData->name)
+ CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductName"),
+ nsDependentCString(aAppData->name));
+ if (aAppData->version)
+ CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Version"),
+ nsDependentCString(aAppData->version));
+ if (aAppData->buildID)
+ CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BuildID"),
+ nsDependentCString(aAppData->buildID));
+ }
#endif
#ifdef XP_WIN32
// Suppress the "DLL Foo could not be found" dialog, such that if dependent
// libraries (such as GDI+) are not preset, we gracefully fail to load those
// XPCOM components, instead of being ungraceful.
UINT realMode = SetErrorMode(0);
realMode |= SEM_FAILCRITICALERRORS;
@@ -2927,14 +2941,17 @@ XRE_main(int argc, char* argv[], const n
desktopStartupEnv.Append(currentDesktopStartupID);
// Leak it with extreme prejudice!
PR_SetEnv(ToNewCString(desktopStartupEnv));
}
}
#endif
rv = LaunchChild(nativeApp, appInitiatedRestart, upgraded ? -1 : 0);
+
+ CrashReporter::UnsetExceptionHandler();
return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
}
}
+ CrashReporter::UnsetExceptionHandler();
return NS_FAILED(rv) ? 1 : 0;
}