bug 389548 - cvs removing toolkit/airbag

This commit is contained in:
ted.mielczarek@gmail.com 2007-08-09 12:55:15 -07:00
parent e95c66ecef
commit 87fe4abc1e
11 changed files with 0 additions and 1638 deletions

View File

@ -1,110 +0,0 @@
# ***** 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 Airbag integration
#
# The Initial Developer of the Original Code is
# Ted Mielczarek <ted.mielczarek@gmail.com>
# Portions created by the Initial Developer are Copyright (C) 2006
# 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 = crashreporter
LIBXUL_LIBRARY = 1
LIBRARY_NAME = exception_handler_s
REQUIRES = \
xpcom \
string \
xulapp \
$(NULL)
DIRS = \
$(NULL)
ifeq ($(OS_ARCH),WINNT)
DIRS += airbag/src/common/windows \
airbag/src/client/windows \
$(NULL)
endif
ifeq ($(OS_ARCH),Darwin)
CMMSRCS = mac_utils.mm
DIRS += \
airbag/src/common \
airbag/src/common/mac \
airbag/src/client \
airbag/src/client/mac/handler \
airbag/src/tools/mac/dump_syms \
$(NULL)
endif
ifeq ($(OS_ARCH),Linux)
# there's no define for this normally
DEFINES += -DXP_LINUX
DIRS += \
airbag/src/common \
airbag/src/common/linux \
airbag/src/client \
airbag/src/client/linux/handler \
airbag/src/tools/linux/dump_syms \
$(NULL)
endif
DIRS += client
LOCAL_INCLUDES = -I$(srcdir)/airbag/src
DEFINES += -DUNICODE -D_UNICODE
XPIDLSRCS = \
nsICrashReporter.idl \
$(NULL)
EXPORTS = \
nsAirbagExceptionHandler.h \
$(NULL)
CPPSRCS = \
nsAirbagExceptionHandler.cpp \
$(NULL)
FORCE_STATIC_LIB = 1
ifdef ENABLE_TESTS
DIRS += test
endif
include $(topsrcdir)/config/rules.mk

View File

@ -1,47 +0,0 @@
/* -*- 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 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 ***** */
#ifndef toolkit_breakpad_mac_utils_h__
#define toolkit_breakpad_mac_utils_h__
/*
* Look up a setting in our user defaults indicating
* that the user wants to see the OS crash reporting dialog.
*/
bool PassToOSCrashReporter();
#endif /* toolkit_breakpad_mac_utils_h__ */

View File

@ -1,50 +0,0 @@
/* -*- 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 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 ***** */
#include <Foundation/Foundation.h>
#include "mac_utils.h"
bool PassToOSCrashReporter()
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
BOOL osCrashReporter = [userDefaults boolForKey:@"OSCrashReporter"];
[pool release];
return osCrashReporter == YES;
}

View File

