Commit 635af78d authored by Pallab Bhattacharya's avatar Pallab Bhattacharya Committed by facebook-github-bot-1

folly::Symbolizer can be enhanced for dumpStackTrace

Summary:
added functionality in Symbolizer.cpp to handle multi-segment binary and to allow symbol lookup via /proc/self/exe when some or whole text is relocated to ANON pages such as during hugification. An example of multi-segment binary : P56071432

cc markw65 - a part of the change include logic pulled from hphp/runtime/base/stack-logger.cpp:symbolize_huge_text so that hugified consumers of dumpStackTrace need not fork off.

Reviewed By: edwardc

Differential Revision: D2802837

fb-gh-sync-id: 577ab1b4ef8f22059894bfdd9c0526a22ee89ca8
parent 81295897
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include <limits.h> #include <limits.h>
#include <unistd.h>
#ifdef __GNUC__ #ifdef __GNUC__
#include <ext/stdio_filebuf.h> #include <ext/stdio_filebuf.h>
...@@ -86,8 +87,12 @@ void skipWS(StringPiece& sp) { ...@@ -86,8 +87,12 @@ void skipWS(StringPiece& sp) {
* Parse a line from /proc/self/maps * Parse a line from /proc/self/maps
*/ */
bool parseProcMapsLine(StringPiece line, bool parseProcMapsLine(StringPiece line,
uintptr_t& from, uintptr_t& to, uintptr_t& from,
uintptr_t& to,
uintptr_t& fileOff,
bool& isSelf,
StringPiece& fileName) { StringPiece& fileName) {
isSelf = false;
// from to perm offset dev inode path // from to perm offset dev inode path
// 00400000-00405000 r-xp 00000000 08:03 35291182 /bin/cat // 00400000-00405000 r-xp 00000000 08:03 35291182 /bin/cat
if (line.empty()) { if (line.empty()) {
...@@ -125,9 +130,15 @@ bool parseProcMapsLine(StringPiece line, ...@@ -125,9 +130,15 @@ bool parseProcMapsLine(StringPiece line,
return false; return false;
} }
line.pop_front(); line.pop_front();
if (fileOffset != 0) { // main mapping starts at 0 but there can be multi-segment binary
return false; // main mapping starts at 0 // such as
} // from to perm offset dev inode path
// 00400000-00405000 r-xp 00000000 08:03 54011424 /bin/foo
// 00600000-00605000 r-xp 00020000 08:03 54011424 /bin/foo
// 00800000-00805000 r-xp 00040000 08:03 54011424 /bin/foo
// if the offset > 0, this indicates to the caller that the baseAddress
// need to be used for undo relocation step.
fileOff = fileOffset;
// dev // dev
skipNS(line); skipNS(line);
...@@ -142,8 +153,14 @@ bool parseProcMapsLine(StringPiece line, ...@@ -142,8 +153,14 @@ bool parseProcMapsLine(StringPiece line,
return false; return false;
} }
// if inode is 0, such as in case of ANON pages, there should be atleast
// one white space before EOL
skipWS(line); skipWS(line);
if (line.empty()) { if (line.empty()) {
// There will be no fileName for ANON text pages
// if the parsing came this far without a fileName, then from/to address
// may contain text in ANON pages.
isSelf = true;
fileName.clear(); fileName.clear();
return true; return true;
} }
...@@ -203,6 +220,14 @@ void Symbolizer::symbolize(const uintptr_t* addresses, ...@@ -203,6 +220,14 @@ void Symbolizer::symbolize(const uintptr_t* addresses,
return; return;
} }
char selfFile[PATH_MAX + 8];
ssize_t selfSize;
if ((selfSize = readlink("/proc/self/exe", selfFile, PATH_MAX + 1)) == -1) {
// something terribly wrong
return;
}
selfFile[selfSize] = '\0';
char buf[PATH_MAX + 100]; // Long enough for any line char buf[PATH_MAX + 100]; // Long enough for any line
LineReader reader(fd, buf, sizeof(buf)); LineReader reader(fd, buf, sizeof(buf));
...@@ -215,14 +240,33 @@ void Symbolizer::symbolize(const uintptr_t* addresses, ...@@ -215,14 +240,33 @@ void Symbolizer::symbolize(const uintptr_t* addresses,
// Parse line // Parse line
uintptr_t from; uintptr_t from;
uintptr_t to; uintptr_t to;
uintptr_t fileOff;
uintptr_t base;
bool isSelf = false; // fileName can potentially be '/proc/self/exe'
StringPiece fileName; StringPiece fileName;
if (!parseProcMapsLine(line, from, to, fileName)) { if (!parseProcMapsLine(line, from, to, fileOff, isSelf, fileName)) {
continue; continue;
} }
base = from;
bool first = true; bool first = true;
std::shared_ptr<ElfFile> elfFile; std::shared_ptr<ElfFile> elfFile;
// case of text on ANON?
// Recompute from/to/base from the executable
if (isSelf && fileName.empty()) {
elfFile = cache_->getFile(selfFile);
if (elfFile != nullptr) {
auto textSection = elfFile->getSectionByName(".text");
base = elfFile->getBaseAddress();
from = textSection->sh_addr;
to = from + textSection->sh_size;
fileName = selfFile;
first = false; // no need to get this file again from the cache
}
}
// See if any addresses are here // See if any addresses are here
for (size_t i = 0; i < addressCount; ++i) { for (size_t i = 0; i < addressCount; ++i) {
auto& frame = frames[i]; auto& frame = frames[i];
...@@ -244,6 +288,12 @@ void Symbolizer::symbolize(const uintptr_t* addresses, ...@@ -244,6 +288,12 @@ void Symbolizer::symbolize(const uintptr_t* addresses,
if (first) { if (first) {
first = false; first = false;
elfFile = cache_->getFile(fileName); elfFile = cache_->getFile(fileName);
// Need to get the correct base address as from
// when fileOff > 0
if (fileOff && elfFile != nullptr) {
base = elfFile->getBaseAddress();
}
} }
if (!elfFile) { if (!elfFile) {
...@@ -251,7 +301,7 @@ void Symbolizer::symbolize(const uintptr_t* addresses, ...@@ -251,7 +301,7 @@ void Symbolizer::symbolize(const uintptr_t* addresses,
} }
// Undo relocation // Undo relocation
frame.set(elfFile, address - from); frame.set(elfFile, address - base);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment