void ah_crap_handler(int signum) { printf("\nProgram %s (pid = %d) received signal %d.\n", _progname, getpid(), signum); printf("Stack:\n"); NS_StackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0, nullptr, 0, nullptr); printf("Sleeping for %d seconds.\n",_gdb_sleep_duration); printf("Type 'gdb %s %d' to attach your debugger to this thread.\n", _progname, getpid()); // Allow us to be ptraced by gdb on Linux with Yama restrictions enabled. prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY); sleep(_gdb_sleep_duration); printf("Done sleeping...\n"); _exit(signum); }
static void GetChromeHangReport(Telemetry::HangStack &callStack, SharedLibraryInfo &moduleMap) { MOZ_ASSERT(winMainThreadHandle); DWORD ret = ::SuspendThread(winMainThreadHandle); if (ret == -1) { callStack.Clear(); moduleMap.Clear(); return; } NS_StackWalk(ChromeStackWalker, 0, &callStack, reinterpret_cast<uintptr_t>(winMainThreadHandle)); ret = ::ResumeThread(winMainThreadHandle); if (ret == -1) { callStack.Clear(); moduleMap.Clear(); return; } moduleMap = SharedLibraryInfo::GetInfoForSelf(); moduleMap.SortByAddress(); // Remove all modules not referenced by a PC on the stack Telemetry::HangStack sortedStack = callStack; sortedStack.Sort(); size_t moduleIndex = 0; size_t stackIndex = 0; bool unreferencedModule = true; while (stackIndex < sortedStack.Length() && moduleIndex < moduleMap.GetSize()) { uintptr_t pc = sortedStack[stackIndex]; SharedLibrary& module = moduleMap.GetEntry(moduleIndex); uintptr_t moduleStart = module.GetStart(); uintptr_t moduleEnd = module.GetEnd() - 1; if (moduleStart <= pc && pc <= moduleEnd) { // If the current PC is within the current module, mark module as used unreferencedModule = false; ++stackIndex; } else if (pc > moduleEnd) { if (unreferencedModule) { // Remove module if no PCs within its address range moduleMap.RemoveEntries(moduleIndex, moduleIndex + 1); } else { // Module was referenced on stack, but current PC belongs to later module unreferencedModule = true; ++moduleIndex; } } else { // PC does not belong to any module ++stackIndex; } } // Clean up remaining unreferenced modules, i.e. module addresses > max(pc) if (moduleIndex + 1 < moduleMap.GetSize()) { moduleMap.RemoveEntries(moduleIndex + 1, moduleMap.GetSize()); } }
void nsTraceRefcnt::WalkTheStack(FILE* aStream) { #ifdef MOZ_STACKWALKING NS_StackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0, aStream, 0, nullptr); #endif }
void nsTraceRefcnt::WalkTheStackCached(FILE* aStream) { #ifdef MOZ_STACKWALKING if (!gCodeAddressService) { gCodeAddressService = new WalkTheStackCodeAddressService(); } NS_StackWalk(PrintStackFrameCached, /* skipFrames */ 2, /* maxFrames */ 0, aStream, 0, nullptr); #endif }
void BlockingResourceBase::GetStackTrace(AcquisitionState& aState) { #ifndef MOZ_CALLSTACK_DISABLED // Skip this function and the calling function. const uint32_t kSkipFrames = 2; aState.Clear(); // NB: Ignore the return value, there's nothing useful we can do if this // this fails. NS_StackWalk(StackWalkCallback, kSkipFrames, 24, &aState, 0, nullptr); #endif }
static void GetChromeHangReport(Telemetry::ProcessedStack &aStack) { 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); DWORD ret = ::SuspendThread(winMainThreadHandle); if (ret == -1) return; NS_StackWalk(ChromeStackWalker, 0, reinterpret_cast<void*>(&rawStack), reinterpret_cast<uintptr_t>(winMainThreadHandle)); ret = ::ResumeThread(winMainThreadHandle); if (ret == -1) return; aStack = Telemetry::GetStackAndModules(rawStack, false); }
void ah_crap_handler(int signum) { printf("\nProgram %s (pid = %d) received signal %d.\n", _progname, getpid(), signum); printf("Stack:\n"); NS_StackWalk(PrintStackFrame, 2, nsnull); printf("Sleeping for %d seconds.\n",_gdb_sleep_duration); printf("Type 'gdb %s %d' to attach your debugger to this thread.\n", _progname, getpid()); sleep(_gdb_sleep_duration); printf("Done sleeping...\n"); _exit(signum); }
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); DWORD ret = ::SuspendThread(winMainThreadHandle); if (ret == -1) { return; } NS_StackWalk(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; } }
void nsTraceRefcntImpl::WalkTheStack(FILE* aStream) { NS_StackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0, aStream, 0, nullptr); }
void nsTraceRefcntImpl::WalkTheStack(FILE* aStream) { NS_StackWalk(PrintStackFrame, 2, aStream, 0); }
bool ValidWriteAssert(bool ok) { if (gShutdownChecks == SCM_CRASH && !ok) { MOZ_CRASH(); } // We normally don't poison writes if gShutdownChecks is SCM_NOTHING, but // write poisoning can get more users in the future (profiling for example), // so make sure we behave correctly. if (gShutdownChecks == SCM_NOTHING || ok || !sProfileDirectory || !Telemetry::CanRecord()) { return ok; } // Write the stack and loaded libraries to a file. We can get here // concurrently from many writes, so we use multiple temporary files. std::vector<uintptr_t> rawStack; NS_StackWalk(RecordStackWalker, /* skipFrames */ 0, /* maxFrames */ 0, reinterpret_cast<void*>(&rawStack), 0, nullptr); Telemetry::ProcessedStack stack = Telemetry::GetStackAndModules(rawStack); nsPrintfCString nameAux("%s%s%s", sProfileDirectory, NS_SLASH, "Telemetry.LateWriteTmpXXXXXX"); char *name; nameAux.GetMutableData(&name); // We want the sha1 of the entire file, so please don't write to fd // directly; use sha1Stream. FILE *stream; #ifdef XP_WIN HANDLE hFile; do { // mkstemp isn't supported so keep trying until we get a file int result = _mktemp_s(name, strlen(name) + 1); hFile = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); } while (GetLastError() == ERROR_FILE_EXISTS); if (hFile == INVALID_HANDLE_VALUE) { NS_RUNTIMEABORT("Um, how did we get here?"); } // http://support.microsoft.com/kb/139640 int fd = _open_osfhandle((intptr_t)hFile, _O_APPEND); if (fd == -1) { NS_RUNTIMEABORT("Um, how did we get here?"); } stream = _fdopen(fd, "w"); #else int fd = mkstemp(name); stream = fdopen(fd, "w"); #endif SHA1Stream sha1Stream(stream); size_t numModules = stack.GetNumModules(); sha1Stream.Printf("%u\n", (unsigned)numModules); for (size_t i = 0; i < numModules; ++i) { Telemetry::ProcessedStack::Module module = stack.GetModule(i); sha1Stream.Printf("%s %s\n", module.mBreakpadId.c_str(), module.mName.c_str()); } size_t numFrames = stack.GetStackSize(); sha1Stream.Printf("%u\n", (unsigned)numFrames); for (size_t i = 0; i < numFrames; ++i) { const Telemetry::ProcessedStack::Frame &frame = stack.GetFrame(i); // NOTE: We write the offsets, while the atos tool expects a value with // the virtual address added. For example, running otool -l on the the firefox // binary shows // cmd LC_SEGMENT_64 // cmdsize 632 // segname __TEXT // vmaddr 0x0000000100000000 // so to print the line matching the offset 123 one has to run // atos -o firefox 0x100000123. sha1Stream.Printf("%d %x\n", frame.mModIndex, (unsigned)frame.mOffset); } SHA1Sum::Hash sha1; sha1Stream.Finish(sha1); // Note: These files should be deleted by telemetry once it reads them. If // there were no telemery runs by the time we shut down, we just add files // to the existing ones instead of replacing them. Given that each of these // files is a bug to be fixed, that is probably the right thing to do. // We append the sha1 of the contents to the file name. This provides a simple // client side deduplication. nsPrintfCString finalName("%s%s", sProfileDirectory, "/Telemetry.LateWriteFinal-"); for (int i = 0; i < 20; ++i) { finalName.AppendPrintf("%02x", sha1[i]); } PR_Delete(finalName.get()); PR_Rename(name, finalName.get()); return false; }