bug 539552 - keep track of child process minidumps, offer pid based lookup API, write out .extra data in child minidump callback. r=ted,bsmedberg

--HG--
extra : transplant_source : %C2x%AA%8C%9E%FF%05%9A%9A%86aw%09L%A1%FAQ%DATG
This commit is contained in:
Chris Jones 2010-01-14 17:38:00 -05:00
parent efbc806050
commit 273e53136e
5 changed files with 155 additions and 51 deletions

View File

@ -3,22 +3,6 @@
var id;
function getExtraData() {
let appData = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
appData.QueryInterface(Ci.nsICrashReporter);
appData.QueryInterface(Ci.nsIXULAppInfo);
let r = "";
r += "ServerURL=" + appData.serverURL.spec + "\n";
r += "BuildID=" + appData.appBuildID + "\n";
r += "ProductName=" + appData.name + "\n";
r += "Vendor=" + appData.vendor + "\n";
r += "Version=" + appData.version + "\n";
r += "CrashTime=" + ((new Date()).getTime() / 1000).toFixed() + "\n";
r += "ProcessType=plugin\n";
return r;
}
function collectData() {
// HACK: crashes.js uses document.body, so we just alias it
document.body = document.getElementById('iframe-holder');
@ -40,27 +24,11 @@ function collectData() {
reportsDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0770);
let dumpFile = window.arguments[0].QueryInterface(Ci.nsIFile);
let extraFile = dumpFile.clone();
id = dumpFile.leafName.replace(/.dmp$/, "");
extraFile.leafName = id + ".extra";
dumpFile.moveTo(pendingDir, "");
let leafName = dumpFile.leafName;
id = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.dmp/(leafName)[1];
dumpFile = pendingDir.clone();
dumpFile.append(leafName);
let extraFile = pendingDir.clone();
extraFile.append(id + ".extra");
let fstream = Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(Ci.nsIFileOutputStream);
fstream.init(extraFile, -1, -1, 0);
var os = Cc["@mozilla.org/intl/converter-output-stream;1"].
createInstance(Ci.nsIConverterOutputStream);
os.init(fstream, "UTF-8", 0, 0x0000);
os.writeString(getExtraData());
os.close();
fstream.close();
extraFile.moveTo(pendingDir, "");
}
function onSubmit()

View File

