--- a/mozglue/misc/StackWalk.cpp
+++ b/mozglue/misc/StackWalk.cpp
@@ -90,17 +90,16 @@ struct WalkStackData
uint32_t pc_count;
uint32_t pc_max;
void** sps;
uint32_t sp_size;
uint32_t sp_count;
CONTEXT* context;
};
-DWORD gStackWalkThread;
CRITICAL_SECTION gDbgHelpCS;
#ifdef _M_AMD64
// Because various Win64 APIs acquire function-table locks, we need a way of
// preventing stack walking while those APIs are being called. Otherwise, the
// stack walker may suspend a thread holding such a lock, and deadlock when the
// stack unwind code attempts to wait for that lock.
//
@@ -184,85 +183,29 @@ InitializeDbgHelpCriticalSection()
static bool initialized = false;
if (initialized) {
return;
}
::InitializeCriticalSection(&gDbgHelpCS);
initialized = true;
}
-static unsigned int WINAPI WalkStackThread(void* aData);
-
-static bool
-EnsureWalkThreadReady()
-{
- static bool walkThreadReady = false;
- static HANDLE stackWalkThread = nullptr;
- static HANDLE readyEvent = nullptr;
-
- if (walkThreadReady) {
- return walkThreadReady;
- }
-
- if (!stackWalkThread) {
- readyEvent = ::CreateEvent(nullptr, FALSE /* auto-reset*/,
- FALSE /* initially non-signaled */,
- nullptr);
- if (!readyEvent) {
- PrintError("CreateEvent");
- return false;
- }
-
- unsigned int threadID;
- stackWalkThread = (HANDLE)_beginthreadex(nullptr, 0, WalkStackThread,
- (void*)readyEvent, 0, &threadID);
- if (!stackWalkThread) {
- PrintError("CreateThread");
- ::CloseHandle(readyEvent);
- readyEvent = nullptr;
- return false;
- }
- gStackWalkThread = threadID;
- ::CloseHandle(stackWalkThread);
- }
-
- MOZ_ASSERT((stackWalkThread && readyEvent) ||
- (!stackWalkThread && !readyEvent));
-
- // The thread was created. Try to wait an arbitrary amount of time (1 second
- // should be enough) for its event loop to start before posting events to it.
- DWORD waitRet = ::WaitForSingleObject(readyEvent, 1000);
- if (waitRet == WAIT_TIMEOUT) {
- // We get a timeout if we're called during static initialization because
- // the thread will only start executing after we return so it couldn't
- // have signalled the event. If that is the case, give up for now and
- // try again next time we're called.
- return false;
- }
- ::CloseHandle(readyEvent);
- stackWalkThread = nullptr;
- readyEvent = nullptr;
-
- return walkThreadReady = true;
-}
-
static void
WalkStackMain64(struct WalkStackData* aData)
{
// Get a context for the specified thread.
CONTEXT context_buf;
CONTEXT* context;
if (!aData->context) {
context = &context_buf;
memset(context, 0, sizeof(CONTEXT));
context->ContextFlags = CONTEXT_FULL;
- if (!GetThreadContext(aData->thread, context)) {
- if (aData->walkCallingThread) {
- PrintError("GetThreadContext");
- }
+ if (aData->walkCallingThread) {
+ ::RtlCaptureContext(context);
+ } else if (!GetThreadContext(aData->thread, context)) {
return;
}
} else {
context = aData->context;
}
#if defined(_M_IX86) || defined(_M_IA64)
// Setup initial stack frame to walk from.
@@ -423,95 +366,35 @@ WalkStackMain64(struct WalkStackData* aD
#if defined(_M_IX86) || defined(_M_IA64)
if (frame64.AddrReturn.Offset == 0) {
break;
}
#endif
}
}
-static unsigned int WINAPI
-WalkStackThread(void* aData)
-{
- BOOL msgRet;
- MSG msg;
-
- // Call PeekMessage to force creation of a message queue so that
- // other threads can safely post events to us.
- ::PeekMessage(&msg, nullptr, WM_USER, WM_USER, PM_NOREMOVE);
-
- // and tell the thread that created us that we're ready.
- HANDLE readyEvent = (HANDLE)aData;
- ::SetEvent(readyEvent);
-
- while ((msgRet = ::GetMessage(&msg, (HWND)-1, 0, 0)) != 0) {
- if (msgRet == -1) {
- PrintError("GetMessage");
- } else {
- DWORD ret;
-
- struct WalkStackData* data = (WalkStackData*)msg.lParam;
- if (!data) {
- continue;
- }
-
- // Don't suspend the calling thread until it's waiting for
- // us; otherwise the number of frames on the stack could vary.
- ret = ::WaitForSingleObject(data->eventStart, INFINITE);
- if (ret != WAIT_OBJECT_0) {
- PrintError("WaitForSingleObject");
- }
-
- // Suspend the calling thread, dump his stack, and then resume him.
- // He's currently waiting for us to finish so now should be a good time.
- ret = ::SuspendThread(data->thread);
- if (ret == (DWORD)-1) {
- PrintError("ThreadSuspend");
- } else {
- WalkStackMain64(data);
-
- ret = ::ResumeThread(data->thread);
- if (ret == (DWORD)-1) {
- PrintError("ThreadResume");
- }
- }
-
- ::SetEvent(data->eventEnd);
- }
- }
-
- return 0;
-}
-
/**
* Walk the stack, translating PC's found into strings and recording the
* chain in aBuffer. For this to work properly, the DLLs must be rebased
* so that the address in the file agrees with the address in memory.
* Otherwise StackWalk will return FALSE when it hits a frame in a DLL
* whose in memory address doesn't match its in-file address.
*/
MFBT_API void
MozStackWalkThread(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
uint32_t aMaxFrames, void* aClosure,
HANDLE aThread, CONTEXT* aContext)
{
static HANDLE myProcess = nullptr;
HANDLE myThread;
- DWORD walkerReturn;
struct WalkStackData data;
InitializeDbgHelpCriticalSection();
- // EnsureWalkThreadReady's _beginthreadex takes a heap lock and must be
- // avoided if we're walking another (i.e. suspended) thread.
- if (!aThread && !EnsureWalkThreadReady()) {
- return;
- }
-
HANDLE targetThread = aThread;
if (!aThread) {
targetThread = ::GetCurrentThread();
data.walkCallingThread = true;
} else {
DWORD threadId = ::GetThreadId(aThread);
DWORD currentThreadId = ::GetCurrentThreadId();
data.walkCallingThread = (threadId == currentThreadId);
@@ -550,60 +433,26 @@ MozStackWalkThread(MozWalkStackCallback
data.pc_size = ArrayLength(local_pcs);
data.pc_max = aMaxFrames;
void* local_sps[1024];
data.sps = local_sps;
data.sp_count = 0;
data.sp_size = ArrayLength(local_sps);
data.context = aContext;
- if (aThread) {
- // If we're walking the stack of another thread, we don't need to
- // use a separate walker thread.
- WalkStackMain64(&data);
-
- if (data.pc_count > data.pc_size) {
- data.pcs = (void**)_alloca(data.pc_count * sizeof(void*));
- data.pc_size = data.pc_count;
- data.pc_count = 0;
- data.sps = (void**)_alloca(data.sp_count * sizeof(void*));
- data.sp_size = data.sp_count;
- data.sp_count = 0;
- WalkStackMain64(&data);
- }
- } else {
- data.eventStart = ::CreateEvent(nullptr, FALSE /* auto-reset*/,
- FALSE /* initially non-signaled */, nullptr);
- data.eventEnd = ::CreateEvent(nullptr, FALSE /* auto-reset*/,
- FALSE /* initially non-signaled */, nullptr);
-
- ::PostThreadMessage(gStackWalkThread, WM_USER, 0, (LPARAM)&data);
+ WalkStackMain64(&data);
- walkerReturn = ::SignalObjectAndWait(data.eventStart,
- data.eventEnd, INFINITE, FALSE);
- if (walkerReturn != WAIT_OBJECT_0 && data.walkCallingThread) {
- PrintError("SignalObjectAndWait (1)");
- }
- if (data.pc_count > data.pc_size) {
- data.pcs = (void**)_alloca(data.pc_count * sizeof(void*));
- data.pc_size = data.pc_count;
- data.pc_count = 0;
- data.sps = (void**)_alloca(data.sp_count * sizeof(void*));
- data.sp_size = data.sp_count;
- data.sp_count = 0;
- ::PostThreadMessage(gStackWalkThread, WM_USER, 0, (LPARAM)&data);
- walkerReturn = ::SignalObjectAndWait(data.eventStart,
- data.eventEnd, INFINITE, FALSE);
- if (walkerReturn != WAIT_OBJECT_0 && data.walkCallingThread) {
- PrintError("SignalObjectAndWait (2)");
- }
- }
-
- ::CloseHandle(data.eventStart);
- ::CloseHandle(data.eventEnd);
+ if (data.pc_count > data.pc_size) {
+ data.pcs = (void**)_alloca(data.pc_count * sizeof(void*));
+ data.pc_size = data.pc_count;
+ data.pc_count = 0;
+ data.sps = (void**)_alloca(data.sp_count * sizeof(void*));
+ data.sp_size = data.sp_count;
+ data.sp_count = 0;
+ WalkStackMain64(&data);
}
::CloseHandle(myThread);
for (uint32_t i = 0; i < data.pc_count; ++i) {
(*aCallback)(i + 1, data.pcs[i], data.sps[i], aClosure);
}
}