void verifyStackTraces() { constexpr size_t kMaxAddresses = 100; FrameArray<kMaxAddresses> fa; CHECK(getStackTrace(fa)); FrameArray<kMaxAddresses> faSafe; CHECK(getStackTraceSafe(faSafe)); CHECK_EQ(fa.frameCount, faSafe.frameCount); if (VLOG_IS_ON(1)) { Symbolizer symbolizer; OStreamSymbolizePrinter printer(std::cerr, SymbolizePrinter::COLOR_IF_TTY); symbolizer.symbolize(fa); VLOG(1) << "getStackTrace\n"; printer.println(fa); symbolizer.symbolize(faSafe); VLOG(1) << "getStackTraceSafe\n"; printer.println(faSafe); } // Other than the top 2 frames (this one and getStackTrace / // getStackTraceSafe), the stack traces should be identical for (size_t i = 2; i < fa.frameCount; ++i) { VLOG(1) << "i=" << i << " " << std::hex << fa.addresses[i] << " " << faSafe.addresses[i]; CHECK_EQ(fa.addresses[i], faSafe.addresses[i]); } }
// Capture "golden" stack trace with default-configured Symbolizer void ElfCacheTest::SetUp() { bar(); Symbolizer symbolizer; symbolizer.symbolize(goldenFrames); // At least 3 stack frames from us + getStackTrace() ASSERT_LE(4, goldenFrames.frameCount); }
std::ostream& operator<<(std::ostream& out, const ExceptionInfo& info) { out << "Exception type: "; if (info.type) { out << folly::demangle(*info.type); } else { out << "(unknown type)"; } out << " (" << info.frames.size() << (info.frames.size() == 1 ? " frame" : " frames") << ")\n"; try { size_t frameCount = info.frames.size(); // Skip our own internal frames static constexpr size_t kInternalFramesNumber = 3; if (frameCount > kInternalFramesNumber) { auto addresses = info.frames.data() + kInternalFramesNumber; frameCount -= kInternalFramesNumber; std::vector<SymbolizedFrame> frames; frames.resize(frameCount); Symbolizer symbolizer; symbolizer.symbolize(addresses, frames.data(), frameCount); OStreamSymbolizePrinter osp(out, SymbolizePrinter::COLOR_IF_TTY); osp.println(addresses, frames.data(), frameCount); } } catch (const std::exception& e) { out << "\n !! caught " << folly::exceptionStr(e) << "\n"; } catch (...) { out << "\n !!! caught unexpected exception\n"; } return out; }
std::ostream& operator<<(std::ostream& out, const ExceptionInfo& info) { out << "Exception type: "; if (info.type) { out << folly::demangle(*info.type); } else { out << "(unknown type)"; } out << " (" << info.frames.size() << (info.frames.size() == 1 ? " frame" : " frames") << ")\n"; try { Symbolizer symbolizer; folly::StringPiece symbolName; Dwarf::LocationInfo location; for (auto ip : info.frames) { // Symbolize the previous address because the IP might be in the // next function, per glog/src/signalhandler.cc symbolizer.symbolize(ip-1, symbolName, location); Symbolizer::write(out, ip, symbolName, location); } } catch (const std::exception& e) { out << "\n !! caught " << folly::exceptionStr(e) << "\n"; } catch (...) { out << "\n !!! caught unexpected exception\n"; } return out; }
int main(int argc, char *argv[]) { google::InitGoogleLogging(argv[0]); Symbolizer s; StringPiece name; Dwarf::LocationInfo location; CHECK(s.symbolize(reinterpret_cast<uintptr_t>(main), name, location)); LOG(INFO) << name << " " << location.file << " " << location.line << " (" << location.mainFile << ")"; return 0; }
void runElfCacheTest(Symbolizer& symbolizer) { FrameArray<100> frames = goldenFrames; for (size_t i = 0; i < frames.frameCount; ++i) { frames.frames[i].clear(); } symbolizer.symbolize(frames); ASSERT_LE(4, frames.frameCount); for (size_t i = 1; i < 4; ++i) { EXPECT_STREQ(goldenFrames.frames[i].name, frames.frames[i].name); } }
TEST(Symbolizer, Single) { Symbolizer symbolizer; SymbolizedFrame a; ASSERT_TRUE(symbolizer.symbolize(reinterpret_cast<uintptr_t>(foo), a)); EXPECT_EQ("folly::symbolizer::test::foo()", a.demangledName()); auto path = a.location.file.toString(); folly::StringPiece basename(path); auto pos = basename.rfind('/'); if (pos != folly::StringPiece::npos) { basename.advance(pos + 1); } EXPECT_EQ("SymbolizerTest.cpp", basename.str()); }
void MemoryManager::refreshStatsHelperExceeded() { #ifdef FACEBOOK if (RuntimeOption::LogNativeStackOnOOM) { using namespace folly::symbolizer; constexpr size_t kMaxFrames = 128; uintptr_t addresses[kMaxFrames]; auto nframes = getStackTrace(addresses, kMaxFrames); std::vector<SymbolizedFrame> frames(nframes); Symbolizer symbolizer; symbolizer.symbolize(addresses, frames.data(), nframes); StringSymbolizePrinter printer; printer.println(addresses, frames.data(), nframes); Logger::Error("Exceeded memory limit\n\nC++ stack:\n%s", printer.str().c_str()); } #endif ThreadInfo* info = ThreadInfo::s_threadInfo.getNoCheck(); info->m_reqInjectionData.setMemExceededFlag(); m_couldOOM = false; }
TEST(Symbolizer, Single) { Symbolizer symbolizer; SymbolizedFrame a; ASSERT_TRUE(symbolizer.symbolize(reinterpret_cast<uintptr_t>(foo), a)); EXPECT_EQ("folly::symbolizer::test::foo()", a.demangledName()); // The version of clang we use doesn't generate a `.debug_aranges` section, // which the symbolizer needs to lookup the filename. constexpr bool built_with_clang = #ifdef __clang__ true; #else false; #endif if (!built_with_clang) { auto path = a.location.file.toString(); folly::StringPiece basename(path); auto pos = basename.rfind('/'); if (pos != folly::StringPiece::npos) { basename.advance(pos + 1); } EXPECT_EQ("SymbolizerTest.cpp", basename.str()); } }