@ -1,644 +0,0 @@
/* -*- 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 Airbag integration
*
* The Initial Developer of the Original Code is
* Ted Mielczarek <ted.mielczarek@gmail.com>
* Portions created by the Initial Developer are Copyright (C) 2006
* 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 ***** */
#include "nsAirbagExceptionHandler.h"
#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>
#include <sys/types.h>
#include <unistd.h>
#include "mac_utils.h"
#elif defined(XP_LINUX)
#include "client/linux/handler/exception_handler.h"
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#else
#error "Not yet implemented for this platform"
#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 <time.h>
#include <prenv.h>
#include <prio.h>
#include "nsDebug.h"
#include "nsCRT.h"
#include "nsILocalFile.h"
#include "nsDataHashtable.h"
namespace CrashReporter {
#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 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;
static XP_CHAR* crashReporterPath;
// if this is false, we don't launch the crash reporter
static bool doReport = true;
// if this is true, we pass the exception on to the OS crash reporter
static bool showOSCrashReporter = false;
// this holds additional data sent via the API
static nsDataHashtable<nsCStringHashKey,nsCString>* crashReporterAPIData_Hash;
static nsCString* crashReporterAPIData = nsnull;
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)
{
bool returnValue = showOSCrashReporter ? false : succeeded;
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);
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(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);
}
}
if (!doReport) {
return returnValue;
}
STARTUPINFO si;
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)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);
#elif defined(XP_UNIX)
if (!crashReporterAPIData->IsEmpty()) {
// write out API data
int fd = open(extraDataPath,
O_WRONLY | O_CREAT | O_TRUNC,
0666);
if (fd != -1) {
// not much we can do in case of error
write(fd, crashReporterAPIData->get(), crashReporterAPIData->Length());
close (fd);
}
}
if (!doReport) {
return returnValue;
}
pid_t pid = fork();
if (pid == -1)
return false;
else if (pid == 0) {
(void) execl(crashReporterPath,
crashReporterPath, minidumpPath, (char*)0);
_exit(1);
}
#endif
return returnValue;
}
nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
const char* aServerURL)
{
nsresult rv;
if (gExceptionHandler)
return NS_ERROR_ALREADY_INITIALIZED;
const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_DISABLE");
if (envvar && *envvar)
return NS_OK;
// this environment variable prevents us from launching
// the crash reporter client
envvar = PR_GetEnv("MOZ_CRASHREPORTER_NO_REPORT");
if (envvar && *envvar)
doReport = false;
// allocate our strings
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();
NS_ENSURE_SUCCESS(rv, rv);
// locate crashreporter executable
nsCOMPtr<nsIFile> exePath;
rv = aXREDirectory->Clone(getter_AddRefs(exePath));
NS_ENSURE_SUCCESS(rv, rv);
#if defined(XP_MACOSX)
exePath->Append(NS_LITERAL_STRING("crashreporter.app"));
exePath->Append(NS_LITERAL_STRING("Contents"));
exePath->Append(NS_LITERAL_STRING("MacOS"));
#endif
exePath->Append(NS_LITERAL_STRING(CRASH_REPORTER_FILENAME));
nsString crashReporterPath_temp;
exePath->GetPath(crashReporterPath_temp);
crashReporterPath = TO_NEW_XP_CHAR(crashReporterPath_temp);
// get temp path to use for minidump path
nsString tempPath;
#if defined(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());
#elif defined(XP_MACOSX)
FSRef fsRef;
OSErr err = FSFindFolder(kUserDomain, kTemporaryFolderType,
kCreateFolder, &fsRef);
if (err != noErr)
return NS_ERROR_FAILURE;
char path[PATH_MAX];
OSStatus status = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX);
if (status != noErr)
return NS_ERROR_FAILURE;
tempPath = NS_ConvertUTF8toUTF16(path);
#elif defined(XP_UNIX)
// we assume it's always /tmp on unix systems
tempPath = NS_LITERAL_STRING("/tmp/");
#else
//XXX: implement get temp path on other platforms
return NS_ERROR_NOT_IMPLEMENTED;
#endif
// now set the exception handler
gExceptionHandler = new google_breakpad::
ExceptionHandler(CONVERT_UTF16_TO_XP_CHAR(tempPath).get(),
nsnull,
MinidumpCallback,
nsnull,
#if defined(XP_WIN32)
google_breakpad::ExceptionHandler::HANDLER_ALL);
#else
true);
#endif
if (!gExceptionHandler)
return NS_ERROR_OUT_OF_MEMORY;
// store server URL with the API data
if (aServerURL)
AnnotateCrashReport(NS_LITERAL_CSTRING("ServerURL"),
nsDependentCString(aServerURL));
#if defined(XP_MACOSX)
// On OS X, many testers like to see the OS crash reporting dialog
// since it offers immediate stack traces. We allow them to set
// a default to pass exceptions to the OS handler.
showOSCrashReporter = PassToOSCrashReporter();
#endif
return NS_OK;
}
nsresult SetMinidumpPath(const nsAString& aPath)
{
if (!gExceptionHandler)
return NS_ERROR_NOT_INITIALIZED;
gExceptionHandler->set_dump_path(CONVERT_UTF16_TO_XP_CHAR(aPath).BeginReading());
return NS_OK;
}
static nsresult
WriteDataToFile(nsIFile* aFile, const nsACString& data)
{
nsCAutoString filename;
nsresult rv = aFile->GetNativePath(filename);
NS_ENSURE_SUCCESS(rv, rv);
PRFileDesc* fd = PR_Open(filename.get(), PR_WRONLY | PR_CREATE_FILE, 00600);
NS_ENSURE_TRUE(fd, NS_ERROR_FAILURE);
rv = NS_OK;
if (PR_Write(fd, data.Data(), data.Length()) == -1) {
rv = NS_ERROR_FAILURE;
}
PR_Close(fd);
return rv;
}
static nsresult
GetFileContents(nsIFile* aFile, nsACString& data)
{
nsCAutoString filename;
nsresult rv = aFile->GetNativePath(filename);
NS_ENSURE_SUCCESS(rv, rv);
PRFileDesc* fd = PR_Open(filename.get(), PR_RDONLY, 0);
NS_ENSURE_TRUE(fd, NS_ERROR_FILE_NOT_FOUND);
rv = NS_OK;
PRInt32 filesize = PR_Available(fd);
if (filesize <= 0) {
rv = NS_ERROR_FILE_NOT_FOUND;
}
else {
data.SetLength(filesize);
if (PR_Read(fd, data.BeginWriting(), filesize) == -1) {
rv = NS_ERROR_FAILURE;
}
}
PR_Close(fd);
return rv;
}
// Function typedef for initializing a piece of data that we
// don't already have.
typedef nsresult (*InitDataFunc)(nsACString&);
// Attempt to read aFile's contents into aContents, if aFile
// does not exist, create it and initialize its contents
// by calling aInitFunc for the data.
static nsresult
GetOrInit(nsILocalFile* aDir, const nsAString& filename,
nsACString& aContents, InitDataFunc aInitFunc)
{
PRBool exists;
nsCOMPtr<nsIFile> dataFile;
nsresult rv = aDir->Clone(getter_AddRefs(dataFile));
NS_ENSURE_SUCCESS(rv, rv);
rv = dataFile->Append(filename);
NS_ENSURE_SUCCESS(rv, rv);
rv = dataFile->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (!exists) {
// get the initial value and write it to the file
rv = aInitFunc(aContents);
NS_ENSURE_SUCCESS(rv, rv);
rv = WriteDataToFile(dataFile, aContents);
}
else {
// just get the file's contents
rv = GetFileContents(dataFile, aContents);
}
return rv;
}
// Generate a unique user ID. We're using a GUID form,
// but not jumping through hoops to make it cryptographically
// secure. We just want it to distinguish unique users.
static nsresult
InitUserID(nsACString& aUserID)
{
nsID id;
// copied shamelessly from nsUUIDGenerator.cpp
#if defined(XP_WIN)
HRESULT hr = CoCreateGuid((GUID*)&id);
if (NS_FAILED(hr))
return NS_ERROR_FAILURE;
#elif defined(XP_MACOSX)
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
if (!uuid)
return NS_ERROR_FAILURE;
CFUUIDBytes bytes = CFUUIDGetUUIDBytes(uuid);
memcpy(&id, &bytes, sizeof(nsID));
CFRelease(uuid);
#else
// UNIX or some such thing
id.m0 = random();
id.m1 = random();
id.m2 = random();
*reinterpret_cast<PRUint32*>(&id.m3[0]) = random();
*reinterpret_cast<PRUint32*>(&id.m3[4]) = random();
#endif
nsCAutoString id_str(id.ToString());
aUserID = Substring(id_str, 1, id_str.Length()-2);
return NS_OK;
}
// Init the "install time" data. We're taking an easy way out here
// and just setting this to "the time when this version was first run".
static nsresult
InitInstallTime(nsACString& aInstallTime)
{
time_t t = time(NULL);
char buf[16];
sprintf(buf, "%ld", t);
aInstallTime = buf;
return NS_OK;
}
// Annotate the crash report with a Unique User ID.
// TODO: also add time since install, and time since last crash.
// (bug 376720 and bug 376721)
// If any piece of data doesn't exist, initialize it first.
nsresult SetupExtraData(nsILocalFile* aAppDataDirectory,
const nsACString& aBuildID)
{
nsresult rv = aAppDataDirectory->Append(NS_LITERAL_STRING("Crash Reports"));
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString data;
if(NS_SUCCEEDED(GetOrInit(aAppDataDirectory, NS_LITERAL_STRING("UserID"),
data, InitUserID)))
AnnotateCrashReport(NS_LITERAL_CSTRING("UserID"), data);
if(NS_SUCCEEDED(GetOrInit(aAppDataDirectory,
NS_LITERAL_STRING("InstallTime") +
NS_ConvertASCIItoUTF16(aBuildID),
data, InitInstallTime)))
AnnotateCrashReport(NS_LITERAL_CSTRING("InstallTime"), data);
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 (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;
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);
}
static PLDHashOperator PR_CALLBACK EnumerateEntries(const nsACString& key,
nsCString entry,
void* userData)
{
crashReporterAPIData->Append(key + NS_LITERAL_CSTRING("=") + entry +
NS_LITERAL_CSTRING("\n"));
return PL_DHASH_NEXT;
}
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;
if (DoFindInReadable(data, NS_LITERAL_CSTRING("\0")))
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"));
nsresult rv = crashReporterAPIData_Hash->Put(key, escapedData);
NS_ENSURE_SUCCESS(rv, rv);
// now rebuild the file contents
crashReporterAPIData->Truncate(0);
crashReporterAPIData_Hash->EnumerateRead(EnumerateEntries,
crashReporterAPIData);
return NS_OK;
}
nsresult
SetRestartArgs(int argc, char **argv)
{
if (!gExceptionHandler)
return NS_OK;
int i;
nsCAutoString envVar;
char *env;
for (i = 0; i < argc; i++) {
envVar = "MOZ_CRASHREPORTER_RESTART_ARG_";
envVar.AppendInt(i);
envVar += "=";
envVar += argv[i];
// PR_SetEnv() wants the string to be available for the lifetime
// of the app, so dup it here
env = ToNewCString(envVar);
if (!env)
return NS_ERROR_OUT_OF_MEMORY;
PR_SetEnv(env);
}
// make sure the arg list is terminated
envVar = "MOZ_CRASHREPORTER_RESTART_ARG_";
envVar.AppendInt(i);
envVar += "=";
// PR_SetEnv() wants the string to be available for the lifetime
// of the app, so dup it here
env = ToNewCString(envVar);
if (!env)
return NS_ERROR_OUT_OF_MEMORY;
PR_SetEnv(env);
// make sure we save the info in XUL_APP_FILE for the reporter
const char *appfile = PR_GetEnv("XUL_APP_FILE");
if (appfile && *appfile) {
envVar = "MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE=";
envVar += appfile;
env = ToNewCString(envVar);
PR_SetEnv(env);
}
return NS_OK;
}
} // namespace CrashReporter