@ -59,6 +59,7 @@
#include "mac_utils.h"
#elif defined(XP_LINUX)
#if defined(MOZ_IPC)
# include "client/linux/crash_generation/client_info.h"
# include "client/linux/crash_generation/crash_generation_server.h"
#endif
#include "client/linux/handler/exception_handler.h"
@ -79,16 +80,22 @@
#include <prenv.h>
#include <prio.h>
#include <prmem.h>
#include "mozilla/Mutex.h"
#include "nsDebug.h"
#include "nsCRT.h"
#include "nsILocalFile.h"
#include "nsIFileStreams.h"
#include "nsDataHashtable.h"
#include "nsInterfaceHashtable.h"
#include "prprf.h"
#if defined(MOZ_IPC)
using google_breakpad::CrashGenerationServer;
using google_breakpad::ClientInfo;
using mozilla::Mutex;
using mozilla::MutexAutoLock;
#include "nsThreadUtils.h"
#include "nsIWindowWatcher.h"
#include "nsIDOMWindow.h"
@ -173,6 +180,12 @@ static int serverSocketFd = -1;
static int clientSocketFd = -1;
static const int kMagicChildCrashReportFd = 42;
# endif
// |dumpMapLock| must protect all access to |pidToMinidump|.
static Mutex* dumpMapLock;
typedef nsInterfaceHashtable<nsUint32HashKey, nsIFile> ChildMinidumpMap;
static ChildMinidumpMap* pidToMinidump;
#endif // MOZ_IPC
static XP_CHAR*
@ -247,7 +260,8 @@ bool MinidumpCallback(const XP_CHAR* dump_path,
O_WRONLY | O_CREAT | O_TRUNC,
0600);
if (fd != -1) {
write(fd, crashTimeString, crashTimeStringLen);
ssize_t ignored = write(fd, crashTimeString, crashTimeStringLen);
(void)ignored;
close(fd);
}
#endif
@ -315,14 +329,17 @@ bool MinidumpCallback(const XP_CHAR* dump_path,
if (fd != -1) {
// not much we can do in case of error
write(fd, crashReporterAPIData->get(), crashReporterAPIData->Length());
write(fd, kCrashTimeParameter, kCrashTimeParameterLen);
write(fd, crashTimeString, crashTimeStringLen);
write(fd, "\n", 1);
ssize_t ignored = write(fd, crashReporterAPIData->get(),
crashReporterAPIData->Length());
ignored = write(fd, kCrashTimeParameter, kCrashTimeParameterLen);
ignored = write(fd, crashTimeString, crashTimeStringLen);
ignored = write(fd, "\n", 1);
if (timeSinceLastCrash != 0) {
write(fd, kTimeSinceLastCrashParameter,kTimeSinceLastCrashParameterLen);
write(fd, timeSinceLastCrashString, timeSinceLastCrashStringLen);
write(fd, "\n", 1);
ignored = write(fd, kTimeSinceLastCrashParameter,
kTimeSinceLastCrashParameterLen);
ignored = write(fd, timeSinceLastCrashString,
timeSinceLastCrashStringLen);
ignored = write(fd, "\n", 1);
}
close (fd);
}
@ -971,6 +988,37 @@ private:
nsCOMPtr<nsIFile> mDumpFile;
};
static PLDHashOperator EnumerateChildAnnotations(const nsACString& key,
nsCString entry,
void* userData)
{
// blacklist of entries from the parent process that we don't want to
// submit with the child process
static const char* kBlacklist[] = {
"FramePoisonBase",
"FramePoisonSize",
"StartupTime",
"URL"
};
static const int kBlacklistLength =
sizeof(kBlacklist) / sizeof(kBlacklist[0]);
// skip entries in the blacklist
for (int i = 0; i < kBlacklistLength; i++) {
if (key.EqualsASCII(kBlacklist[i]))
return PL_DHASH_NEXT;
}
nsIFileOutputStream* extraStream =
reinterpret_cast<nsIFileOutputStream*>(userData);
PRUint32 written;
extraStream->Write(key.BeginReading(), key.Length(), &written);
extraStream->Write("=", 1, &written);
extraStream->Write(entry.BeginReading(), entry.Length(), &written);
extraStream->Write("\n", 1, &written);
return PL_DHASH_NEXT;
}
static void
OnChildProcessDumpRequested(void* aContext,
const ClientInfo* aClientInfo,
@ -982,13 +1030,59 @@ OnChildProcessDumpRequested(void* aContext,
aFilePath)
{
nsCOMPtr<nsILocalFile> lf;
PRUint32 pid;
#ifdef XP_WIN
NS_NewLocalFile(nsDependentString(aFilePath->c_str()), PR_FALSE,
getter_AddRefs(lf));
pid = aClientInfo->pid();
#else
NS_NewNativeLocalFile(nsDependentCString(aFilePath->c_str()), PR_FALSE,
getter_AddRefs(lf));
pid = aClientInfo->pid_;
#endif
// Get an .extra file with the same base name as the .dmp file
nsCOMPtr<nsIFile> extraFile;
nsresult rv = lf->Clone(getter_AddRefs(extraFile));
if (NS_FAILED(rv))
return;
nsAutoString leafName;
rv = extraFile->GetLeafName(leafName);
if (NS_FAILED(rv))
return;
leafName.Replace(leafName.Length() - 3, 3,
NS_LITERAL_STRING("extra"));
rv = extraFile->SetLeafName(leafName);
if (NS_FAILED(rv))
return;
// Now write out the annotations to it
nsCOMPtr<nsIFileOutputStream> stream =
do_CreateInstance("@mozilla.org/network/file-output-stream;1");
rv = stream->Init(extraFile, -1, 0600, 0);
if (NS_FAILED(rv))
return;
crashReporterAPIData_Hash->EnumerateRead(EnumerateChildAnnotations,
stream.get());
// Add CrashTime to extra data
time_t crashTime = time(NULL);
char crashTimeString[32];
XP_TTOA(crashTime, crashTimeString, 10);
PRUint32 written;
stream->Write(kCrashTimeParameter, kCrashTimeParameterLen, &written);
stream->Write(crashTimeString, strlen(crashTimeString), &written);
stream->Write("\n", 1, &written);
stream->Close();
{
MutexAutoLock lock(*dumpMapLock);
pidToMinidump->Put(pid, lf);
}
nsCOMPtr<nsIRunnable> r = new SubmitCrashReport(lf);
NS_DispatchToMainThread(r);
}
@ -1039,6 +1133,11 @@ OOPInit()
if (!crashServer->Start())
NS_RUNTIMEABORT("can't start crash reporter server()");
pidToMinidump = new ChildMinidumpMap();
pidToMinidump->Init();
dumpMapLock = new Mutex("CrashReporter::dumpMapLock");
}
#if defined(XP_WIN)
@ -1122,6 +1221,16 @@ SetRemoteExceptionHandler()
#endif // XP_WIN
bool
GetMinidumpForChild(PRUint32 childPid, nsIFile** dump)
{
if (!GetEnabled())
return false;
MutexAutoLock lock(*dumpMapLock);
return pidToMinidump->Get(childPid, dump);
}
bool
UnsetRemoteExceptionHandler()
{

View File

@ -42,6 +42,8 @@
#include "nsXPCOM.h"
#include "nsStringGlue.h"
#include "nsIFile.h"
#if defined(XP_WIN32)
#ifdef WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
@ -64,16 +66,26 @@ nsresult SetupExtraData(nsILocalFile* aAppDataDirectory,
const nsACString& aBuildID);
#ifdef XP_WIN32
nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo);
// Parent-side API for children
const char* GetChildNotificationPipe();
// Child-side API
bool SetRemoteExceptionHandler(const nsACString& crashPipe);
#endif
#ifdef XP_MACOSX
nsresult AppendObjCExceptionInfoToAppNotes(void *inException);
#endif
#ifdef XP_LINUX
#ifdef MOZ_IPC
// Out-of-process crash reporter API.
// Return true iff a dump was found for |childPid|, and return the
// path in |dump|.
bool GetMinidumpForChild(PRUint32 childPid, nsIFile** dump NS_OUTPARAM);
# if defined(XP_WIN32)
// Parent-side API for children
const char* GetChildNotificationPipe();
// Child-side API
bool SetRemoteExceptionHandler(const nsACString& crashPipe);
# elif defined(XP_LINUX)
// Parent-side API for children
// Set the outparams for crash reporter server's fd (|childCrashFd|)
@ -88,9 +100,10 @@ bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd);
// Child-side API
bool SetRemoteExceptionHandler();
#endif
#endif // XP_WIN32
bool UnsetRemoteExceptionHandler();
#endif // MOZ_IPC
}
#endif /* nsExceptionHandler_h__ */

View File

@ -248,6 +248,15 @@ GeckoProcessType sChildProcessType = GeckoProcessType_Default;
static MessageLoop* sIOMessageLoop;
#if defined(MOZ_CRASHREPORTER)
// FIXME/bug 539522: this out-of-place function is stuck here because
// IPDL wants access to this crashreporter interface, and
// crashreporter is built in such a way to make that awkward
PRBool
XRE_GetMinidumpForChild(PRUint32 aChildPid, nsIFile** aDump)
{
return CrashReporter::GetMinidumpForChild(aChildPid, aDump);
}
PRBool
XRE_SetRemoteExceptionHandler(const char* aPipe/*= 0*/)
{

View File

@ -450,6 +450,11 @@ XRE_API(GeckoProcessType,
XRE_StringToChildProcessType, (const char* aProcessTypeString))
#if defined(MOZ_CRASHREPORTER)
// Used in the "master" parent process hosting the crash server
XRE_API(PRBool,
XRE_GetMinidumpForChild, (PRUint32 aChildPid, nsIFile** aDump))
// Used in child processes.
XRE_API(PRBool,
XRE_SetRemoteExceptionHandler, (const char* aPipe))
#endif