Commit 3272dfdb authored by Mark Williams's avatar Mark Williams Committed by Facebook Github Bot 2

Make ElfCache follow .gnu_debuglink

Summary:
If you split out debug info into a separate file, folly::Symbolizer
didn't find it, and failed to include file and line number info in
backtraces.

This adds a new open mode which follows the .gnu_debuginfo link, and
uses it from ElfCache and SignalSafeElfCache.

Reviewed By: meyering, luciang

Differential Revision: D3852311

fbshipit-source-id: fec9e57378ae59fa1b82d41a163bb9cfcf9ca23c
parent 9f838616
......@@ -58,8 +58,9 @@ void ElfFile::open(const char* name, bool readOnly) {
}
}
int ElfFile::openNoThrow(const char* name, bool readOnly, const char** msg)
noexcept {
int ElfFile::openNoThrow(const char* name,
bool readOnly,
const char** msg) noexcept {
FOLLY_SAFE_CHECK(fd_ == -1, "File already open");
fd_ = ::open(name, readOnly ? O_RDONLY : O_RDWR);
if (fd_ == -1) {
......@@ -95,6 +96,43 @@ int ElfFile::openNoThrow(const char* name, bool readOnly, const char** msg)
return kSuccess;
}
int ElfFile::openAndFollow(const char* name,
bool readOnly,
const char** msg) noexcept {
auto result = openNoThrow(name, readOnly, msg);
if (!readOnly || result != kSuccess) return result;
/* NOTE .gnu_debuglink specifies only the name of the debugging info file
* (with no directory components). GDB checks 3 different directories, but
* ElfFile only supports the first version:
* - dirname(name)
* - dirname(name) + /.debug/
* - X/dirname(name)/ - where X is set in gdb's `debug-file-directory`.
*/
auto dirend = strrchr(name, '/');
// include ending '/' if any.
auto dirlen = dirend != nullptr ? dirend + 1 - name : 0;
auto debuginfo = getSectionByName(".gnu_debuglink");
if (!debuginfo) return result;
// The section starts with the filename, with any leading directory
// components removed, followed by a zero byte.
auto debugFileName = getSectionBody(*debuginfo);
auto debugFileLen = strlen(debugFileName.begin());
if (dirlen + debugFileLen >= PATH_MAX) {
return result;
}
char linkname[PATH_MAX];
memcpy(linkname, name, dirlen);
memcpy(linkname + dirlen, debugFileName.begin(), debugFileLen + 1);
reset();
result = openNoThrow(linkname, readOnly, msg);
if (result == kSuccess) return result;
return openNoThrow(name, readOnly, msg);
}
ElfFile::~ElfFile() {
reset();
}
......
......@@ -58,9 +58,14 @@ class ElfFile {
kSystemError = -1,
kInvalidElfFile = -2,
};
// Open the ELF file. Does not throw on error.
int openNoThrow(const char* name, bool readOnly=true,
const char** msg=nullptr) noexcept;
// Like openNoThrow, but follow .gnu_debuglink if present
int openAndFollow(const char* name, bool readOnly=true,
const char** msg=nullptr) noexcept;
// Open the ELF file. Throws on error.
void open(const char* name, bool readOnly=true);
......
......@@ -48,7 +48,7 @@ std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) {
auto& f = slots_[n];
const char* msg = "";
int r = f->openNoThrow(path.data(), true, &msg);
int r = f->openAndFollow(path.data(), true, &msg);
if (r != ElfFile::kSuccess) {
return nullptr;
}
......@@ -77,7 +77,7 @@ std::shared_ptr<ElfFile> ElfCache::getFile(StringPiece p) {
// No negative caching
const char* msg = "";
int r = entry->file.openNoThrow(path.c_str(), true, &msg);
int r = entry->file.openAndFollow(path.c_str(), true, &msg);
if (r != ElfFile::kSuccess) {
return nullptr;
}
......
#!/bin/bash
crash="$1"
rm -f "$crash."{debuginfo,strip}
objcopy --only-keep-debug "$crash" "$crash.debuginfo"
objcopy --strip-debug --add-gnu-debuglink="$crash.debuginfo" "$crash" "$crash.strip"
echo '{"op":"start","test":"gnu_debuglink_test"}';
start=$(date +%s)
if "$crash.strip" 2>&1 | grep 'Crash.cpp:[0-9]*$' > /dev/null; then
result='"status":"passed"';
else
result='"status":"failed"';
fi
end=$(date +%s)
echo '{"op":"test_done","test":"gnu_debuglink_test",'"$result"'}'
echo '{"op":"all_done","results":[{"name":"gnu_debuglink_test",'"$result"',"start_time":'"$start"',"end_time":'"$end"',"details":"nothing"}]}'
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