View File

@ -1,56 +0,0 @@
/* -*- 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 Airbag integration
*
* The Initial Developer of the Original Code is
* Ted Mielczarek <ted.mielczarek@gmail.com>
* Portions created by the Initial Developer are Copyright (C) 2006
* 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 ***** */
#ifndef nsAirbagExceptionHandler_h__
#define nsAirbagExceptionHandler_h__
#include "nscore.h"
#include "nsXPCOM.h"
#include "nsStringGlue.h"
namespace CrashReporter {
nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
const char* aServerURL);
nsresult SetMinidumpPath(const nsAString& aPath);
nsresult UnsetExceptionHandler();
nsresult AnnotateCrashReport(const nsACString &key, const nsACString &data);
nsresult SetRestartArgs(int argc, char **argv);
nsresult SetupExtraData(nsILocalFile* aAppDataDirectory,
const nsACString& aBuildID);
}
#endif /* nsAirbagExceptionHandler_h__ */

View File

@ -1,62 +0,0 @@
/* ***** 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 ***** */
#include "nsISupports.idl"
/**
* Provides access to crash reporting functionality.
* @status UNSTABLE - This interface is not frozen and will probably change in
* future releases.
*/
[scriptable, uuid(da7020ad-fad4-443e-b02b-c5cc9d482e2f)]
interface nsICrashReporter : nsISupports
{
/**
* Add some extra data to be submitted with a crash report.
* @param key
* Name of the data to be added.
* @param data
* Data to be added.
*
* @throw NS_ERROR_NOT_INITIALIZED if crash reporting not initialized
* @throw NS_ERROR_INVALID_ARG if key or data contain invalid characters.
* Invalid characters for key are '=' and
* '\n'. Invalid character for data is '\0'.
*/
void annotateCrashReport(in ACString key, in ACString data);
};

View File

@ -1,100 +0,0 @@
#
# ***** 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 of 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
ifndef MOZ_ENABLE_LIBXUL
PROGRAM = TestCrashReporterAPI$(BIN_SUFFIX)
CPPSRCS = TestCrashReporterAPI.cpp
endif
REQUIRES = \
xpcom \
string \
crashreporter \
$(NULL)
LIBS = \
$(EXTRA_DSO_LIBS) \
$(XPCOM_GLUE_LDOPTS) \
$(XPCOM_LIBS) \
$(NSPR_LIBS) \
$(DEPTH)/toolkit/airbag/$(LIB_PREFIX)exception_handler_s.$(LIB_SUFFIX) \
$(NULL)
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
ifeq ($(OS_ARCH),Darwin)
OS_LIBS += -framework Cocoa -lcrypto
LIBS += \
$(DEPTH)/toolkit/airbag/airbag/src/client/$(LIB_PREFIX)minidump_file_writer_s.$(LIB_SUFFIX) \
$(DEPTH)/toolkit/airbag/airbag/src/client/mac/handler/$(LIB_PREFIX)exception_handler_s.$(LIB_SUFFIX) \
$(DEPTH)/toolkit/airbag/airbag/src/common/$(LIB_PREFIX)breakpad_common_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
ifeq ($(OS_ARCH),Linux)
LIBS += \
$(DEPTH)/toolkit/airbag/airbag/src/client/linux/handler/$(LIB_PREFIX)exception_handler_s.$(LIB_SUFFIX) \
$(DEPTH)/toolkit/airbag/airbag/src/client/$(LIB_PREFIX)minidump_file_writer_s.$(LIB_SUFFIX) \
$(DEPTH)/toolkit/airbag/airbag/src/common/$(LIB_PREFIX)breakpad_common_s.$(LIB_SUFFIX) \
$(DEPTH)/toolkit/airbag/airbag/src/common/linux/$(LIB_PREFIX)breakpad_linux_common_s.$(LIB_SUFFIX) \
$(NULL)
endif
ifndef MOZ_ENABLE_LIBXUL
check:: $(PROGRAM)
$(RUN_TEST_PROGRAM) $(DIST)/bin/TestCrashReporterAPI
endif

