diff options
Diffstat (limited to 'xpcom/threads')
-rw-r--r-- | xpcom/threads/HangMonitor.cpp | 144 | ||||
-rw-r--r-- | xpcom/threads/ThreadStackHelper.cpp | 466 | ||||
-rw-r--r-- | xpcom/threads/ThreadStackHelper.h | 40 |
3 files changed, 3 insertions, 647 deletions
diff --git a/xpcom/threads/HangMonitor.cpp b/xpcom/threads/HangMonitor.cpp index bd415be50..6def6ed61 100644 --- a/xpcom/threads/HangMonitor.cpp +++ b/xpcom/threads/HangMonitor.cpp @@ -26,10 +26,6 @@ #include <windows.h> #endif -#if defined(MOZ_ENABLE_PROFILER_SPS) && defined(MOZ_PROFILING) && defined(XP_WIN) - #define REPORT_CHROME_HANGS -#endif - namespace mozilla { namespace HangMonitor { @@ -41,10 +37,6 @@ volatile bool gDebugDisableHangMonitor = false; const char kHangMonitorPrefName[] = "hangmonitor.timeout"; -#ifdef REPORT_CHROME_HANGS -const char kTelemetryPrefName[] = "toolkit.telemetry.enabled"; -#endif - // Monitor protects gShutdown and gTimeout, but not gTimestamp which rely on // being atomically set by the processor; synchronization doesn't really matter // in this use case. @@ -62,31 +54,11 @@ bool gShutdown; // we're currently not processing events. Atomic<PRIntervalTime> gTimestamp(PR_INTERVAL_NO_WAIT); -#ifdef REPORT_CHROME_HANGS -// Main thread ID used in reporting chrome hangs under Windows -static HANDLE winMainThreadHandle = nullptr; - -// Default timeout for reporting chrome hangs to Telemetry (5 seconds) -static const int32_t DEFAULT_CHROME_HANG_INTERVAL = 5; - -// Maximum number of PCs to gather from the stack -static const int32_t MAX_CALL_STACK_PCS = 400; -#endif - // PrefChangedFunc void PrefChanged(const char*, void*) { int32_t newval = Preferences::GetInt(kHangMonitorPrefName); -#ifdef REPORT_CHROME_HANGS - // Monitor chrome hangs on the profiling branch if Telemetry enabled - if (newval == 0) { - bool telemetryEnabled = Preferences::GetBool(kTelemetryPrefName); - if (telemetryEnabled) { - newval = DEFAULT_CHROME_HANG_INTERVAL; - } - } -#endif MonitorAutoLock lock(*gMonitor); if (newval != gTimeout) { gTimeout = newval; @@ -110,89 +82,6 @@ Crash() NS_RUNTIMEABORT("HangMonitor triggered"); } -#ifdef REPORT_CHROME_HANGS - -static void -ChromeStackWalker(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure) -{ - MOZ_ASSERT(aClosure); - std::vector<uintptr_t>* stack = - static_cast<std::vector<uintptr_t>*>(aClosure); - if (stack->size() == MAX_CALL_STACK_PCS) { - return; - } - MOZ_ASSERT(stack->size() < MAX_CALL_STACK_PCS); - stack->push_back(reinterpret_cast<uintptr_t>(aPC)); -} - -static void -GetChromeHangReport(Telemetry::ProcessedStack& aStack, - int32_t& aSystemUptime, - int32_t& aFirefoxUptime) -{ - MOZ_ASSERT(winMainThreadHandle); - - // The thread we're about to suspend might have the alloc lock - // so allocate ahead of time - std::vector<uintptr_t> rawStack; - rawStack.reserve(MAX_CALL_STACK_PCS); - - // Workaround possible deadlock where the main thread is running a - // long-standing JS job, and happens to be in the JIT allocator when we - // suspend it. Since, on win 64, this requires holding a process lock that - // MozStackWalk requires, take this "workaround lock" to avoid deadlock. -#ifdef _WIN64 - AcquireStackWalkWorkaroundLock(); -#endif - DWORD ret = ::SuspendThread(winMainThreadHandle); - bool suspended = false; - if (ret != -1) { - // SuspendThread is asynchronous, so the thread may still be running. Use - // GetThreadContext to ensure it's really suspended. - // See https://blogs.msdn.microsoft.com/oldnewthing/20150205-00/?p=44743. - CONTEXT context; - context.ContextFlags = CONTEXT_CONTROL; - if (::GetThreadContext(winMainThreadHandle, &context)) { - suspended = true; - } - } - -#ifdef _WIN64 - ReleaseStackWalkWorkaroundLock(); -#endif - - if (!suspended) { - if (ret != -1) { - MOZ_ALWAYS_TRUE(::ResumeThread(winMainThreadHandle) != DWORD(-1)); - } - return; - } - - MozStackWalk(ChromeStackWalker, /* skipFrames */ 0, /* maxFrames */ 0, - reinterpret_cast<void*>(&rawStack), - reinterpret_cast<uintptr_t>(winMainThreadHandle), nullptr); - ret = ::ResumeThread(winMainThreadHandle); - if (ret == -1) { - return; - } - aStack = Telemetry::GetStackAndModules(rawStack); - - // Record system uptime (in minutes) at the time of the hang - aSystemUptime = ((GetTickCount() / 1000) - (gTimeout * 2)) / 60; - - // Record Firefox uptime (in minutes) at the time of the hang - bool error; - TimeStamp processCreation = TimeStamp::ProcessCreation(error); - if (!error) { - TimeDuration td = TimeStamp::Now() - processCreation; - aFirefoxUptime = (static_cast<int32_t>(td.ToSeconds()) - (gTimeout * 2)) / 60; - } else { - aFirefoxUptime = -1; - } -} - -#endif - void ThreadMain(void*) { @@ -206,13 +95,6 @@ ThreadMain(void*) PRIntervalTime lastTimestamp = 0; int waitCount = 0; -#ifdef REPORT_CHROME_HANGS - Telemetry::ProcessedStack stack; - int32_t systemUptime = -1; - int32_t firefoxUptime = -1; - UniquePtr<HangAnnotations> annotations; -#endif - while (true) { if (gShutdown) { return; // Exit the thread @@ -233,14 +115,6 @@ ThreadMain(void*) timestamp == lastTimestamp && gTimeout > 0) { ++waitCount; -#ifdef REPORT_CHROME_HANGS - // Capture the chrome-hang stack + Firefox & system uptimes after - // the minimum hang duration has been reached (not when the hang ends) - if (waitCount == 2) { - GetChromeHangReport(stack, systemUptime, firefoxUptime); - annotations = ChromeHangAnnotatorCallout(); - } -#else // This is the crash-on-hang feature. // See bug 867313 for the quirk in the waitCount comparison if (waitCount >= 2) { @@ -251,16 +125,7 @@ ThreadMain(void*) Crash(); } } -#endif } else { -#ifdef REPORT_CHROME_HANGS - if (waitCount >= 2) { - uint32_t hangDuration = PR_IntervalToSeconds(now - lastTimestamp); - Telemetry::RecordChromeHang(hangDuration, stack, systemUptime, - firefoxUptime, Move(annotations)); - stack.Clear(); - } -#endif lastTimestamp = timestamp; waitCount = 0; } @@ -289,15 +154,6 @@ Startup() Preferences::RegisterCallback(PrefChanged, kHangMonitorPrefName, nullptr); PrefChanged(nullptr, nullptr); -#ifdef REPORT_CHROME_HANGS - Preferences::RegisterCallback(PrefChanged, kTelemetryPrefName, nullptr); - winMainThreadHandle = - OpenThread(THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId()); - if (!winMainThreadHandle) { - return; - } -#endif - // Don't actually start measuring hangs until we hit the main event loop. // This potentially misses a small class of really early startup hangs, // but avoids dealing with some xpcshell tests and other situations which diff --git a/xpcom/threads/ThreadStackHelper.cpp b/xpcom/threads/ThreadStackHelper.cpp index 1713c9194..2c0e87986 100644 --- a/xpcom/threads/ThreadStackHelper.cpp +++ b/xpcom/threads/ThreadStackHelper.cpp @@ -9,9 +9,6 @@ #include "nsJSPrincipals.h" #include "nsScriptSecurityManager.h" #include "jsfriendapi.h" -#ifdef MOZ_THREADSTACKHELPER_NATIVE -#include "shared-libraries.h" -#endif #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" @@ -62,17 +59,6 @@ #endif #endif -#ifdef MOZ_THREADSTACKHELPER_NATIVE -#if defined(MOZ_THREADSTACKHELPER_X86) || \ - defined(MOZ_THREADSTACKHELPER_X64) || \ - defined(MOZ_THREADSTACKHELPER_ARM) -// On these architectures, the stack grows downwards (toward lower addresses). -#define MOZ_THREADSTACKHELPER_STACK_GROWS_DOWN -#else -#error "Unsupported architecture" -#endif -#endif // MOZ_THREADSTACKHELPER_NATIVE - namespace mozilla { void @@ -114,14 +100,6 @@ ThreadStackHelper::Shutdown() ThreadStackHelper::ThreadStackHelper() : mStackToFill(nullptr) -#ifdef MOZ_THREADSTACKHELPER_PSEUDO - , mPseudoStack(mozilla_get_pseudo_stack()) -#ifdef MOZ_THREADSTACKHELPER_NATIVE - , mContextToFill(nullptr) -#endif - , mMaxStackSize(Stack::sMaxInlineStorage) - , mMaxBufferSize(512) -#endif { #if defined(XP_LINUX) MOZ_ALWAYS_TRUE(!::sem_init(&mSem, 0, 0)); @@ -131,18 +109,11 @@ ThreadStackHelper::ThreadStackHelper() ::GetCurrentProcess(), ::GetCurrentThread(), ::GetCurrentProcess(), &mThreadID, THREAD_SUSPEND_RESUME -#ifdef MOZ_THREADSTACKHELPER_NATIVE - | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION -#endif , FALSE, 0); MOZ_ASSERT(mInitialized); #elif defined(XP_MACOSX) mThreadID = mach_thread_self(); #endif - -#ifdef MOZ_THREADSTACKHELPER_NATIVE - GetThreadStackBase(); -#endif } ThreadStackHelper::~ThreadStackHelper() @@ -156,45 +127,6 @@ ThreadStackHelper::~ThreadStackHelper() #endif } -#ifdef MOZ_THREADSTACKHELPER_NATIVE -void ThreadStackHelper::GetThreadStackBase() -{ - mThreadStackBase = 0; - -#if defined(XP_LINUX) - void* stackAddr; - size_t stackSize; - ::pthread_t pthr = ::pthread_self(); - ::pthread_attr_t pthr_attr; - NS_ENSURE_TRUE_VOID(!::pthread_getattr_np(pthr, &pthr_attr)); - if (!::pthread_attr_getstack(&pthr_attr, &stackAddr, &stackSize)) { -#ifdef MOZ_THREADSTACKHELPER_STACK_GROWS_DOWN - mThreadStackBase = intptr_t(stackAddr) + stackSize; -#else - mThreadStackBase = intptr_t(stackAddr); -#endif - } - MOZ_ALWAYS_TRUE(!::pthread_attr_destroy(&pthr_attr)); - -#elif defined(XP_WIN) - ::MEMORY_BASIC_INFORMATION meminfo = {}; - NS_ENSURE_TRUE_VOID(::VirtualQuery(&meminfo, &meminfo, sizeof(meminfo))); -#ifdef MOZ_THREADSTACKHELPER_STACK_GROWS_DOWN - mThreadStackBase = intptr_t(meminfo.BaseAddress) + meminfo.RegionSize; -#else - mThreadStackBase = intptr_t(meminfo.AllocationBase); -#endif - -#elif defined(XP_MACOSX) - ::pthread_t pthr = ::pthread_self(); - mThreadStackBase = intptr_t(::pthread_get_stackaddr_np(pthr)); - -#else - #error "Unsupported platform" -#endif // platform -} -#endif // MOZ_THREADSTACKHELPER_NATIVE - namespace { template<typename T> class ScopedSetPtr @@ -281,53 +213,10 @@ ThreadStackHelper::GetStack(Stack& aStack) #endif } -#ifdef MOZ_THREADSTACKHELPER_NATIVE -class ThreadStackHelper::ThreadContext final -{ -public: - // TODO: provide per-platform definition of Context. - typedef struct {} Context; - - // Limit copied stack to 4kB - static const size_t kMaxStackSize = 0x1000; - // Limit unwound stack to 32 frames - static const unsigned int kMaxStackFrames = 32; - // Whether this structure contains valid data - bool mValid; - // Processor context - Context mContext; - // Stack area - UniquePtr<uint8_t[]> mStack; - // Start of stack area - uintptr_t mStackBase; - // Size of stack area - size_t mStackSize; - // End of stack area - const void* mStackEnd; - - ThreadContext() - : mValid(false) - , mStackBase(0) - , mStackSize(0) - , mStackEnd(nullptr) {} -}; -#endif // MOZ_THREADSTACKHELPER_NATIVE - void ThreadStackHelper::GetNativeStack(Stack& aStack) { -#ifdef MOZ_THREADSTACKHELPER_NATIVE - ThreadContext context; - context.mStack = MakeUnique<uint8_t[]>(ThreadContext::kMaxStackSize); - - ScopedSetPtr<ThreadContext> contextPtr(mContextToFill, &context); - - // Get pseudostack first and fill the thread context. - GetStack(aStack); - NS_ENSURE_TRUE_VOID(context.mValid); - - // TODO: walk the saved stack frames. -#endif // MOZ_THREADSTACKHELPER_NATIVE + /*** STUB ***/ } #ifdef XP_LINUX @@ -353,369 +242,20 @@ ThreadStackHelper::PrepareStackBuffer(Stack& aStack) { // Return false to skip getting the stack and return an empty stack aStack.clear(); -#ifdef MOZ_THREADSTACKHELPER_PSEUDO - /* Normally, provided the profiler is enabled, it would be an error if we - don't have a pseudostack here (the thread probably forgot to call - profiler_register_thread). However, on B2G, profiling secondary threads - may be disabled despite profiler being enabled. This is by-design and - is not an error. */ - MOZ_ASSERT(mPseudoStack); - if (!aStack.reserve(mMaxStackSize) || - !aStack.reserve(aStack.capacity()) || // reserve up to the capacity - !aStack.EnsureBufferCapacity(mMaxBufferSize)) { - return false; - } - return true; -#else return false; -#endif -} - -#ifdef MOZ_THREADSTACKHELPER_PSEUDO - -namespace { - -bool -IsChromeJSScript(JSScript* aScript) -{ - // May be called from another thread or inside a signal handler. - // We assume querying the script is safe but we must not manipulate it. - - nsIScriptSecurityManager* const secman = - nsScriptSecurityManager::GetScriptSecurityManager(); - NS_ENSURE_TRUE(secman, false); - - JSPrincipals* const principals = JS_GetScriptPrincipals(aScript); - return secman->IsSystemPrincipal(nsJSPrincipals::get(principals)); -} - -// Get the full path after the URI scheme, if the URI matches the scheme. -// For example, GetFullPathForScheme("a://b/c/d/e", "a://") returns "b/c/d/e". -template <size_t LEN> -const char* -GetFullPathForScheme(const char* filename, const char (&scheme)[LEN]) { - // Account for the null terminator included in LEN. - if (!strncmp(filename, scheme, LEN - 1)) { - return filename + LEN - 1; - } - return nullptr; -} - -// Get the full path after a URI component, if the URI contains the component. -// For example, GetPathAfterComponent("a://b/c/d/e", "/c/") returns "d/e". -template <size_t LEN> -const char* -GetPathAfterComponent(const char* filename, const char (&component)[LEN]) { - const char* found = nullptr; - const char* next = strstr(filename, component); - while (next) { - // Move 'found' to end of the component, after the separator '/'. - // 'LEN - 1' accounts for the null terminator included in LEN, - found = next + LEN - 1; - // Resume searching before the separator '/'. - next = strstr(found - 1, component); - } - return found; } -} // namespace - -const char* -ThreadStackHelper::AppendJSEntry(const volatile StackEntry* aEntry, - intptr_t& aAvailableBufferSize, - const char* aPrevLabel) -{ - // May be called from another thread or inside a signal handler. - // We assume querying the script is safe but we must not manupulate it. - // Also we must not allocate any memory from heap. - MOZ_ASSERT(aEntry->isJs()); - - const char* label; - JSScript* script = aEntry->script(); - if (!script) { - label = "(profiling suppressed)"; - } else if (IsChromeJSScript(aEntry->script())) { - const char* filename = JS_GetScriptFilename(aEntry->script()); - const unsigned lineno = JS_PCToLineNumber(aEntry->script(), aEntry->pc()); - MOZ_ASSERT(filename); - - char buffer[128]; // Enough to fit longest js file name from the tree - - // Some script names are in the form "foo -> bar -> baz". - // Here we find the origin of these redirected scripts. - const char* basename = GetPathAfterComponent(filename, " -> "); - if (basename) { - filename = basename; - } - - basename = GetFullPathForScheme(filename, "chrome://"); - if (!basename) { - basename = GetFullPathForScheme(filename, "resource://"); - } - if (!basename) { - // If the (add-on) script is located under the {profile}/extensions - // directory, extract the path after the /extensions/ part. - basename = GetPathAfterComponent(filename, "/extensions/"); - } - if (!basename) { - // Only keep the file base name for paths outside the above formats. - basename = strrchr(filename, '/'); - basename = basename ? basename + 1 : filename; - // Look for Windows path separator as well. - filename = strrchr(basename, '\\'); - if (filename) { - basename = filename + 1; - } - } - - size_t len = SprintfLiteral(buffer, "%s:%u", basename, lineno); - if (len < sizeof(buffer)) { - if (mStackToFill->IsSameAsEntry(aPrevLabel, buffer)) { - return aPrevLabel; - } - - // Keep track of the required buffer size - aAvailableBufferSize -= (len + 1); - if (aAvailableBufferSize >= 0) { - // Buffer is big enough. - return mStackToFill->InfallibleAppendViaBuffer(buffer, len); - } - // Buffer is not big enough; fall through to using static label below. - } - // snprintf failed or buffer is not big enough. - label = "(chrome script)"; - } else { - label = "(content script)"; - } - - if (mStackToFill->IsSameAsEntry(aPrevLabel, label)) { - return aPrevLabel; - } - mStackToFill->infallibleAppend(label); - return label; -} - -#endif // MOZ_THREADSTACKHELPER_PSEUDO - void ThreadStackHelper::FillStackBuffer() { MOZ_ASSERT(mStackToFill->empty()); - -#ifdef MOZ_THREADSTACKHELPER_PSEUDO - size_t reservedSize = mStackToFill->capacity(); - size_t reservedBufferSize = mStackToFill->AvailableBufferSize(); - intptr_t availableBufferSize = intptr_t(reservedBufferSize); - - // Go from front to back - const volatile StackEntry* entry = mPseudoStack->mStack; - const volatile StackEntry* end = entry + mPseudoStack->stackSize(); - // Deduplicate identical, consecutive frames - const char* prevLabel = nullptr; - for (; reservedSize-- && entry != end; entry++) { - /* We only accept non-copy labels, including js::RunScript, - because we only want static labels in the hang stack. */ - if (entry->isCopyLabel()) { - continue; - } - if (entry->isJs()) { - prevLabel = AppendJSEntry(entry, availableBufferSize, prevLabel); - continue; - } -#ifdef MOZ_THREADSTACKHELPER_NATIVE - if (mContextToFill) { - mContextToFill->mStackEnd = entry->stackAddress(); - } -#endif - const char* const label = entry->label(); - if (mStackToFill->IsSameAsEntry(prevLabel, label)) { - // Avoid duplicate labels to save space in the stack. - continue; - } - mStackToFill->infallibleAppend(label); - prevLabel = label; - } - - // end != entry if we exited early due to not enough reserved frames. - // Expand the number of reserved frames for next time. - mMaxStackSize = mStackToFill->capacity() + (end - entry); - - // availableBufferSize < 0 if we needed a larger buffer than we reserved. - // Calculate a new reserve size for next time. - if (availableBufferSize < 0) { - mMaxBufferSize = reservedBufferSize - availableBufferSize; - } -#endif + /*** STUB ***/ } MOZ_ASAN_BLACKLIST void ThreadStackHelper::FillThreadContext(void* aContext) { -#ifdef MOZ_THREADSTACKHELPER_NATIVE - if (!mContextToFill) { - return; - } - -#if 0 // TODO: remove dependency on Breakpad structs. -#if defined(XP_LINUX) - const ucontext_t& context = *reinterpret_cast<ucontext_t*>(aContext); -#if defined(MOZ_THREADSTACKHELPER_X86) - mContextToFill->mContext.context_flags = MD_CONTEXT_X86_FULL; - mContextToFill->mContext.edi = context.uc_mcontext.gregs[REG_EDI]; - mContextToFill->mContext.esi = context.uc_mcontext.gregs[REG_ESI]; - mContextToFill->mContext.ebx = context.uc_mcontext.gregs[REG_EBX]; - mContextToFill->mContext.edx = context.uc_mcontext.gregs[REG_EDX]; - mContextToFill->mContext.ecx = context.uc_mcontext.gregs[REG_ECX]; - mContextToFill->mContext.eax = context.uc_mcontext.gregs[REG_EAX]; - mContextToFill->mContext.ebp = context.uc_mcontext.gregs[REG_EBP]; - mContextToFill->mContext.eip = context.uc_mcontext.gregs[REG_EIP]; - mContextToFill->mContext.eflags = context.uc_mcontext.gregs[REG_EFL]; - mContextToFill->mContext.esp = context.uc_mcontext.gregs[REG_ESP]; -#elif defined(MOZ_THREADSTACKHELPER_X64) - mContextToFill->mContext.context_flags = MD_CONTEXT_AMD64_FULL; - mContextToFill->mContext.eflags = uint32_t(context.uc_mcontext.gregs[REG_EFL]); - mContextToFill->mContext.rax = context.uc_mcontext.gregs[REG_RAX]; - mContextToFill->mContext.rcx = context.uc_mcontext.gregs[REG_RCX]; - mContextToFill->mContext.rdx = context.uc_mcontext.gregs[REG_RDX]; - mContextToFill->mContext.rbx = context.uc_mcontext.gregs[REG_RBX]; - mContextToFill->mContext.rsp = context.uc_mcontext.gregs[REG_RSP]; - mContextToFill->mContext.rbp = context.uc_mcontext.gregs[REG_RBP]; - mContextToFill->mContext.rsi = context.uc_mcontext.gregs[REG_RSI]; - mContextToFill->mContext.rdi = context.uc_mcontext.gregs[REG_RDI]; - memcpy(&mContextToFill->mContext.r8, - &context.uc_mcontext.gregs[REG_R8], 8 * sizeof(int64_t)); - mContextToFill->mContext.rip = context.uc_mcontext.gregs[REG_RIP]; -#elif defined(MOZ_THREADSTACKHELPER_ARM) - mContextToFill->mContext.context_flags = MD_CONTEXT_ARM_FULL; - memcpy(&mContextToFill->mContext.iregs[0], - &context.uc_mcontext.arm_r0, 17 * sizeof(int32_t)); -#else - #error "Unsupported architecture" -#endif // architecture - -#elif defined(XP_WIN) - // Breakpad context struct is based off of the Windows CONTEXT struct, - // so we assume they are the same; do some sanity checks to make sure. - static_assert(sizeof(ThreadContext::Context) == sizeof(::CONTEXT), - "Context struct mismatch"); - static_assert(offsetof(ThreadContext::Context, context_flags) == - offsetof(::CONTEXT, ContextFlags), - "Context struct mismatch"); - mContextToFill->mContext.context_flags = CONTEXT_FULL; - NS_ENSURE_TRUE_VOID(::GetThreadContext(mThreadID, - reinterpret_cast<::CONTEXT*>(&mContextToFill->mContext))); - -#elif defined(XP_MACOSX) -#if defined(MOZ_THREADSTACKHELPER_X86) - const thread_state_flavor_t flavor = x86_THREAD_STATE32; - x86_thread_state32_t state = {}; - mach_msg_type_number_t count = x86_THREAD_STATE32_COUNT; -#elif defined(MOZ_THREADSTACKHELPER_X64) - const thread_state_flavor_t flavor = x86_THREAD_STATE64; - x86_thread_state64_t state = {}; - mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT; -#elif defined(MOZ_THREADSTACKHELPER_ARM) - const thread_state_flavor_t flavor = ARM_THREAD_STATE; - arm_thread_state_t state = {}; - mach_msg_type_number_t count = ARM_THREAD_STATE_COUNT; -#endif - NS_ENSURE_TRUE_VOID(KERN_SUCCESS == ::thread_get_state( - mThreadID, flavor, reinterpret_cast<thread_state_t>(&state), &count)); -#if __DARWIN_UNIX03 -#define GET_REGISTER(s, r) ((s).__##r) -#else -#define GET_REGISTER(s, r) ((s).r) -#endif -#if defined(MOZ_THREADSTACKHELPER_X86) - mContextToFill->mContext.context_flags = MD_CONTEXT_X86_FULL; - mContextToFill->mContext.edi = GET_REGISTER(state, edi); - mContextToFill->mContext.esi = GET_REGISTER(state, esi); - mContextToFill->mContext.ebx = GET_REGISTER(state, ebx); - mContextToFill->mContext.edx = GET_REGISTER(state, edx); - mContextToFill->mContext.ecx = GET_REGISTER(state, ecx); - mContextToFill->mContext.eax = GET_REGISTER(state, eax); - mContextToFill->mContext.ebp = GET_REGISTER(state, ebp); - mContextToFill->mContext.eip = GET_REGISTER(state, eip); - mContextToFill->mContext.eflags = GET_REGISTER(state, eflags); - mContextToFill->mContext.esp = GET_REGISTER(state, esp); -#elif defined(MOZ_THREADSTACKHELPER_X64) - mContextToFill->mContext.context_flags = MD_CONTEXT_AMD64_FULL; - mContextToFill->mContext.eflags = uint32_t(GET_REGISTER(state, rflags)); - mContextToFill->mContext.rax = GET_REGISTER(state, rax); - mContextToFill->mContext.rcx = GET_REGISTER(state, rcx); - mContextToFill->mContext.rdx = GET_REGISTER(state, rdx); - mContextToFill->mContext.rbx = GET_REGISTER(state, rbx); - mContextToFill->mContext.rsp = GET_REGISTER(state, rsp); - mContextToFill->mContext.rbp = GET_REGISTER(state, rbp); - mContextToFill->mContext.rsi = GET_REGISTER(state, rsi); - mContextToFill->mContext.rdi = GET_REGISTER(state, rdi); - memcpy(&mContextToFill->mContext.r8, - &GET_REGISTER(state, r8), 8 * sizeof(int64_t)); - mContextToFill->mContext.rip = GET_REGISTER(state, rip); -#elif defined(MOZ_THREADSTACKHELPER_ARM) - mContextToFill->mContext.context_flags = MD_CONTEXT_ARM_FULL; - memcpy(mContextToFill->mContext.iregs, - GET_REGISTER(state, r), 17 * sizeof(int32_t)); -#else - #error "Unsupported architecture" -#endif // architecture -#undef GET_REGISTER - -#else - #error "Unsupported platform" -#endif // platform - - intptr_t sp = 0; -#if defined(MOZ_THREADSTACKHELPER_X86) - sp = mContextToFill->mContext.esp; -#elif defined(MOZ_THREADSTACKHELPER_X64) - sp = mContextToFill->mContext.rsp; -#elif defined(MOZ_THREADSTACKHELPER_ARM) - sp = mContextToFill->mContext.iregs[13]; -#else - #error "Unsupported architecture" -#endif // architecture - NS_ENSURE_TRUE_VOID(sp); - NS_ENSURE_TRUE_VOID(mThreadStackBase); - - size_t stackSize = std::min(intptr_t(ThreadContext::kMaxStackSize), - std::abs(sp - mThreadStackBase)); - - if (mContextToFill->mStackEnd) { - // Limit the start of stack to a certain location if specified. - stackSize = std::min(intptr_t(stackSize), - std::abs(sp - intptr_t(mContextToFill->mStackEnd))); - } - -#ifndef MOZ_THREADSTACKHELPER_STACK_GROWS_DOWN - // If if the stack grows upwards, and we need to recalculate our - // stack copy's base address. Subtract sizeof(void*) so that the - // location pointed to by sp is included. - sp -= stackSize - sizeof(void*); -#endif - -#ifndef MOZ_ASAN - memcpy(mContextToFill->mStack.get(), reinterpret_cast<void*>(sp), stackSize); - // Valgrind doesn't care about the access outside the stack frame, but - // the presence of uninitialised values on the stack does cause it to - // later report a lot of false errors when Breakpad comes to unwind it. - // So mark the extracted data as defined. - MOZ_MAKE_MEM_DEFINED(mContextToFill->mStack.get(), stackSize); -#else - // ASan will flag memcpy for access outside of stack frames, - // so roll our own memcpy here. - intptr_t* dst = reinterpret_cast<intptr_t*>(&mContextToFill->mStack[0]); - const intptr_t* src = reinterpret_cast<intptr_t*>(sp); - for (intptr_t len = stackSize; len > 0; len -= sizeof(*src)) { - *(dst++) = *(src++); - } -#endif - - mContextToFill->mStackBase = uintptr_t(sp); - mContextToFill->mStackSize = stackSize; - mContextToFill->mValid = true; -#endif -#endif // MOZ_THREADSTACKHELPER_NATIVE + /*** STUB ***/ } } // namespace mozilla diff --git a/xpcom/threads/ThreadStackHelper.h b/xpcom/threads/ThreadStackHelper.h index 9c40ad5e2..f06e704b4 100644 --- a/xpcom/threads/ThreadStackHelper.h +++ b/xpcom/threads/ThreadStackHelper.h @@ -23,27 +23,6 @@ #include <mach/mach.h> #endif -// Support pseudostack on these platforms. -#if defined(XP_LINUX) || defined(XP_WIN) || defined(XP_MACOSX) -# ifdef MOZ_ENABLE_PROFILER_SPS -# define MOZ_THREADSTACKHELPER_PSEUDO -# endif -#endif - -#ifdef MOZ_THREADSTACKHELPER_PSEUDO -# define MOZ_THREADSTACKHELPER_NATIVE -# if defined(__i386__) || defined(_M_IX86) -# define MOZ_THREADSTACKHELPER_X86 -# elif defined(__x86_64__) || defined(_M_X64) -# define MOZ_THREADSTACKHELPER_X64 -# elif defined(__arm__) || defined(_M_ARM) -# define MOZ_THREADSTACKHELPER_ARM -# else - // Unsupported architecture -# undef MOZ_THREADSTACKHELPER_NATIVE -# endif -#endif - namespace mozilla { /** @@ -63,29 +42,10 @@ public: private: Stack* mStackToFill; -#ifdef MOZ_THREADSTACKHELPER_PSEUDO - const PseudoStack* const mPseudoStack; -#ifdef MOZ_THREADSTACKHELPER_NATIVE - class ThreadContext; - // Set to non-null if GetStack should get the thread context. - ThreadContext* mContextToFill; - intptr_t mThreadStackBase; -#endif - size_t mMaxStackSize; - size_t mMaxBufferSize; -#endif bool PrepareStackBuffer(Stack& aStack); void FillStackBuffer(); void FillThreadContext(void* aContext = nullptr); -#ifdef MOZ_THREADSTACKHELPER_PSEUDO - const char* AppendJSEntry(const volatile StackEntry* aEntry, - intptr_t& aAvailableBufferSize, - const char* aPrevLabel); -#endif -#ifdef MOZ_THREADSTACKHELPER_NATIVE - void GetThreadStackBase(); -#endif public: /** |