mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-03 07:01:19 +00:00
Bug 1481009 Part 5 - Generate a minidump when reporting a fatal record/replay error, r=froydnj.
--HG-- extra : rebase_source : e9f64d2fe625dbb6eb01c9868e8aab6ebc11b8f4
This commit is contained in:
parent
a4c6ff4a58
commit
71986ca9f7
@ -127,9 +127,7 @@ PassThroughThreadEventsAllowCallbacks(const std::function<void()>& aFn)
|
||||
while (true) {
|
||||
ThreadEvent ev = (ThreadEvent) thread->Events().ReadScalar();
|
||||
if (ev != ThreadEvent::ExecuteCallback) {
|
||||
if (ev != ThreadEvent::CallbacksFinished) {
|
||||
child::ReportFatalError("Unexpected event while replaying callback events");
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(ev == ThreadEvent::CallbacksFinished);
|
||||
break;
|
||||
}
|
||||
size_t id = thread->Events().ReadScalar();
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include "DirtyMemoryHandler.h"
|
||||
|
||||
#include "ipc/ChildIPC.h"
|
||||
#include "ipc/ChildInternal.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "MemorySnapshot.h"
|
||||
#include "Thread.h"
|
||||
@ -65,11 +65,15 @@ DirtyMemoryExceptionHandlerThread(void*)
|
||||
if (HandleDirtyMemoryFault(faultingAddress)) {
|
||||
replyCode = KERN_SUCCESS;
|
||||
} else {
|
||||
child::ReportFatalError("HandleDirtyMemoryFault failed %p %s", faultingAddress,
|
||||
gMozCrashReason ? gMozCrashReason : "");
|
||||
child::MinidumpInfo info(request.body.exception,
|
||||
request.body.code[0], request.body.code[1],
|
||||
request.body.thread.name);
|
||||
child::ReportFatalError(Some(info), "HandleDirtyMemoryFault failed %p %s",
|
||||
faultingAddress, gMozCrashReason ? gMozCrashReason : "");
|
||||
}
|
||||
} else {
|
||||
child::ReportFatalError("DirtyMemoryExceptionHandlerThread mach_msg returned unexpected data");
|
||||
child::ReportFatalError(Nothing(),
|
||||
"DirtyMemoryExceptionHandlerThread mach_msg returned unexpected data");
|
||||
}
|
||||
|
||||
__Reply__exception_raise_t reply;
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include "File.h"
|
||||
|
||||
#include "ipc/ChildIPC.h"
|
||||
#include "ipc/ChildInternal.h"
|
||||
#include "mozilla/Compression.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "ProcessRewind.h"
|
||||
@ -161,7 +161,8 @@ Stream::CheckInput(size_t aValue)
|
||||
size_t oldValue = aValue;
|
||||
RecordOrReplayScalar(&oldValue);
|
||||
if (oldValue != aValue) {
|
||||
child::ReportFatalError("Input Mismatch: Recorded: %zu Replayed %zu\n", oldValue, aValue);
|
||||
child::ReportFatalError(Nothing(), "Input Mismatch: Recorded: %zu Replayed %zu\n",
|
||||
oldValue, aValue);
|
||||
Unreachable();
|
||||
}
|
||||
}
|
||||
|
@ -410,7 +410,7 @@ CountdownThreadMain(void*)
|
||||
if (gMemoryInfo->mCountdown && --gMemoryInfo->mCountdown == 0) {
|
||||
// When debugging hangs in the child process, we can break here in lldb
|
||||
// to inspect what the process is doing.
|
||||
child::ReportFatalError("CountdownThread activated");
|
||||
child::ReportFatalError(Nothing(), "CountdownThread activated");
|
||||
}
|
||||
ThreadYield();
|
||||
}
|
||||
@ -665,11 +665,13 @@ HandleDirtyMemoryFault(uint8_t* aAddress)
|
||||
void
|
||||
UnrecoverableSnapshotFailure()
|
||||
{
|
||||
AutoSpinLock lock(gMemoryInfo->mTrackedRegionsLock);
|
||||
DirectUnprotectMemory(PageBase(&errno), PageSize, false);
|
||||
for (auto region : gMemoryInfo->mTrackedRegionsByAllocationOrder) {
|
||||
DirectUnprotectMemory(region.mBase, region.mSize, region.mExecutable,
|
||||
/* aIgnoreFailures = */ true);
|
||||
if (gMemoryInfo) {
|
||||
AutoSpinLock lock(gMemoryInfo->mTrackedRegionsLock);
|
||||
DirectUnprotectMemory(PageBase(&errno), PageSize, false);
|
||||
for (auto region : gMemoryInfo->mTrackedRegionsByAllocationOrder) {
|
||||
DirectUnprotectMemory(region.mBase, region.mSize, region.mExecutable,
|
||||
/* aIgnoreFailures = */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1064,14 +1066,14 @@ CheckFixedMemory(void* aAddress, size_t aSize)
|
||||
gMemoryInfo->mTrackedRegions.lookupClosestLessOrEqual(page);
|
||||
if (!region.isSome() ||
|
||||
!MemoryContains(region.ref().mBase, region.ref().mSize, page, PageSize)) {
|
||||
child::ReportFatalError("Fixed memory is not tracked!");
|
||||
MOZ_CRASH("Fixed memory is not tracked!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The memory should not be free.
|
||||
if (gFreeRegions.Intersects(aAddress, aSize)) {
|
||||
child::ReportFatalError("Fixed memory is currently free!");
|
||||
MOZ_CRASH("Fixed memory is currently free!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,9 +205,9 @@ MOZ_EXPORT void
|
||||
RecordReplayInterface_InternalInvalidateRecording(const char* aWhy)
|
||||
{
|
||||
if (IsRecording()) {
|
||||
child::ReportFatalError("Recording invalidated: %s", aWhy);
|
||||
child::ReportFatalError(Nothing(), "Recording invalidated: %s", aWhy);
|
||||
} else {
|
||||
child::ReportFatalError("Recording invalidated while replaying: %s", aWhy);
|
||||
child::ReportFatalError(Nothing(), "Recording invalidated while replaying: %s", aWhy);
|
||||
}
|
||||
Unreachable();
|
||||
}
|
||||
@ -471,7 +471,8 @@ RecordReplayInterface_InternalRecordReplayAssert(const char* aFormat, va_list aA
|
||||
SetCurrentStackString(text, text + strlen(text), sizeof(text) - strlen(text));
|
||||
}
|
||||
|
||||
child::ReportFatalError("Assertion Mismatch: Thread %d\n"
|
||||
child::ReportFatalError(Nothing(),
|
||||
"Assertion Mismatch: Thread %d\n"
|
||||
"Recorded: %s [%d,%d]\n"
|
||||
"Replayed: %s [%d,%d]\n",
|
||||
(int) thread->Id(), buffer, (int) streamPos, (int) progress, text,
|
||||
@ -547,7 +548,8 @@ RecordReplayInterface_InternalRecordReplayAssertBytes(const void* aData, size_t
|
||||
}
|
||||
}
|
||||
|
||||
child::ReportFatalError("Byte Comparison Check Failed: Position %d %d Length %d %d\n",
|
||||
child::ReportFatalError(Nothing(),
|
||||
"Byte Comparison Check Failed: Position %d %d Length %d %d\n",
|
||||
(int) streamPos, (int) thread->Events().StreamPosition(),
|
||||
(int) oldSize, (int) aSize);
|
||||
Unreachable();
|
||||
|
@ -256,7 +256,7 @@ Thread::StartThread(Callback aStart, void* aArgument, bool aNeedsJoin)
|
||||
}
|
||||
}
|
||||
if (id >= MaxRecordedThreadId) {
|
||||
child::ReportFatalError("Too many threads");
|
||||
child::ReportFatalError(Nothing(), "Too many threads");
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(id <= MaxRecordedThreadId);
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ RecordReplayInterface_ExecuteTriggers()
|
||||
ThreadEvent ev = (ThreadEvent) thread->Events().ReadScalar();
|
||||
if (ev != ThreadEvent::ExecuteTrigger) {
|
||||
if (ev != ThreadEvent::ExecuteTriggersFinished) {
|
||||
child::ReportFatalError("ExecuteTrigger Mismatch");
|
||||
child::ReportFatalError(Nothing(), "ExecuteTrigger Mismatch");
|
||||
Unreachable();
|
||||
}
|
||||
break;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "chrome/common/child_thread.h"
|
||||
#include "chrome/common/mach_ipc_mac.h"
|
||||
#include "ipc/Channel.h"
|
||||
#include "mac/handler/exception_handler.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
@ -282,7 +283,7 @@ InitRecordingOrReplayingProcess(int* aArgc, char*** aArgv)
|
||||
|
||||
// If we failed to initialize then report it to the user.
|
||||
if (gInitializationFailureMessage) {
|
||||
ReportFatalError("%s", gInitializationFailureMessage);
|
||||
ReportFatalError(Nothing(), "%s", gInitializationFailureMessage);
|
||||
Unreachable();
|
||||
}
|
||||
}
|
||||
@ -300,8 +301,21 @@ ParentProcessId()
|
||||
}
|
||||
|
||||
void
|
||||
ReportFatalError(const char* aFormat, ...)
|
||||
ReportFatalError(const Maybe<MinidumpInfo>& aMinidump, const char* aFormat, ...)
|
||||
{
|
||||
// Unprotect any memory which might be written while producing the minidump.
|
||||
UnrecoverableSnapshotFailure();
|
||||
|
||||
AutoEnsurePassThroughThreadEvents pt;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
MinidumpInfo info = aMinidump.isSome()
|
||||
? aMinidump.ref()
|
||||
: MinidumpInfo(EXC_CRASH, 1, 0, mach_thread_self());
|
||||
google_breakpad::ExceptionHandler::WriteForwardedExceptionMinidump
|
||||
(info.mExceptionType, info.mCode, info.mSubcode, info.mThread);
|
||||
#endif
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, aFormat);
|
||||
char buf[2048];
|
||||
@ -323,8 +337,6 @@ ReportFatalError(const char* aFormat, ...)
|
||||
DirectPrint(buf);
|
||||
DirectPrint("\n");
|
||||
|
||||
UnrecoverableSnapshotFailure();
|
||||
|
||||
// Block until we get a terminate message and die.
|
||||
Thread::WaitForeverNoIdle();
|
||||
}
|
||||
|
@ -60,9 +60,6 @@ void NotifyFlushedRecording();
|
||||
// Notify the middleman about an AlwaysMarkMajorCheckpoints directive.
|
||||
void NotifyAlwaysMarkMajorCheckpoints();
|
||||
|
||||
// Report a fatal error to the middleman process.
|
||||
void ReportFatalError(const char* aFormat, ...);
|
||||
|
||||
// Mark a time span when the main thread is idle.
|
||||
void BeginIdleTime();
|
||||
void EndIdleTime();
|
||||
|
@ -78,6 +78,24 @@ void HitCheckpoint(size_t aId, bool aRecordingEndpoint);
|
||||
|
||||
void HitBreakpoint(bool aRecordingEndpoint, const uint32_t* aBreakpoints, size_t aNumBreakpoints);
|
||||
|
||||
// Optional information about a crash that occurred. If not provided to
|
||||
// ReportFatalError, the current thread will be treated as crashed.
|
||||
struct MinidumpInfo
|
||||
{
|
||||
int mExceptionType;
|
||||
int mCode;
|
||||
int mSubcode;
|
||||
mach_port_t mThread;
|
||||
|
||||
MinidumpInfo(int aExceptionType, int aCode, int aSubcode, mach_port_t aThread)
|
||||
: mExceptionType(aExceptionType), mCode(aCode), mSubcode(aSubcode), mThread(aThread)
|
||||
{}
|
||||
};
|
||||
|
||||
// Generate a minidump and report a fatal error to the middleman process.
|
||||
void ReportFatalError(const Maybe<MinidumpInfo>& aMinidumpInfo,
|
||||
const char* aFormat, ...);
|
||||
|
||||
// Monitor used for various synchronization tasks.
|
||||
extern Monitor* gMonitor;
|
||||
|
||||
|
@ -92,12 +92,6 @@ NotifyAlwaysMarkMajorCheckpoints()
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
void
|
||||
ReportFatalError(const char* aFormat, ...)
|
||||
{
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
void
|
||||
BeginIdleTime()
|
||||
{
|
||||
|
@ -49,6 +49,8 @@ LOCAL_INCLUDES += [
|
||||
'!/ipc/ipdl/_ipdlheaders',
|
||||
'/ipc/chromium/src',
|
||||
'/js/xpconnect/src',
|
||||
'/toolkit/crashreporter/breakpad-client',
|
||||
'/toolkit/crashreporter/google-breakpad/src',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
Loading…
x
Reference in New Issue
Block a user