View File

@ -1,166 +0,0 @@
/* -*- 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 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 ***** */
#include <stdlib.h>
#include <stdio.h>
#include "prenv.h"
#include "nsIComponentManager.h"
#include "nsISimpleEnumerator.h"
#include "nsIServiceManager.h"
#include "nsServiceManagerUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsIProperties.h"
#include "nsCOMPtr.h"
#include "nsILocalFile.h"
#include "nsAirbagExceptionHandler.h"
#include "nsICrashReporter.h"
#define mu_assert(message, test) do { if (NS_FAILED(test)) \
return message; } while (0)
#define mu_assert_failure(message, test) do { if (NS_SUCCEEDED(test)) \
return message; } while (0)
#define mu_run_test(test) do { char *message = test(); tests_run++; \
if (message) return message; } while (0)
int tests_run;
char *
test_init_exception_handler()
{
nsCOMPtr<nsILocalFile> lf;
// we don't plan on launching the crash reporter in this app anyway,
// so it's ok to pass a bogus nsILocalFile
mu_assert("NS_NewNativeLocalFile", NS_NewNativeLocalFile(EmptyCString(),
PR_TRUE,
getter_AddRefs(lf)));
mu_assert("CrashReporter::SetExceptionHandler",
CrashReporter::SetExceptionHandler(lf, nsnull));
return 0;
}
char *
test_set_minidump_path()
{
nsresult rv;
nsCOMPtr<nsIProperties> directoryService =
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
mu_assert("do_GetService", rv);
nsCOMPtr<nsILocalFile> currentDirectory;
rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
NS_GET_IID(nsILocalFile),
getter_AddRefs(currentDirectory));
mu_assert("directoryService->Get", rv);
nsAutoString currentDirectoryPath;
rv = currentDirectory->GetPath(currentDirectoryPath);
mu_assert("currentDirectory->GetPath", rv);
mu_assert("CrashReporter::SetMinidumpPath",
CrashReporter::SetMinidumpPath(currentDirectoryPath));
return 0;
}
char *
test_annotate_crash_report_basic()
{
mu_assert("CrashReporter::AnnotateCrashReport: basic",
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("test"),
NS_LITERAL_CSTRING("some data")));
return 0;
}
char *
test_annotate_crash_report_invalid_equals()
{
mu_assert_failure("CrashReporter::AnnotateCrashReport: invalid = in key",
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("test=something"),
NS_LITERAL_CSTRING("some data")));
return 0;
}
char *
test_annotate_crash_report_invalid_cr()
{
mu_assert_failure("CrashReporter::AnnotateCrashReport: invalid \n in key",
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("test\nsomething"),
NS_LITERAL_CSTRING("some data")));
return 0;
}
char *
test_unset_exception_handler()
{
mu_assert("CrashReporter::UnsetExceptionHandler",
CrashReporter::UnsetExceptionHandler());
return 0;
}
static char* all_tests()
{
mu_run_test(test_init_exception_handler);
mu_run_test(test_set_minidump_path);
mu_run_test(test_annotate_crash_report_basic);
mu_run_test(test_annotate_crash_report_invalid_equals);
mu_run_test(test_annotate_crash_report_invalid_cr);
mu_run_test(test_unset_exception_handler);
return 0;
}
int
main (int argc, char **argv)
{
NS_InitXPCOM2(nsnull, nsnull, nsnull);
PR_SetEnv("MOZ_CRASHREPORTER=1");
char* result = all_tests();
if (result != 0) {
printf("FAIL: %s\n", result);
}
else {
printf("ALL TESTS PASSED\n");
}
printf("Tests run: %d\n", tests_run);
return result != 0;
}

