mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
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:
parent
efbc806050
commit
273e53136e
@ -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()
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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__ */
|
||||
|
@ -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*/)
|
||||
{
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user