View File

@ -1,341 +0,0 @@
#!/bin/env python
# ***** 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.org code.
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Ted Mielczarek <ted.mielczarek@gmail.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 *****
#
# Usage: symbolstore.py <params> <dump_syms path> <symbol store path>
# <debug info files or dirs>
# Runs dump_syms on each debug info file specified on the command line,
# then places the resulting symbol file in the proper directory
# structure in the symbol store path. Accepts multiple files
# on the command line, so can be called as part of a pipe using
# find <dir> | xargs symbolstore.pl <dump_syms> <storepath>
# But really, you might just want to pass it <dir>.
#
# Parameters accepted:
# -c : Copy debug info files to the same directory structure
# as sym files
# -a "<archs>" : Run dump_syms -a <arch> for each space separated
# cpu architecture in <archs> (only on OS X)
# -s <srcdir> : Use <srcdir> as the top source directory to
# generate relative filenames.
import sys
import os
import re
import shutil
from optparse import OptionParser
# Utility functions
def GetCVSRevision(file):
"""Given a full path to a file, look in CVS/Entries
for the CVS revision number"""
(path, filename) = os.path.split(file)
entries = os.path.join(path, "CVS", "Entries")
if not os.path.isfile(entries):
return None
f = open(entries, "r")
for line in f:
parts = line.split("/")
if len(parts) > 1 and parts[1] == filename:
return parts[2]
print >> sys.stderr, "Failed to get CVS Revision for %s" % filename
return None
def GetCVSRoot(file):
"""Given a full path to a file, look in CVS/Root
for the CVS Root"""
(path, filename) = os.path.split(file)
root = os.path.join(path, "CVS", "Root")
if not os.path.isfile(root):
return None
f = open(root, "r")
root_name = f.readline().strip()
f.close()
parts = root_name.split("@")
if len(parts) > 1:
# we don't want the extra colon
return parts[1].replace(":","")
print >> sys.stderr, "Failed to get CVS Root for %s" % filename
return None
def GetVCSFilename(file, srcdir):
"""Given a full path to a file, and the top source directory,
look for version control information about this file, and return
a specially formatted filename that contains the VCS type,
VCS location, relative filename, and revision number, formatted like:
vcs:vcs location:filename:revision
For example:
cvs:cvs.mozilla.org/cvsroot:mozilla/browser/app/nsBrowserApp.cpp:1.36"""
(path, filename) = os.path.split(file)
if path == '' or filename == '':
return file
cvsdir = os.path.join(path, "CVS")
if os.path.isdir(cvsdir):
rev = GetCVSRevision(file)
root = GetCVSRoot(file)
if rev is not None and root is not None:
if srcdir is not None:
# strip the base path off
# but we actually want the last dir in srcdir
# also, we want forward slashes on win32 paths
file = os.path.normpath(file)
file = file.replace(srcdir, "", 1)
(head, tail) = os.path.split(srcdir)
if tail == "":
tail = os.path.basename(head)
file = tail + file
file = file.replace("\\", "/")
return "cvs:%s:%s:%s" % (root, file, rev)
file = file.replace("\\", "/")
return file
def GetPlatformSpecificDumper(**kwargs):
"""This function simply returns a instance of a subclass of Dumper
that is appropriate for the current platform."""
return {'win32': Dumper_Win32,
'cygwin': Dumper_Win32,
'linux2': Dumper_Linux,
'darwin': Dumper_Mac}[sys.platform](**kwargs)
class Dumper:
"""This class can dump symbols from a file with debug info, and
store the output in a directory structure that is valid for use as
a Breakpad symbol server. Requires a path to a dump_syms binary--
|dump_syms| and a directory to store symbols in--|symbol_path|.
Optionally takes a list of processor architectures to process from
each debug file--|archs|, the full path to the top source
directory--|srcdir|, for generating relative source file names,
and an option to copy debug info files alongside the dumped
symbol files--|copy_debug|, mostly useful for creating a
Microsoft Symbol Server from the resulting output.
You don't want to use this directly if you intend to call
ProcessDir. Instead, call GetPlatformSpecificDumper to
get an instance of a subclass."""
def __init__(self, dump_syms, symbol_path,
archs=None, srcdir=None, copy_debug=False, vcsinfo=False):
self.dump_syms = dump_syms
self.symbol_path = symbol_path
if archs is None:
# makes the loop logic simpler
self.archs = ['']
else:
self.archs = ['-a %s' % a for a in archs.split()]
if srcdir is not None:
self.srcdir = os.path.normpath(srcdir)
else:
self.srcdir = None
self.copy_debug = copy_debug
self.vcsinfo = vcsinfo
# subclasses override this
def ShouldProcess(self, file):
return False
def RunFileCommand(self, file):
"""Utility function, returns the output of file(1)"""
try:
# we use -L to read the targets of symlinks,
# and -b to print just the content, not the filename
return os.popen("file -Lb " + file).read()
except:
return ""
# This is a no-op except on Win32
def FixFilenameCase(self, file):
return file
def Process(self, file_or_dir):
"Process a file or all the (valid) files in a directory."
if os.path.isdir(file_or_dir):
return self.ProcessDir(file_or_dir)
elif os.path.isfile(file_or_dir):
return self.ProcessFile(file_or_dir)
# maybe it doesn't exist?
return False
def ProcessDir(self, dir):
"""Process all the valid files in this directory. Valid files
are determined by calling ShouldProcess."""
result = True
for root, dirs, files in os.walk(dir):
for f in files:
fullpath = os.path.join(root, f)
if self.ShouldProcess(fullpath):
if not self.ProcessFile(fullpath):
result = False
return result
def ProcessFile(self, file):
"""Dump symbols from this file into a symbol file, stored
in the proper directory structure in |symbol_path|."""
result = False
for arch in self.archs:
try:
cmd = os.popen("%s %s %s" % (self.dump_syms, arch, file), "r")
module_line = cmd.next()
if module_line.startswith("MODULE"):
# MODULE os cpu guid debug_file
(guid, debug_file) = (module_line.split())[3:5]
# strip off .pdb extensions, and append .sym
sym_file = re.sub("\.pdb$", "", debug_file) + ".sym"
# we do want forward slashes here
rel_path = os.path.join(debug_file,
guid,
sym_file).replace("\\", "/")
full_path = os.path.normpath(os.path.join(self.symbol_path,
rel_path))
try:
os.makedirs(os.path.dirname(full_path))
except OSError: # already exists
pass
f = open(full_path, "w")
f.write(module_line)
# now process the rest of the output
for line in cmd:
if line.startswith("FILE"):
# FILE index filename
(x, index, filename) = line.split(None, 2)
filename = self.FixFilenameCase(filename.rstrip())
if self.vcsinfo:
filename = GetVCSFilename(filename, self.srcdir)
f.write("FILE %s %s\n" % (index, filename))
else:
# pass through all other lines unchanged
f.write(line)
f.close()
cmd.close()
# we output relative paths so callers can get a list of what
# was generated
print rel_path
if self.copy_debug:
rel_path = os.path.join(debug_file,
guid,
debug_file).replace("\\", "/")
print rel_path
full_path = os.path.normpath(os.path.join(self.symbol_path,
rel_path))
shutil.copyfile(file, full_path)
result = True
except StopIteration:
pass
except:
print >> sys.stderr, "Unexpected error: ", sys.exc_info()[0]
raise
return result
# Platform-specific subclasses. For the most part, these just have
# logic to determine what files to extract symbols from.
class Dumper_Win32(Dumper):
def ShouldProcess(self, file):
"""This function will allow processing of pdb files that have dll
or exe files with the same base name next to them."""
if file.endswith(".pdb"):
(path,ext) = os.path.splitext(file)
if os.path.isfile(path + ".exe") or os.path.isfile(path + ".dll"):
return True
return False
def FixFilenameCase(self, file):
"""Recent versions of Visual C++ put filenames into
PDB files as all lowercase. If the file exists
on the local filesystem, fix it."""
(path, filename) = os.path.split(file)
if not os.path.isdir(path):
return file
lc_filename = filename.lower()
for f in os.listdir(path):
if f.lower() == lc_filename:
return os.path.join(path, f)
return file
class Dumper_Linux(Dumper):
def ShouldProcess(self, file):
"""This function will allow processing of files that are
executable, or end with the .so extension, and additionally
file(1) reports as being ELF files. It expects to find the file
command in PATH."""
if file.endswith(".so") or os.access(file, os.X_OK):
return self.RunFileCommand(file).startswith("ELF")
return False
class Dumper_Mac(Dumper):
def ShouldProcess(self, file):
"""This function will allow processing of files that are
executable, or end with the .dylib extension, and additionally
file(1) reports as being Mach-O files. It expects to find the file
command in PATH."""
if file.endswith(".dylib") or os.access(file, os.X_OK):
return self.RunFileCommand(file).startswith("Mach-O")
return False
# Entry point if called as a standalone program
def main():
parser = OptionParser(usage="usage: %prog [options] <dump_syms binary> <symbol store path> <debug info files>")
parser.add_option("-c", "--copy",
action="store_true", dest="copy_debug", default=False,
help="Copy debug info files into the same directory structure as symbol files")
parser.add_option("-a", "--archs",
action="store", dest="archs",
help="Run dump_syms -a <arch> for each space separated cpu architecture in ARCHS (only on OS X)")
parser.add_option("-s", "--srcdir",
action="store", dest="srcdir",
help="Use SRCDIR to determine relative paths to source files")
parser.add_option("-v", "--vcs-info",
action="store_true", dest="vcsinfo",
help="Try to retrieve VCS info for each FILE listed in the output")
(options, args) = parser.parse_args()
if len(args) < 3:
parser.error("not enough arguments")
exit(1)
dumper = GetPlatformSpecificDumper(dump_syms=args[0],
symbol_path=args[1],
copy_debug=options.copy_debug,
archs=options.archs,
srcdir=options.srcdir,
vcsinfo=options.vcsinfo)
for arg in args[2:]:
dumper.Process(arg)
# run main if run directly
if __name__ == "__main__":
main()

View File

@ -1,62 +0,0 @@
#!/bin/bash
#
# ***** 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.org code.
#
# The Initial Developer of the Original Code is
# Ted Mielczarek <ted.mielczarek@gmail.com>
# Portions created by the Initial Developer are Copyright (C) 2006
# 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 *****
#
# This script expects the following environment variables to be set:
# SYMBOL_SERVER_HOST : host to upload symbols to
# SYMBOL_SERVER_USER : username on that host
# SYMBOL_SERVER_PATH : path on that host to put symbols in
#
# And will use the following optional environment variable if set:
# SYMBOL_SERVER_SSH_KEY : path to a ssh private key to use
#
set -e
: ${SYMBOL_SERVER_HOST?} ${SYMBOL_SERVER_USER?} ${SYMBOL_SERVER_PATH?} ${1?"You must specify a symbol archive to upload"}
archive=`basename $1`
echo "Transferring symbols... $1"
scp -v ${SYMBOL_SERVER_SSH_KEY:+-i $SYMBOL_SERVER_SSH_KEY} $1 \
${SYMBOL_SERVER_USER}@${SYMBOL_SERVER_HOST}:${SYMBOL_SERVER_PATH}/
echo "Unpacking symbols on remote host..."
ssh -2 ${SYMBOL_SERVER_SSH_KEY:+-i $SYMBOL_SERVER_SSH_KEY} \
-l ${SYMBOL_SERVER_USER} ${SYMBOL_SERVER_HOST} \
"set -e;
umask 0022;
cd ${SYMBOL_SERVER_PATH};
unzip -o $archive;
rm -v $archive;"
echo "Symbol transfer completed"