init();
}
-Dwarf::Section::Section(folly::StringPiece d) : is64Bit_(false), data_(d) {
-}
+Dwarf::Section::Section(folly::StringPiece d) : is64Bit_(false), data_(d) {}
namespace {
// Read (bitwise) one object of type T
template <class T>
-typename std::enable_if<std::is_pod<T>::value, T>::type
-read(folly::StringPiece& sp) {
+typename std::enable_if<std::is_pod<T>::value, T>::type read(
+ folly::StringPiece& sp) {
FOLLY_SAFE_CHECK(sp.size() >= sizeof(T), "underflow");
T x;
memcpy(&x, sp.data(), sizeof(T));
uint64_t r = readULEB(sp, shift, val);
if (shift < 64 && (val & 0x40)) {
- r |= -(1ULL << shift); // sign extend
+ r |= -(1ULL << shift); // sign extend
}
return r;
// Read a null-terminated string
folly::StringPiece readNullTerminated(folly::StringPiece& sp) {
- const char* p = static_cast<const char*>(
- memchr(sp.data(), 0, sp.size()));
+ const char* p = static_cast<const char*>(memchr(sp.data(), 0, sp.size()));
FOLLY_SAFE_CHECK(p, "invalid null-terminated string");
folly::StringPiece ret(sp.data(), p);
sp.assign(p + 1, sp.end());
}
// Strip trailing slashes, except when this is the root path.
- while (sp.size() > 1 && sp.removeSuffix('/')) { }
+ while (sp.size() > 1 && sp.removeSuffix('/')) {
+ }
if (sp.removeSuffix("/.")) {
continue;
}
}
-} // namespace
+} // namespace
-Dwarf::Path::Path(folly::StringPiece baseDir, folly::StringPiece subDir,
- folly::StringPiece file)
- : baseDir_(baseDir),
- subDir_(subDir),
- file_(file) {
+Dwarf::Path::Path(
+ folly::StringPiece baseDir,
+ folly::StringPiece subDir,
+ folly::StringPiece file)
+ : baseDir_(baseDir), subDir_(subDir), file_(file) {
using std::swap;
// Normalize
}
if (!subDir_.empty() && subDir_[0] == '/') {
- baseDir_.clear(); // subDir_ is absolute
+ baseDir_.clear(); // subDir_ is absolute
}
simplifyPath(baseDir_);
size_t totalSize = 0;
bool needsSlash = false;
- auto append = [&] (folly::StringPiece sp) {
+ auto append = [&](folly::StringPiece sp) {
if (bufSize >= 2) {
size_t toCopy = std::min(sp.size(), bufSize - 1);
memcpy(buf, sp.data(), toCopy);
getSection(".debug_aranges", &aranges_);
}
-bool Dwarf::readAbbreviation(folly::StringPiece& section,
- DIEAbbreviation& abbr) {
+bool Dwarf::readAbbreviation(
+ folly::StringPiece& section,
+ DIEAbbreviation& abbr) {
// abbreviation code
abbr.code = readULEB(section);
if (abbr.code == 0) {
return true;
}
-Dwarf::DIEAbbreviation::Attribute Dwarf::readAttribute(
- folly::StringPiece& sp) {
- return { readULEB(sp), readULEB(sp) };
+Dwarf::DIEAbbreviation::Attribute Dwarf::readAttribute(folly::StringPiece& sp) {
+ return {readULEB(sp), readULEB(sp)};
}
Dwarf::DIEAbbreviation Dwarf::getAbbreviation(uint64_t code, uint64_t offset)
- const {
+ const {
// Linear search in the .debug_abbrev section, starting at offset
folly::StringPiece section = abbrev_;
section.advance(offset);
}
Dwarf::AttributeValue Dwarf::readAttributeValue(
- folly::StringPiece& sp, uint64_t form, bool is64Bit) const {
+ folly::StringPiece& sp,
+ uint64_t form,
+ bool is64Bit) const {
switch (form) {
- case DW_FORM_addr:
- return read<uintptr_t>(sp);
- case DW_FORM_block1:
- return readBytes(sp, read<uint8_t>(sp));
- case DW_FORM_block2:
- return readBytes(sp, read<uint16_t>(sp));
- case DW_FORM_block4:
- return readBytes(sp, read<uint32_t>(sp));
- case DW_FORM_block: // fallthrough
- case DW_FORM_exprloc:
- return readBytes(sp, readULEB(sp));
- case DW_FORM_data1: // fallthrough
- case DW_FORM_ref1:
- return read<uint8_t>(sp);
- case DW_FORM_data2: // fallthrough
- case DW_FORM_ref2:
- return read<uint16_t>(sp);
- case DW_FORM_data4: // fallthrough
- case DW_FORM_ref4:
- return read<uint32_t>(sp);
- case DW_FORM_data8: // fallthrough
- case DW_FORM_ref8:
- return read<uint64_t>(sp);
- case DW_FORM_sdata:
- return readSLEB(sp);
- case DW_FORM_udata: // fallthrough
- case DW_FORM_ref_udata:
- return readULEB(sp);
- case DW_FORM_flag:
- return read<uint8_t>(sp);
- case DW_FORM_flag_present:
- return 1;
- case DW_FORM_sec_offset: // fallthrough
- case DW_FORM_ref_addr:
- return readOffset(sp, is64Bit);
- case DW_FORM_string:
- return readNullTerminated(sp);
- case DW_FORM_strp:
- return getStringFromStringSection(readOffset(sp, is64Bit));
- case DW_FORM_indirect: // form is explicitly specified
- return readAttributeValue(sp, readULEB(sp), is64Bit);
- default:
- FOLLY_SAFE_CHECK(false, "invalid attribute form");
+ case DW_FORM_addr:
+ return read<uintptr_t>(sp);
+ case DW_FORM_block1:
+ return readBytes(sp, read<uint8_t>(sp));
+ case DW_FORM_block2:
+ return readBytes(sp, read<uint16_t>(sp));
+ case DW_FORM_block4:
+ return readBytes(sp, read<uint32_t>(sp));
+ case DW_FORM_block: // fallthrough
+ case DW_FORM_exprloc:
+ return readBytes(sp, readULEB(sp));
+ case DW_FORM_data1: // fallthrough
+ case DW_FORM_ref1:
+ return read<uint8_t>(sp);
+ case DW_FORM_data2: // fallthrough
+ case DW_FORM_ref2:
+ return read<uint16_t>(sp);
+ case DW_FORM_data4: // fallthrough
+ case DW_FORM_ref4:
+ return read<uint32_t>(sp);
+ case DW_FORM_data8: // fallthrough
+ case DW_FORM_ref8:
+ return read<uint64_t>(sp);
+ case DW_FORM_sdata:
+ return readSLEB(sp);
+ case DW_FORM_udata: // fallthrough
+ case DW_FORM_ref_udata:
+ return readULEB(sp);
+ case DW_FORM_flag:
+ return read<uint8_t>(sp);
+ case DW_FORM_flag_present:
+ return 1;
+ case DW_FORM_sec_offset: // fallthrough
+ case DW_FORM_ref_addr:
+ return readOffset(sp, is64Bit);
+ case DW_FORM_string:
+ return readNullTerminated(sp);
+ case DW_FORM_strp:
+ return getStringFromStringSection(readOffset(sp, is64Bit));
+ case DW_FORM_indirect: // form is explicitly specified
+ return readAttributeValue(sp, readULEB(sp), is64Bit);
+ default:
+ FOLLY_SAFE_CHECK(false, "invalid attribute form");
}
}
* Find @address in .debug_aranges and return the offset in
* .debug_info for compilation unit to which this address belongs.
*/
-bool Dwarf::findDebugInfoOffset(uintptr_t address,
- StringPiece aranges,
- uint64_t& offset) {
+bool Dwarf::findDebugInfoOffset(
+ uintptr_t address,
+ StringPiece aranges,
+ uint64_t& offset) {
Section arangesSection(aranges);
folly::StringPiece chunk;
while (arangesSection.next(chunk)) {
* Returns whether the address was found.
* Advances @sp to the next entry in .debug_info.
*/
-bool Dwarf::findLocation(uintptr_t address,
- StringPiece& infoEntry,
- LocationInfo& locationInfo) const {
+bool Dwarf::findLocation(
+ uintptr_t address,
+ StringPiece& infoEntry,
+ LocationInfo& locationInfo) const {
// For each compilation unit compiled with a DWARF producer, a
// contribution is made to the .debug_info section of the object
// file. Each such contribution consists of a compilation unit
auto code = readULEB(chunk);
FOLLY_SAFE_CHECK(code != 0, "invalid code");
auto abbr = getAbbreviation(code, abbrevOffset);
- FOLLY_SAFE_CHECK(abbr.tag == DW_TAG_compile_unit,
- "expecting compile unit entry");
+ FOLLY_SAFE_CHECK(
+ abbr.tag == DW_TAG_compile_unit, "expecting compile unit entry");
// Skip children entries, advance to the next compilation unit entry.
infoEntry.advance(chunk.end() - infoEntry.begin());
if (attr.name == 0 && attr.form == 0) {
break;
}
- auto val = readAttributeValue(chunk, attr.form,
- debugInfoSection.is64Bit());
+ auto val = readAttributeValue(chunk, attr.form, debugInfoSection.is64Bit());
switch (attr.name) {
- case DW_AT_stmt_list:
- // Offset in .debug_line for the line number VM program for this
- // compilation unit
- lineOffset = boost::get<uint64_t>(val);
- foundLineOffset = true;
- break;
- case DW_AT_comp_dir:
- // Compilation directory
- compilationDirectory = boost::get<folly::StringPiece>(val);
- break;
- case DW_AT_name:
- // File name of main file being compiled
- mainFileName = boost::get<folly::StringPiece>(val);
- break;
+ case DW_AT_stmt_list:
+ // Offset in .debug_line for the line number VM program for this
+ // compilation unit
+ lineOffset = boost::get<uint64_t>(val);
+ foundLineOffset = true;
+ break;
+ case DW_AT_comp_dir:
+ // Compilation directory
+ compilationDirectory = boost::get<folly::StringPiece>(val);
+ break;
+ case DW_AT_name:
+ // File name of main file being compiled
+ mainFileName = boost::get<folly::StringPiece>(val);
+ break;
}
}
return locationInfo.hasFileAndLine;
}
-bool Dwarf::findAddress(uintptr_t address,
- LocationInfo& locationInfo,
- LocationInfoMode mode) const {
+bool Dwarf::findAddress(
+ uintptr_t address,
+ LocationInfo& locationInfo,
+ LocationInfoMode mode) const {
locationInfo = LocationInfo();
if (mode == LocationInfoMode::DISABLED) {
}
}
-
// Slow path (linear scan): Iterate over all .debug_info entries
// and look for the address in each compilation unit.
folly::StringPiece infoEntry(info_);
return locationInfo.hasFileAndLine;
}
-Dwarf::LineNumberVM::LineNumberVM(folly::StringPiece data,
- folly::StringPiece compilationDirectory)
- : compilationDirectory_(compilationDirectory) {
+Dwarf::LineNumberVM::LineNumberVM(
+ folly::StringPiece data,
+ folly::StringPiece compilationDirectory)
+ : compilationDirectory_(compilationDirectory) {
Section section(data);
FOLLY_SAFE_CHECK(section.next(data_), "invalid line number VM");
is64Bit_ = section.is64Bit();
void Dwarf::LineNumberVM::init() {
version_ = read<uint16_t>(data_);
- FOLLY_SAFE_CHECK(version_ >= 2 && version_ <= 4,
- "invalid version in line number VM");
+ FOLLY_SAFE_CHECK(
+ version_ >= 2 && version_ <= 4, "invalid version in line number VM");
uint64_t headerLength = readOffset(data_, is64Bit_);
- FOLLY_SAFE_CHECK(headerLength <= data_.size(),
- "invalid line number VM header length");
+ FOLLY_SAFE_CHECK(
+ headerLength <= data_.size(), "invalid line number VM header length");
folly::StringPiece header(data_.data(), headerLength);
data_.assign(header.end(), data_.end());
minLength_ = read<uint8_t>(header);
- if (version_ == 4) { // Version 2 and 3 records don't have this
+ if (version_ == 4) { // Version 2 and 3 records don't have this
uint8_t maxOpsPerInstruction = read<uint8_t>(header);
FOLLY_SAFE_CHECK(maxOpsPerInstruction == 1, "VLIW not supported");
}
defaultIsStmt_ = read<uint8_t>(header);
- lineBase_ = read<int8_t>(header); // yes, signed
+ lineBase_ = read<int8_t>(header); // yes, signed
lineRange_ = read<uint8_t>(header);
opcodeBase_ = read<uint8_t>(header);
FOLLY_SAFE_CHECK(opcodeBase_ != 0, "invalid opcode base");
return (ret == COMMIT);
}
-Dwarf::LineNumberVM::FileName Dwarf::LineNumberVM::getFileName(uint64_t index)
- const {
+Dwarf::LineNumberVM::FileName Dwarf::LineNumberVM::getFileName(
+ uint64_t index) const {
FOLLY_SAFE_CHECK(index != 0, "invalid file index 0");
FileName fn;
return fn;
}
-folly::StringPiece Dwarf::LineNumberVM::getIncludeDirectory(uint64_t index)
- const {
+folly::StringPiece Dwarf::LineNumberVM::getIncludeDirectory(
+ uint64_t index) const {
if (index == 0) {
return folly::StringPiece();
}
- FOLLY_SAFE_CHECK(index <= includeDirectoryCount_,
- "invalid include directory");
+ FOLLY_SAFE_CHECK(
+ index <= includeDirectoryCount_, "invalid include directory");
folly::StringPiece includeDirectories = includeDirectories_;
folly::StringPiece dir;
for (; index; --index) {
dir = readNullTerminated(includeDirectories);
if (dir.empty()) {
- abort(); // BUG
+ abort(); // BUG
}
}
return dir;
}
-bool Dwarf::LineNumberVM::readFileName(folly::StringPiece& program,
- FileName& fn) {
+bool Dwarf::LineNumberVM::readFileName(
+ folly::StringPiece& program,
+ FileName& fn) {
fn.relativeName = readNullTerminated(program);
if (fn.relativeName.empty()) {
return false;
return true;
}
-bool Dwarf::LineNumberVM::nextDefineFile(folly::StringPiece& program,
- FileName& fn) const {
+bool Dwarf::LineNumberVM::nextDefineFile(
+ folly::StringPiece& program,
+ FileName& fn) const {
while (!program.empty()) {
auto opcode = read<uint8_t>(program);
- if (opcode >= opcodeBase_) { // special opcode
+ if (opcode >= opcodeBase_) { // special opcode
continue;
}
- if (opcode != 0) { // standard opcode
+ if (opcode != 0) { // standard opcode
// Skip, slurp the appropriate number of LEB arguments
uint8_t argCount = standardOpcodeLengths_[opcode - 1];
while (argCount--) {
--length;
if (opcode == DW_LNE_define_file) {
- FOLLY_SAFE_CHECK(readFileName(program, fn),
- "invalid empty file in DW_LNE_define_file");
+ FOLLY_SAFE_CHECK(
+ readFileName(program, fn),
+ "invalid empty file in DW_LNE_define_file");
return true;
}
folly::StringPiece& program) {
auto opcode = read<uint8_t>(program);
- if (opcode >= opcodeBase_) { // special opcode
+ if (opcode >= opcodeBase_) { // special opcode
uint8_t adjustedOpcode = opcode - opcodeBase_;
uint8_t opAdvance = adjustedOpcode / lineRange_;
return COMMIT;
}
- if (opcode != 0) { // standard opcode
+ if (opcode != 0) { // standard opcode
// Only interpret opcodes that are recognized by the version we're parsing;
// the others are vendor extensions and we should ignore them.
switch (opcode) {
- case DW_LNS_copy:
- basicBlock_ = false;
- prologueEnd_ = false;
- epilogueBegin_ = false;
- discriminator_ = 0;
- return COMMIT;
- case DW_LNS_advance_pc:
- address_ += minLength_ * readULEB(program);
- return CONTINUE;
- case DW_LNS_advance_line:
- line_ += readSLEB(program);
- return CONTINUE;
- case DW_LNS_set_file:
- file_ = readULEB(program);
- return CONTINUE;
- case DW_LNS_set_column:
- column_ = readULEB(program);
- return CONTINUE;
- case DW_LNS_negate_stmt:
- isStmt_ = !isStmt_;
- return CONTINUE;
- case DW_LNS_set_basic_block:
- basicBlock_ = true;
- return CONTINUE;
- case DW_LNS_const_add_pc:
- address_ += minLength_ * ((255 - opcodeBase_) / lineRange_);
- return CONTINUE;
- case DW_LNS_fixed_advance_pc:
- address_ += read<uint16_t>(program);
- return CONTINUE;
- case DW_LNS_set_prologue_end:
- if (version_ == 2) break; // not supported in version 2
- prologueEnd_ = true;
- return CONTINUE;
- case DW_LNS_set_epilogue_begin:
- if (version_ == 2) break; // not supported in version 2
- epilogueBegin_ = true;
- return CONTINUE;
- case DW_LNS_set_isa:
- if (version_ == 2) break; // not supported in version 2
- isa_ = readULEB(program);
- return CONTINUE;
+ case DW_LNS_copy:
+ basicBlock_ = false;
+ prologueEnd_ = false;
+ epilogueBegin_ = false;
+ discriminator_ = 0;
+ return COMMIT;
+ case DW_LNS_advance_pc:
+ address_ += minLength_ * readULEB(program);
+ return CONTINUE;
+ case DW_LNS_advance_line:
+ line_ += readSLEB(program);
+ return CONTINUE;
+ case DW_LNS_set_file:
+ file_ = readULEB(program);
+ return CONTINUE;
+ case DW_LNS_set_column:
+ column_ = readULEB(program);
+ return CONTINUE;
+ case DW_LNS_negate_stmt:
+ isStmt_ = !isStmt_;
+ return CONTINUE;
+ case DW_LNS_set_basic_block:
+ basicBlock_ = true;
+ return CONTINUE;
+ case DW_LNS_const_add_pc:
+ address_ += minLength_ * ((255 - opcodeBase_) / lineRange_);
+ return CONTINUE;
+ case DW_LNS_fixed_advance_pc:
+ address_ += read<uint16_t>(program);
+ return CONTINUE;
+ case DW_LNS_set_prologue_end:
+ if (version_ == 2) {
+ break; // not supported in version 2
+ }
+ prologueEnd_ = true;
+ return CONTINUE;
+ case DW_LNS_set_epilogue_begin:
+ if (version_ == 2) {
+ break; // not supported in version 2
+ }
+ epilogueBegin_ = true;
+ return CONTINUE;
+ case DW_LNS_set_isa:
+ if (version_ == 2) {
+ break; // not supported in version 2
+ }
+ isa_ = readULEB(program);
+ return CONTINUE;
}
// Unrecognized standard opcode, slurp the appropriate number of LEB
--length;
switch (extendedOpcode) {
- case DW_LNE_end_sequence:
- return END;
- case DW_LNE_set_address:
- address_ = read<uintptr_t>(program);
- return CONTINUE;
- case DW_LNE_define_file:
- // We can't process DW_LNE_define_file here, as it would require us to
- // use unbounded amounts of state (ie. use the heap). We'll do a second
- // pass (using nextDefineFile()) if necessary.
- break;
- case DW_LNE_set_discriminator:
- discriminator_ = readULEB(program);
- return CONTINUE;
+ case DW_LNE_end_sequence:
+ return END;
+ case DW_LNE_set_address:
+ address_ = read<uintptr_t>(program);
+ return CONTINUE;
+ case DW_LNE_define_file:
+ // We can't process DW_LNE_define_file here, as it would require us to
+ // use unbounded amounts of state (ie. use the heap). We'll do a second
+ // pass (using nextDefineFile()) if necessary.
+ break;
+ case DW_LNE_set_discriminator:
+ discriminator_ = readULEB(program);
+ return CONTINUE;
}
// Unrecognized extended opcode
return CONTINUE;
}
-bool Dwarf::LineNumberVM::findAddress(uintptr_t target, Path& file,
- uint64_t& line) {
+bool Dwarf::LineNumberVM::findAddress(
+ uintptr_t target,
+ Path& file,
+ uint64_t& line) {
folly::StringPiece program = data_;
// Within each sequence of instructions, the address may only increase.
// a candidate crosses the target address.
enum State {
START,
- LOW_SEQ, // candidate
+ LOW_SEQ, // candidate
HIGH_SEQ
};
State state = START;
return false;
}
auto fn = getFileName(prevFile);
- file = Path(compilationDirectory_,
- getIncludeDirectory(fn.directoryIndex),
- fn.relativeName);
+ file = Path(
+ compilationDirectory_,
+ getIncludeDirectory(fn.directoryIndex),
+ fn.relativeName);
line = prevLine;
return true;
}
return false;
}
-} // namespace symbolizer
-} // namespace folly
+} // namespace symbolizer
+} // namespace folly
*/
class Path {
public:
- Path() { }
+ Path() {}
- Path(folly::StringPiece baseDir, folly::StringPiece subDir,
- folly::StringPiece file);
+ Path(
+ folly::StringPiece baseDir,
+ folly::StringPiece subDir,
+ folly::StringPiece file);
- folly::StringPiece baseDir() const { return baseDir_; }
- folly::StringPiece subDir() const { return subDir_; }
- folly::StringPiece file() const { return file_; }
+ folly::StringPiece baseDir() const {
+ return baseDir_;
+ }
+ folly::StringPiece subDir() const {
+ return subDir_;
+ }
+ folly::StringPiece file() const {
+ return file_;
+ }
size_t size() const;
/**
* Find the file and line number information corresponding to address.
*/
- bool findAddress(uintptr_t address,
- LocationInfo& info,
- LocationInfoMode mode) const;
+ bool findAddress(uintptr_t address, LocationInfo& info, LocationInfoMode mode)
+ const;
private:
- static bool findDebugInfoOffset(uintptr_t address,
- StringPiece aranges,
- uint64_t& offset);
+ static bool
+ findDebugInfoOffset(uintptr_t address, StringPiece aranges, uint64_t& offset);
void init();
- bool findLocation(uintptr_t address,
- StringPiece& infoEntry,
- LocationInfo& info) const;
+ bool findLocation(
+ uintptr_t address,
+ StringPiece& infoEntry,
+ LocationInfo& info) const;
const ElfFile* elf_;
// (yes, DWARF-32 and DWARF-64 sections may coexist in the same file)
class Section {
public:
- Section() : is64Bit_(false) { }
+ Section() : is64Bit_(false) {}
explicit Section(folly::StringPiece d);
bool next(folly::StringPiece& chunk);
// Is the current chunk 64 bit?
- bool is64Bit() const { return is64Bit_; }
+ bool is64Bit() const {
+ return is64Bit_;
+ }
private:
// Yes, 32- and 64- bit sections may coexist. Yikes!
// Interpreter for the line number bytecode VM
class LineNumberVM {
public:
- LineNumberVM(folly::StringPiece data,
- folly::StringPiece compilationDirectory);
+ LineNumberVM(
+ folly::StringPiece data,
+ folly::StringPiece compilationDirectory);
bool findAddress(uintptr_t address, Path& file, uint64_t& line);
// Execute until we commit one new row to the line number matrix
bool next(folly::StringPiece& program);
enum StepResult {
- CONTINUE, // Continue feeding opcodes
- COMMIT, // Commit new <address, file, line> tuple
- END, // End of sequence
+ CONTINUE, // Continue feeding opcodes
+ COMMIT, // Commit new <address, file, line> tuple
+ END, // End of sequence
};
// Execute one opcode
StepResult step(folly::StringPiece& program);
// Read one attribute value, advance sp
typedef boost::variant<uint64_t, folly::StringPiece> AttributeValue;
- AttributeValue readAttributeValue(
- folly::StringPiece& sp,
- uint64_t form,
- bool is64Bit) const;
+ AttributeValue
+ readAttributeValue(folly::StringPiece& sp, uint64_t form, bool is64Bit) const;
// Get an ELF section by name, return true if found
bool getSection(const char* name, folly::StringPiece* section) const;
// Get a string from the .debug_str section
folly::StringPiece getStringFromStringSection(uint64_t offset) const;
- folly::StringPiece info_; // .debug_info
- folly::StringPiece abbrev_; // .debug_abbrev
- folly::StringPiece aranges_; // .debug_aranges
- folly::StringPiece line_; // .debug_line
- folly::StringPiece strings_; // .debug_str
+ folly::StringPiece info_; // .debug_info
+ folly::StringPiece abbrev_; // .debug_abbrev
+ folly::StringPiece aranges_; // .debug_aranges
+ folly::StringPiece line_; // .debug_line
+ folly::StringPiece strings_; // .debug_str
};
inline std::ostream& operator<<(std::ostream& out, const Dwarf::Path& path) {
return out << path.toString();
}
-} // namespace symbolizer
-} // namespace folly
+} // namespace symbolizer
+} // namespace folly
* limitations under the License.
*/
-
#ifndef FOLLY_EXPERIMENTAL_SYMBOLIZER_ELF_H_
-# error This file must be included from Elf.h
+#error This file must be included from Elf.h
#endif
namespace folly {
namespace symbolizer {
template <class Fn>
-const ElfW(Shdr)* ElfFile::iterateSections(Fn fn) const {
- const ElfW(Shdr)* ptr = &at<ElfW(Shdr)>(elfHeader().e_shoff);
+const ElfShdr* ElfFile::iterateSections(Fn fn) const {
+ const ElfShdr* ptr = &at<ElfShdr>(elfHeader().e_shoff);
for (size_t i = 0; i < elfHeader().e_shnum; i++, ptr++) {
if (fn(*ptr)) {
return ptr;
}
template <class Fn>
-const ElfW(Shdr)* ElfFile::iterateSectionsWithType(uint32_t type, Fn fn)
- const {
+const ElfShdr* ElfFile::iterateSectionsWithType(uint32_t type, Fn fn) const {
return iterateSections(
- [&](const ElfW(Shdr)& sh) {
- return sh.sh_type == type && fn(sh);
- });
+ [&](const ElfShdr& sh) { return sh.sh_type == type && fn(sh); });
}
template <class Fn>
-const char* ElfFile::iterateStrings(const ElfW(Shdr)& stringTable, Fn fn)
- const {
+const char* ElfFile::iterateStrings(const ElfShdr& stringTable, Fn fn) const {
validateStringTable(stringTable);
const char* start = file_ + stringTable.sh_offset;
}
template <class Fn>
-const ElfW(Sym)* ElfFile::iterateSymbols(const ElfW(Shdr)& section, Fn fn)
- const {
- FOLLY_SAFE_CHECK(section.sh_entsize == sizeof(ElfW(Sym)),
- "invalid entry size in symbol table");
+const ElfSym* ElfFile::iterateSymbols(const ElfShdr& section, Fn fn) const {
+ FOLLY_SAFE_CHECK(
+ section.sh_entsize == sizeof(ElfSym),
+ "invalid entry size in symbol table");
- const ElfW(Sym)* sym = &at<ElfW(Sym)>(section.sh_offset);
- const ElfW(Sym)* end = sym + (section.sh_size / section.sh_entsize);
+ const ElfSym* sym = &at<ElfSym>(section.sh_offset);
+ const ElfSym* end = sym + (section.sh_size / section.sh_entsize);
while (sym < end) {
if (fn(*sym)) {
}
template <class Fn>
-const ElfW(Sym)* ElfFile::iterateSymbolsWithType(const ElfW(Shdr)& section,
- uint32_t type, Fn fn) const {
+const ElfSym* ElfFile::iterateSymbolsWithType(
+ const ElfShdr& section,
+ uint32_t type,
+ Fn fn) const {
// N.B. st_info has the same representation on 32- and 64-bit platforms
- return iterateSymbols(section, [&](const ElfW(Sym)& sym) -> bool {
+ return iterateSymbols(section, [&](const ElfSym& sym) -> bool {
return ELF32_ST_TYPE(sym.st_info) == type && fn(sym);
});
}
-} // namespace symbolizer
-} // namespace folly
+} // namespace symbolizer
+} // namespace folly
namespace symbolizer {
ElfFile::ElfFile() noexcept
- : fd_(-1),
- file_(static_cast<char*>(MAP_FAILED)),
- length_(0),
- baseAddress_(0) {
-}
+ : fd_(-1),
+ file_(static_cast<char*>(MAP_FAILED)),
+ length_(0),
+ baseAddress_(0) {}
ElfFile::ElfFile(const char* name, bool readOnly)
- : fd_(-1),
- file_(static_cast<char*>(MAP_FAILED)),
- length_(0),
- baseAddress_(0) {
+ : fd_(-1),
+ file_(static_cast<char*>(MAP_FAILED)),
+ length_(0),
+ baseAddress_(0) {
open(name, 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) {
- if (msg) *msg = "open";
+ if (msg) {
+ *msg = "open";
+ }
return kSystemError;
}
// Always close fd and unmap in case of failure along the way to avoid
// check failure above if we leave fd != -1 and the object is recycled
// like it is inside SignalSafeElfCache
- ScopeGuard guard = makeGuard([&]{ reset(); });
+ ScopeGuard guard = makeGuard([&] { reset(); });
struct stat st;
int r = fstat(fd_, &st);
if (r == -1) {
- if (msg) *msg = "fstat";
+ if (msg) {
+ *msg = "fstat";
+ }
return kSystemError;
}
}
file_ = static_cast<char*>(mmap(nullptr, length_, prot, MAP_SHARED, fd_, 0));
if (file_ == MAP_FAILED) {
- if (msg) *msg = "mmap";
+ if (msg) {
+ *msg = "mmap";
+ }
return kSystemError;
}
if (!init(msg)) {
return kSuccess;
}
-int ElfFile::openAndFollow(const char* name,
- bool readOnly,
- const char** msg) noexcept {
+int ElfFile::openAndFollow(
+ const char* name,
+ bool readOnly,
+ const char** msg) noexcept {
auto result = openNoThrow(name, readOnly, msg);
- if (!readOnly || result != kSuccess) return result;
+ 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
auto dirlen = dirend != nullptr ? dirend + 1 - name : 0;
auto debuginfo = getSectionByName(".gnu_debuglink");
- if (!debuginfo) return result;
+ if (!debuginfo) {
+ return result;
+ }
// The section starts with the filename, with any leading directory
// components removed, followed by a zero byte.
memcpy(linkname + dirlen, debugFileName.begin(), debugFileLen + 1);
reset();
result = openNoThrow(linkname, readOnly, msg);
- if (result == kSuccess) return result;
+ if (result == kSuccess) {
+ return result;
+ }
return openNoThrow(name, readOnly, msg);
}
}
ElfFile::ElfFile(ElfFile&& other) noexcept
- : fd_(other.fd_),
- file_(other.file_),
- length_(other.length_),
- baseAddress_(other.baseAddress_) {
+ : fd_(other.fd_),
+ file_(other.file_),
+ length_(other.length_),
+ baseAddress_(other.baseAddress_) {
other.fd_ = -1;
other.file_ = static_cast<char*>(MAP_FAILED);
other.length_ = 0;
elfHeader.e_ident[EI_MAG1] == ELFMAG1 &&
elfHeader.e_ident[EI_MAG2] == ELFMAG2 &&
elfHeader.e_ident[EI_MAG3] == ELFMAG3)) {
- if (msg) *msg = "invalid ELF magic";
+ if (msg) {
+ *msg = "invalid ELF magic";
+ }
return false;
}
- // Validate ELF class (32/64 bits)
#define EXPECTED_CLASS P1(ELFCLASS, __ELF_NATIVE_CLASS)
#define P1(a, b) P2(a, b)
-#define P2(a, b) a ## b
+#define P2(a, b) a##b
+ // Validate ELF class (32/64 bits)
if (elfHeader.e_ident[EI_CLASS] != EXPECTED_CLASS) {
- if (msg) *msg = "invalid ELF class";
+ if (msg) {
+ *msg = "invalid ELF class";
+ }
return false;
}
#undef P1
static constexpr auto kExpectedEncoding =
kIsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;
if (elfHeader.e_ident[EI_DATA] != kExpectedEncoding) {
- if (msg) *msg = "invalid ELF encoding";
+ if (msg) {
+ *msg = "invalid ELF encoding";
+ }
return false;
}
// Validate ELF version (1)
if (elfHeader.e_ident[EI_VERSION] != EV_CURRENT ||
elfHeader.e_version != EV_CURRENT) {
- if (msg) *msg = "invalid ELF version";
+ if (msg) {
+ *msg = "invalid ELF version";
+ }
return false;
}
// We only support executable and shared object files
if (elfHeader.e_type != ET_EXEC && elfHeader.e_type != ET_DYN) {
- if (msg) *msg = "invalid ELF file type";
+ if (msg) {
+ *msg = "invalid ELF file type";
+ }
return false;
}
if (elfHeader.e_phnum == 0) {
- if (msg) *msg = "no program header!";
+ if (msg) {
+ *msg = "no program header!";
+ }
return false;
}
- if (elfHeader.e_phentsize != sizeof(ElfW(Phdr))) {
- if (msg) *msg = "invalid program header entry size";
+ if (elfHeader.e_phentsize != sizeof(ElfPhdr)) {
+ if (msg) {
+ *msg = "invalid program header entry size";
+ }
return false;
}
- if (elfHeader.e_shentsize != sizeof(ElfW(Shdr))) {
- if (msg) *msg = "invalid section header entry size";
+ if (elfHeader.e_shentsize != sizeof(ElfShdr)) {
+ if (msg) {
+ *msg = "invalid section header entry size";
+ }
}
- const ElfW(Phdr)* programHeader = &at<ElfW(Phdr)>(elfHeader.e_phoff);
+ const ElfPhdr* programHeader = &at<ElfPhdr>(elfHeader.e_phoff);
bool foundBase = false;
for (size_t i = 0; i < elfHeader.e_phnum; programHeader++, i++) {
// Program headers are sorted by load address, so the first PT_LOAD
}
if (!foundBase) {
- if (msg) *msg = "could not find base address";
+ if (msg) {
+ *msg = "could not find base address";
+ }
return false;
}
return true;
}
-const ElfW(Shdr)* ElfFile::getSectionByIndex(size_t idx) const {
+const ElfShdr* ElfFile::getSectionByIndex(size_t idx) const {
FOLLY_SAFE_CHECK(idx < elfHeader().e_shnum, "invalid section index");
- return &at<ElfW(Shdr)>(elfHeader().e_shoff + idx * sizeof(ElfW(Shdr)));
+ return &at<ElfShdr>(elfHeader().e_shoff + idx * sizeof(ElfShdr));
}
-folly::StringPiece ElfFile::getSectionBody(const ElfW(Shdr)& section) const {
+folly::StringPiece ElfFile::getSectionBody(const ElfShdr& section) const {
return folly::StringPiece(file_ + section.sh_offset, section.sh_size);
}
-void ElfFile::validateStringTable(const ElfW(Shdr)& stringTable) const {
- FOLLY_SAFE_CHECK(stringTable.sh_type == SHT_STRTAB,
- "invalid type for string table");
+void ElfFile::validateStringTable(const ElfShdr& stringTable) const {
+ FOLLY_SAFE_CHECK(
+ stringTable.sh_type == SHT_STRTAB, "invalid type for string table");
const char* start = file_ + stringTable.sh_offset;
// First and last bytes must be 0
- FOLLY_SAFE_CHECK(stringTable.sh_size == 0 ||
- (start[0] == '\0' && start[stringTable.sh_size - 1] == '\0'),
- "invalid string table");
+ FOLLY_SAFE_CHECK(
+ stringTable.sh_size == 0 ||
+ (start[0] == '\0' && start[stringTable.sh_size - 1] == '\0'),
+ "invalid string table");
}
-const char* ElfFile::getString(const ElfW(Shdr)& stringTable, size_t offset)
- const {
+const char* ElfFile::getString(const ElfShdr& stringTable, size_t offset)
+ const {
validateStringTable(stringTable);
- FOLLY_SAFE_CHECK(offset < stringTable.sh_size,
- "invalid offset in string table");
+ FOLLY_SAFE_CHECK(
+ offset < stringTable.sh_size, "invalid offset in string table");
return file_ + stringTable.sh_offset + offset;
}
-const char* ElfFile::getSectionName(const ElfW(Shdr)& section) const {
+const char* ElfFile::getSectionName(const ElfShdr& section) const {
if (elfHeader().e_shstrndx == SHN_UNDEF) {
- return nullptr; // no section name string table
+ return nullptr; // no section name string table
}
- const ElfW(Shdr)& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
+ const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
return getString(sectionNames, section.sh_name);
}
-const ElfW(Shdr)* ElfFile::getSectionByName(const char* name) const {
+const ElfShdr* ElfFile::getSectionByName(const char* name) const {
if (elfHeader().e_shstrndx == SHN_UNDEF) {
- return nullptr; // no section name string table
+ return nullptr; // no section name string table
}
// Find offset in the section name string table of the requested name
- const ElfW(Shdr)& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
+ const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
const char* foundName = iterateStrings(
- sectionNames,
- [&] (const char* s) { return !strcmp(name, s); });
+ sectionNames, [&](const char* s) { return !strcmp(name, s); });
if (foundName == nullptr) {
return nullptr;
}
size_t offset = foundName - (file_ + sectionNames.sh_offset);
// Find section with the appropriate sh_name offset
- const ElfW(Shdr)* foundSection = iterateSections(
- [&](const ElfW(Shdr)& sh) {
- if (sh.sh_name == offset) {
- return true;
- }
- return false;
- });
+ const ElfShdr* foundSection = iterateSections([&](const ElfShdr& sh) {
+ if (sh.sh_name == offset) {
+ return true;
+ }
+ return false;
+ });
return foundSection;
}
ElfFile::Symbol ElfFile::getDefinitionByAddress(uintptr_t address) const {
- Symbol foundSymbol {nullptr, nullptr};
+ Symbol foundSymbol{nullptr, nullptr};
- auto findSection = [&](const ElfW(Shdr)& section) {
- auto findSymbols = [&](const ElfW(Sym)& sym) {
+ auto findSection = [&](const ElfShdr& section) {
+ auto findSymbols = [&](const ElfSym& sym) {
if (sym.st_shndx == SHN_UNDEF) {
- return false; // not a definition
+ return false; // not a definition
}
if (address >= sym.st_value && address < sym.st_value + sym.st_size) {
foundSymbol.first = §ion;
};
return iterateSymbolsWithType(section, STT_OBJECT, findSymbols) ||
- iterateSymbolsWithType(section, STT_FUNC, findSymbols);
+ iterateSymbolsWithType(section, STT_FUNC, findSymbols);
};
// Try the .dynsym section first if it exists, it's smaller.
ElfFile::Symbol ElfFile::getSymbolByName(const char* name) const {
Symbol foundSymbol{nullptr, nullptr};
- auto findSection = [&](const ElfW(Shdr)& section) -> bool {
+ auto findSection = [&](const ElfShdr& section) -> bool {
// This section has no string table associated w/ its symbols; hence we
// can't get names for them
if (section.sh_link == SHN_UNDEF) {
return false;
}
- auto findSymbols = [&](const ElfW(Sym)& sym) -> bool {
+ auto findSymbols = [&](const ElfSym& sym) -> bool {
if (sym.st_shndx == SHN_UNDEF) {
- return false; // not a definition
+ return false; // not a definition
}
if (sym.st_name == 0) {
- return false; // no name for this symbol
+ return false; // no name for this symbol
}
- const char* sym_name = getString(
- *getSectionByIndex(section.sh_link), sym.st_name);
+ const char* sym_name =
+ getString(*getSectionByIndex(section.sh_link), sym.st_name);
if (strcmp(sym_name, name) == 0) {
foundSymbol.first = §ion;
foundSymbol.second = &sym;
};
return iterateSymbolsWithType(section, STT_OBJECT, findSymbols) ||
- iterateSymbolsWithType(section, STT_FUNC, findSymbols);
+ iterateSymbolsWithType(section, STT_FUNC, findSymbols);
};
// Try the .dynsym section first if it exists, it's smaller.
iterateSectionsWithType(SHT_DYNSYM, findSection) ||
- iterateSectionsWithType(SHT_SYMTAB, findSection);
+ iterateSectionsWithType(SHT_SYMTAB, findSection);
return foundSymbol;
}
-const ElfW(Shdr)* ElfFile::getSectionContainingAddress(ElfW(Addr) addr) const {
- return iterateSections([&](const ElfW(Shdr)& sh) -> bool {
+const ElfShdr* ElfFile::getSectionContainingAddress(ElfAddr addr) const {
+ return iterateSections([&](const ElfShdr& sh) -> bool {
return (addr >= sh.sh_addr) && (addr < (sh.sh_addr + sh.sh_size));
});
}
}
if (symbol.second->st_name == 0) {
- return nullptr; // symbol has no name
+ return nullptr; // symbol has no name
}
if (symbol.first->sh_link == SHN_UNDEF) {
- return nullptr; // symbol table has no strings
+ return nullptr; // symbol table has no strings
}
- return getString(*getSectionByIndex(symbol.first->sh_link),
- symbol.second->st_name);
+ return getString(
+ *getSectionByIndex(symbol.first->sh_link), symbol.second->st_name);
}
-} // namespace symbolizer
-} // namespace folly
+} // namespace symbolizer
+} // namespace folly
namespace folly {
namespace symbolizer {
+using ElfAddr = ElfW(Addr);
+using ElfEhdr = ElfW(Ehdr);
+using ElfOff = ElfW(Off);
+using ElfPhdr = ElfW(Phdr);
+using ElfShdr = ElfW(Shdr);
+using ElfSym = ElfW(Sym);
+
/**
* ELF file parser.
*
ElfFile() noexcept;
// Note: may throw, call openNoThrow() explicitly if you don't want to throw
- explicit ElfFile(const char* name, bool readOnly=true);
+ explicit ElfFile(const char* name, bool readOnly = true);
// Open the ELF file.
// Returns 0 on success, kSystemError (guaranteed to be -1) (and sets errno)
kInvalidElfFile = -2,
};
// Open the ELF file. Does not throw on error.
- int openNoThrow(const char* name, bool readOnly=true,
- const char** msg=nullptr) noexcept;
+ 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;
+ 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);
+ void open(const char* name, bool readOnly = true);
~ElfFile();
ElfFile& operator=(ElfFile&& other);
/** Retrieve the ELF header */
- const ElfW(Ehdr)& elfHeader() const {
- return at<ElfW(Ehdr)>(0);
+ const ElfEhdr& elfHeader() const {
+ return at<ElfEhdr>(0);
}
/**
}
/** Find a section given its name */
- const ElfW(Shdr)* getSectionByName(const char* name) const;
+ const ElfShdr* getSectionByName(const char* name) const;
/** Find a section given its index in the section header table */
- const ElfW(Shdr)* getSectionByIndex(size_t idx) const;
+ const ElfShdr* getSectionByIndex(size_t idx) const;
/** Retrieve the name of a section */
- const char* getSectionName(const ElfW(Shdr)& section) const;
+ const char* getSectionName(const ElfShdr& section) const;
/** Get the actual section body */
- folly::StringPiece getSectionBody(const ElfW(Shdr)& section) const;
+ folly::StringPiece getSectionBody(const ElfShdr& section) const;
/** Retrieve a string from a string table section */
- const char* getString(const ElfW(Shdr)& stringTable, size_t offset) const;
+ const char* getString(const ElfShdr& stringTable, size_t offset) const;
/**
* Iterate over all strings in a string table section for as long as
* if fn returned false for all strings in the table.
*/
template <class Fn>
- const char* iterateStrings(const ElfW(Shdr)& stringTable, Fn fn) const;
+ const char* iterateStrings(const ElfShdr& stringTable, Fn fn) const;
/**
* Iterate over all sections for as long as fn(section) returns false.
* true, or nullptr if fn returned false for all sections.
*/
template <class Fn>
- const ElfW(Shdr)* iterateSections(Fn fn) const;
+ const ElfShdr* iterateSections(Fn fn) const;
/**
* Iterate over all sections with a given type. Similar to
* iterateSections(), but filtered only for sections with the given type.
*/
template <class Fn>
- const ElfW(Shdr)* iterateSectionsWithType(uint32_t type, Fn fn) const;
+ const ElfShdr* iterateSectionsWithType(uint32_t type, Fn fn) const;
/**
* Iterate over all symbols witin a given section.
* or nullptr if fn returned false for all symbols.
*/
template <class Fn>
- const ElfW(Sym)* iterateSymbols(const ElfW(Shdr)& section, Fn fn) const;
+ const ElfSym* iterateSymbols(const ElfShdr& section, Fn fn) const;
template <class Fn>
- const ElfW(Sym)* iterateSymbolsWithType(const ElfW(Shdr)& section,
- uint32_t type, Fn fn) const;
+ const ElfSym*
+ iterateSymbolsWithType(const ElfShdr& section, uint32_t type, Fn fn) const;
/**
* Find symbol definition by address.
*
* Returns {nullptr, nullptr} if not found.
*/
- typedef std::pair<const ElfW(Shdr)*, const ElfW(Sym)*> Symbol;
+ typedef std::pair<const ElfShdr*, const ElfSym*> Symbol;
Symbol getDefinitionByAddress(uintptr_t address) const;
/**
* Get the value of a symbol.
*/
template <class T>
- const T& getSymbolValue(const ElfW(Sym)* symbol) const {
- const ElfW(Shdr)* section = getSectionByIndex(symbol->st_shndx);
+ const T& getSymbolValue(const ElfSym* symbol) const {
+ const ElfShdr* section = getSectionByIndex(symbol->st_shndx);
FOLLY_SAFE_CHECK(section, "Symbol's section index is invalid");
return valueAt<T>(*section, symbol->st_value);
* a char* symbol, you'd do something like this:
*
* auto sym = getSymbolByName("someGlobalValue");
- * auto addr = getSymbolValue<ElfW(Addr)>(sym.second);
+ * auto addr = getSymbolValue<ElfAddr>(sym.second);
* const char* str = &getSymbolValue<const char>(addr);
*/
template <class T>
- const T& getAddressValue(const ElfW(Addr) addr) const {
- const ElfW(Shdr)* section = getSectionContainingAddress(addr);
+ const T& getAddressValue(const ElfAddr addr) const {
+ const ElfShdr* section = getSectionContainingAddress(addr);
FOLLY_SAFE_CHECK(section, "Address does not refer to existing section");
return valueAt<T>(*section, addr);
const char* getSymbolName(Symbol symbol) const;
/** Find the section containing the given address */
- const ElfW(Shdr)* getSectionContainingAddress(ElfW(Addr) addr) const;
+ const ElfShdr* getSectionContainingAddress(ElfAddr addr) const;
private:
bool init(const char** msg);
ElfFile(const ElfFile&) = delete;
ElfFile& operator=(const ElfFile&) = delete;
- void validateStringTable(const ElfW(Shdr)& stringTable) const;
+ void validateStringTable(const ElfShdr& stringTable) const;
template <class T>
- const typename std::enable_if<std::is_pod<T>::value, T>::type&
- at(ElfW(Off) offset) const {
- FOLLY_SAFE_CHECK(offset + sizeof(T) <= length_,
- "Offset is not contained within our mmapped file");
+ const typename std::enable_if<std::is_pod<T>::value, T>::type& at(
+ ElfOff offset) const {
+ FOLLY_SAFE_CHECK(
+ offset + sizeof(T) <= length_,
+ "Offset is not contained within our mmapped file");
return *reinterpret_cast<T*>(file_ + offset);
}
template <class T>
- const T& valueAt(const ElfW(Shdr)& section, const ElfW(Addr) addr) const {
+ const T& valueAt(const ElfShdr& section, const ElfAddr addr) const {
// For exectuables and shared objects, st_value holds a virtual address
// that refers to the memory owned by sections. Since we didn't map the
// sections into the addresses that they're expecting (sh_addr), but
"Only exectuables and shared objects are supported");
FOLLY_SAFE_CHECK(
addr >= section.sh_addr &&
- (addr + sizeof(T)) <= (section.sh_addr + section.sh_size),
+ (addr + sizeof(T)) <= (section.sh_addr + section.sh_size),
"Address is not contained within the provided segment");
return at<T>(section.sh_offset + (addr - section.sh_addr));
}
int fd_;
- char* file_; // mmap() location
- size_t length_; // mmap() length
+ char* file_; // mmap() location
+ size_t length_; // mmap() length
uintptr_t baseAddress_;
};
-} // namespace symbolizer
-} // namespace folly
+} // namespace symbolizer
+} // namespace folly
#include <folly/experimental/symbolizer/Elf-inl.h>
*/
extern struct r_debug _r_debug;
-namespace folly { namespace symbolizer {
+namespace folly {
+namespace symbolizer {
size_t countLoadedElfFiles() {
// _r_debug synchronization is... lacking to say the least. It's
return f;
}
-ElfCache::ElfCache(size_t capacity) : capacity_(capacity) { }
+ElfCache::ElfCache(size_t capacity) : capacity_(capacity) {}
std::shared_ptr<ElfFile> ElfCache::getFile(StringPiece p) {
std::lock_guard<std::mutex> lock(mutex_);
// share ownership
return std::shared_ptr<ElfFile>(e, &e->file);
}
-
-}} // namespaces
+} // namespace symbolizer
+} // namespace folly
#include <folly/Range.h>
#include <folly/experimental/symbolizer/Elf.h>
-namespace folly { namespace symbolizer {
+namespace folly {
+namespace symbolizer {
/**
* Number of ELF files loaded by the dynamic loader.
class ElfCacheBase {
public:
virtual std::shared_ptr<ElfFile> getFile(StringPiece path) = 0;
- virtual ~ElfCacheBase() { }
+ virtual ~ElfCacheBase() {}
};
/**
typedef boost::intrusive::list<
Entry,
boost::intrusive::member_hook<Entry, LruLink, &Entry::lruLink>,
- boost::intrusive::constant_time_size<false>> LruList;
+ boost::intrusive::constant_time_size<false>>
+ LruList;
LruList lruList_;
};
-
-}} // namespaces
+} // namespace symbolizer
+} // namespace folly
* limitations under the License.
*/
-
#include <folly/experimental/symbolizer/Elf.h>
#include <stdio.h>
using namespace folly;
using namespace folly::symbolizer;
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK_GE(argc, 2);
if (argc > 2) {
auto section = elf.getSectionByName(argv[2]);
- printf("Section %s: %s\n",
- argv[2],
- (section ? "found" : "not found"));
+ printf("Section %s: %s\n", argv[2], (section ? "found" : "not found"));
}
auto sym = elf.getDefinitionByAddress(reinterpret_cast<uintptr_t>(main));
#include <folly/FileUtil.h>
-namespace folly { namespace symbolizer {
+namespace folly {
+namespace symbolizer {
LineReader::LineReader(int fd, char* buf, size_t bufSize)
- : fd_(fd),
- buf_(buf),
- bufEnd_(buf_ + bufSize),
- bol_(buf),
- eol_(buf),
- end_(buf),
- state_(kReading) {
-}
+ : fd_(fd),
+ buf_(buf),
+ bufEnd_(buf_ + bufSize),
+ bol_(buf),
+ eol_(buf),
+ end_(buf),
+ state_(kReading) {}
LineReader::State LineReader::readLine(StringPiece& line) {
- bol_ = eol_; // Start past what we already returned
+ bol_ = eol_; // Start past what we already returned
for (;;) {
// Search for newline
char* newline = static_cast<char*>(memchr(eol_, '\n', end_ - eol_));
line.assign(bol_, eol_);
return eol_ != bol_ ? kReading : state_;
}
-
-}} // namespaces
+} // namespace symbolizer
+} // namespace folly
#include <folly/Range.h>
-namespace folly { namespace symbolizer {
+namespace folly {
+namespace symbolizer {
/**
* Async-signal-safe line reader.
enum State {
kReading,
kEof,
- kError
+ kError,
};
/**
* Read the next line from the file.
char* end_;
State state_;
};
-
-}} // namespaces
+} // namespace symbolizer
+} // namespace folly
#include <folly/portability/SysSyscall.h>
#include <folly/portability/Unistd.h>
-namespace folly { namespace symbolizer {
+namespace folly {
+namespace symbolizer {
namespace {
};
FatalSignalCallbackRegistry::FatalSignalCallbackRegistry()
- : installed_(false) {
-}
+ : installed_(false) {}
void FatalSignalCallbackRegistry::add(SignalCallback func) {
std::lock_guard<std::mutex> lock(mutex_);
- CHECK(!installed_)
- << "FatalSignalCallbackRegistry::add may not be used "
- "after installing the signal handlers.";
+ CHECK(!installed_) << "FatalSignalCallbackRegistry::add may not be used "
+ "after installing the signal handlers.";
handlers_.push_back(func);
}
void FatalSignalCallbackRegistry::markInstalled() {
std::lock_guard<std::mutex> lock(mutex_);
CHECK(!installed_.exchange(true))
- << "FatalSignalCallbackRegistry::markInstalled must be called "
- << "at most once";
+ << "FatalSignalCallbackRegistry::markInstalled must be called "
+ << "at most once";
}
void FatalSignalCallbackRegistry::run() {
// Leak it so we don't have to worry about destruction order
FatalSignalCallbackRegistry* gFatalSignalCallbackRegistry =
- new FatalSignalCallbackRegistry;
+ new FatalSignalCallbackRegistry;
struct {
int number;
const char* name;
struct sigaction oldAction;
} kFatalSignals[] = {
- { SIGSEGV, "SIGSEGV", {} },
- { SIGILL, "SIGILL", {} },
- { SIGFPE, "SIGFPE", {} },
- { SIGABRT, "SIGABRT", {} },
- { SIGBUS, "SIGBUS", {} },
- { SIGTERM, "SIGTERM", {} },
- { 0, nullptr, {} }
+ {SIGSEGV, "SIGSEGV", {}},
+ {SIGILL, "SIGILL", {}},
+ {SIGFPE, "SIGFPE", {}},
+ {SIGABRT, "SIGABRT", {}},
+ {SIGBUS, "SIGBUS", {}},
+ {SIGTERM, "SIGTERM", {}},
+ {0, nullptr, {}},
};
void callPreviousSignalHandler(int signum) {
const char kHexChars[] = "0123456789abcdef";
void printHex(uint64_t val) {
// TODO(tudorb): Add this to folly/Conv.h
- char buf[2 + 2 * sizeof(uint64_t)]; // "0x" prefix, 2 digits for each byte
+ char buf[2 + 2 * sizeof(uint64_t)]; // "0x" prefix, 2 digits for each byte
char* end = buf + sizeof(buf);
char* p = end;
}
void dumpTimeInfo() {
- SCOPE_EXIT { flush(); };
+ SCOPE_EXIT {
+ flush();
+ };
time_t now = time(nullptr);
print("*** Aborted at ");
printDec(now);
}
void dumpSignalInfo(int signum, siginfo_t* siginfo) {
- SCOPE_EXIT { flush(); };
+ SCOPE_EXIT {
+ flush();
+ };
// Get the signal name, if possible.
const char* name = nullptr;
for (auto p = kFatalSignals; p->name; ++p) {
// Wait a while, try again.
timespec ts;
ts.tv_sec = 0;
- ts.tv_nsec = 100L * 1000 * 1000; // 100ms
+ ts.tv_nsec = 100L * 1000 * 1000; // 100ms
nanosleep(&ts, nullptr);
prevSignalThread = kInvalidThreadId;
}
void signalHandler(int signum, siginfo_t* info, void* uctx) {
- SCOPE_EXIT { flush(); };
+ SCOPE_EXIT {
+ flush();
+ };
innerSignalHandler(signum, info, uctx);
gSignalThread = kInvalidThreadId;
callPreviousSignalHandler(signum);
}
-} // namespace
+} // namespace
void addFatalSignalCallback(SignalCallback cb) {
gFatalSignalCallbackRegistry->add(cb);
std::atomic<bool> gAlreadyInstalled;
-} // namespace
+} // namespace
void installFatalSignalHandler() {
if (gAlreadyInstalled.exchange(true)) {
CHECK_ERR(sigaction(p->number, &sa, &p->oldAction));
}
}
-
-}} // namespaces
+} // namespace symbolizer
+} // namespace folly
#include <functional>
-namespace folly { namespace symbolizer {
+namespace folly {
+namespace symbolizer {
/**
* Install handler for fatal signals. The list of signals being handled is in
* callbacks in the order in which they were added.
*/
void installFatalSignalCallbacks();
-
-}} // namespaces
+} // namespace symbolizer
+} // namespace folly
#define UNW_LOCAL_ONLY 1
#include <libunwind.h>
-namespace folly { namespace symbolizer {
+namespace folly {
+namespace symbolizer {
ssize_t getStackTrace(uintptr_t* addresses, size_t maxAddresses) {
- static_assert(sizeof(uintptr_t) == sizeof(void*),
- "uinptr_t / pointer size mismatch");
+ static_assert(
+ sizeof(uintptr_t) == sizeof(void*), "uinptr_t / pointer size mismatch");
// The libunwind documentation says that unw_backtrace is async-signal-safe
// but, as of libunwind 1.0.1, it isn't (tdep_trace allocates memory on
// x86_64)
ip = uip - (r == 0);
return true;
}
-} // namespace
+} // namespace
ssize_t getStackTraceSafe(uintptr_t* addresses, size_t maxAddresses) {
if (maxAddresses == 0) {
}
return count;
}
-
-}} // namespaces
+} // namespace symbolizer
+} // namespace folly
#include <cstdint>
#include <cstdlib>
-namespace folly { namespace symbolizer {
+namespace folly {
+namespace symbolizer {
/**
* Get the current stack trace into addresses, which has room for at least
* Async-signal-safe, but likely slower.
*/
ssize_t getStackTraceSafe(uintptr_t* addresses, size_t maxAddresses);
-
-}} // namespaces
+} // namespace symbolizer
+} // namespace folly
return cache;
}
-} // namespace
+} // namespace
-void SymbolizedFrame::set(const std::shared_ptr<ElfFile>& file,
- uintptr_t address,
- Dwarf::LocationInfoMode mode) {
+void SymbolizedFrame::set(
+ const std::shared_ptr<ElfFile>& file,
+ uintptr_t address,
+ Dwarf::LocationInfoMode mode) {
clear();
found = true;
}
Symbolizer::Symbolizer(ElfCacheBase* cache, Dwarf::LocationInfoMode mode)
- : cache_(cache ? cache : defaultElfCache()), mode_(mode) {
-}
+ : cache_(cache ? cache : defaultElfCache()), mode_(mode) {}
-void Symbolizer::symbolize(const uintptr_t* addresses,
- SymbolizedFrame* frames,
- size_t addrCount) {
+void Symbolizer::symbolize(
+ const uintptr_t* addresses,
+ SymbolizedFrame* frames,
+ size_t addrCount) {
size_t remaining = 0;
for (size_t i = 0; i < addrCount; ++i) {
auto& frame = frames[i];
}
}
- if (remaining == 0) { // we're done
+ if (remaining == 0) { // we're done
return;
}
}
selfPath[selfSize] = '\0';
- for (auto lmap = _r_debug.r_map;
- lmap != nullptr && remaining != 0;
+ for (auto lmap = _r_debug.r_map; lmap != nullptr && remaining != 0;
lmap = lmap->l_next) {
// The empty string is used in place of the filename for the link_map
// corresponding to the running executable. Additionally, the `l_addr' is
// header for the running executable, since its `l_addr' is zero, but we
// should use `l_addr' for everything else---in particular, if the object
// is position-independent, getBaseAddress() (which is p_vaddr) will be 0.
- auto const base = lmap->l_addr != 0
- ? lmap->l_addr
- : elfFile->getBaseAddress();
+ auto const base =
+ lmap->l_addr != 0 ? lmap->l_addr : elfFile->getBaseAddress();
for (size_t i = 0; i < addrCount && remaining != 0; ++i) {
auto& frame = frames[i];
constexpr auto kAddressColor = SymbolizePrinter::Color::BLUE;
constexpr auto kFunctionColor = SymbolizePrinter::Color::PURPLE;
constexpr auto kFileColor = SymbolizePrinter::Color::DEFAULT;
-} // namespace
+} // namespace
constexpr char AddressFormatter::bufTemplate[];
constexpr std::array<const char*, SymbolizePrinter::Color::NUM>
return;
}
- SCOPE_EXIT { color(Color::DEFAULT); };
+ SCOPE_EXIT {
+ color(Color::DEFAULT);
+ };
if (!(options_ & NO_FRAME_ADDRESS)) {
color(kAddressColor);
}
const char padBuf[] = " ";
- folly::StringPiece pad(padBuf,
- sizeof(padBuf) - 1 - (16 - 2 * sizeof(uintptr_t)));
+ folly::StringPiece pad(
+ padBuf, sizeof(padBuf) - 1 - (16 - 2 * sizeof(uintptr_t)));
color(kFunctionColor);
if (!frame.found) {
}
void SymbolizePrinter::color(SymbolizePrinter::Color color) {
- if ((options_ & COLOR) == 0 &&
- ((options_ & COLOR_IF_TTY) == 0 || !isTty_)) {
+ if ((options_ & COLOR) == 0 && ((options_ & COLOR_IF_TTY) == 0 || !isTty_)) {
return;
}
if (color < 0 || color >= kColorMap.size()) {
doPrint(kColorMap[color]);
}
-void SymbolizePrinter::println(uintptr_t address,
- const SymbolizedFrame& frame) {
+void SymbolizePrinter::println(
+ uintptr_t address,
+ const SymbolizedFrame& frame) {
print(address, frame);
doPrint("\n");
}
-void SymbolizePrinter::printTerse(uintptr_t address,
- const SymbolizedFrame& frame) {
+void SymbolizePrinter::printTerse(
+ uintptr_t address,
+ const SymbolizedFrame& frame) {
if (frame.found && frame.name && frame.name[0] != '\0') {
char demangledBuf[2048] = {0};
demangle(frame.name, demangledBuf, sizeof(demangledBuf));
}
}
-void SymbolizePrinter::println(const uintptr_t* addresses,
- const SymbolizedFrame* frames,
- size_t frameCount) {
+void SymbolizePrinter::println(
+ const uintptr_t* addresses,
+ const SymbolizedFrame* frames,
+ size_t frameCount) {
for (size_t i = 0; i < frameCount; ++i) {
println(addresses[i], frames[i]);
}
return sbuf->fd();
}
}
-#endif // __GNUC__
+#endif // __GNUC__
return -1;
}
bool isColorfulTty(int options, int fd) {
if ((options & SymbolizePrinter::TERSE) != 0 ||
- (options & SymbolizePrinter::COLOR_IF_TTY) == 0 ||
- fd < 0 || !::isatty(fd)) {
+ (options & SymbolizePrinter::COLOR_IF_TTY) == 0 || fd < 0 ||
+ !::isatty(fd)) {
return false;
}
auto term = ::getenv("TERM");
return !(term == nullptr || term[0] == '\0' || strcmp(term, "dumb") == 0);
}
-} // anonymous namespace
+} // anonymous namespace
OStreamSymbolizePrinter::OStreamSymbolizePrinter(std::ostream& out, int options)
- : SymbolizePrinter(options, isColorfulTty(options, getFD(out))),
- out_(out) {
-}
+ : SymbolizePrinter(options, isColorfulTty(options, getFD(out))),
+ out_(out) {}
void OStreamSymbolizePrinter::doPrint(StringPiece sp) {
out_ << sp;
}
FDSymbolizePrinter::FDSymbolizePrinter(int fd, int options, size_t bufferSize)
- : SymbolizePrinter(options, isColorfulTty(options, fd)),
- fd_(fd),
- buffer_(bufferSize ? IOBuf::create(bufferSize) : nullptr) {
-}
+ : SymbolizePrinter(options, isColorfulTty(options, fd)),
+ fd_(fd),
+ buffer_(bufferSize ? IOBuf::create(bufferSize) : nullptr) {}
FDSymbolizePrinter::~FDSymbolizePrinter() {
flush();
}
FILESymbolizePrinter::FILESymbolizePrinter(FILE* file, int options)
- : SymbolizePrinter(options, isColorfulTty(options, fileno(file))),
- file_(file) {
-}
+ : SymbolizePrinter(options, isColorfulTty(options, fileno(file))),
+ file_(file) {}
void FILESymbolizePrinter::doPrint(StringPiece sp) {
fwrite(sp.data(), 1, sp.size(), file_);
}
}
-} // namespace symbolizer
-} // namespace folly
+} // namespace symbolizer
+} // namespace folly
* Frame information: symbol name and location.
*/
struct SymbolizedFrame {
- SymbolizedFrame() { }
+ SymbolizedFrame() {}
- void set(const std::shared_ptr<ElfFile>& file,
- uintptr_t address,
- Dwarf::LocationInfoMode mode);
+ void set(
+ const std::shared_ptr<ElfFile>& file,
+ uintptr_t address,
+ Dwarf::LocationInfoMode mode);
- void clear() { *this = SymbolizedFrame(); }
+ void clear() {
+ *this = SymbolizedFrame();
+ }
bool found = false;
const char* name = nullptr;
template <size_t N>
struct FrameArray {
- FrameArray() { }
+ FrameArray() {}
size_t frameCount = 0;
uintptr_t addresses[N];
return false;
}
}
-} // namespace detail
+} // namespace detail
// Always inline these functions; they don't do much, and unittests rely
// on them never showing up in a stack trace.
Dwarf::LocationInfoMode::FAST;
explicit Symbolizer(Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode)
- : Symbolizer(nullptr, mode) {}
+ : Symbolizer(nullptr, mode) {}
- explicit Symbolizer(ElfCacheBase* cache,
- Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode);
+ explicit Symbolizer(
+ ElfCacheBase* cache,
+ Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode);
/**
* Symbolize given addresses.
*/
- void symbolize(const uintptr_t* addresses,
- SymbolizedFrame* frames,
- size_t frameCount);
+ void symbolize(
+ const uintptr_t* addresses,
+ SymbolizedFrame* frames,
+ size_t frameCount);
template <size_t N>
void symbolize(FrameArray<N>& fa) {
/**
* Print multiple addresses on separate lines.
*/
- void println(const uintptr_t* addresses,
- const SymbolizedFrame* frames,
- size_t frameCount);
+ void println(
+ const uintptr_t* addresses,
+ const SymbolizedFrame* frames,
+ size_t frameCount);
/**
* Print a string, no endling newline.
*/
- void print(StringPiece sp) { doPrint(sp); }
+ void print(StringPiece sp) {
+ doPrint(sp);
+ }
/**
* Print multiple addresses on separate lines, skipping the first
* skip addresses.
*/
template <size_t N>
- void println(const FrameArray<N>& fa, size_t skip=0) {
+ void println(const FrameArray<N>& fa, size_t skip = 0) {
if (skip < fa.frameCount) {
println(fa.addresses + skip, fa.frames + skip, fa.frameCount - skip);
}
}
- virtual ~SymbolizePrinter() { }
+ virtual ~SymbolizePrinter() {}
enum Options {
// Skip file and line information
protected:
explicit SymbolizePrinter(int options, bool isTty = false)
- : options_(options),
- isTty_(isTty) {
- }
+ : options_(options), isTty_(isTty) {}
const int options_;
const bool isTty_;
*/
class OStreamSymbolizePrinter : public SymbolizePrinter {
public:
- explicit OStreamSymbolizePrinter(std::ostream& out, int options=0);
+ explicit OStreamSymbolizePrinter(std::ostream& out, int options = 0);
+
private:
void doPrint(StringPiece sp) override;
std::ostream& out_;
*/
class FDSymbolizePrinter : public SymbolizePrinter {
public:
- explicit FDSymbolizePrinter(int fd, int options=0,
- size_t bufferSize=0);
+ explicit FDSymbolizePrinter(int fd, int options = 0, size_t bufferSize = 0);
~FDSymbolizePrinter() override;
void flush();
+
private:
void doPrint(StringPiece sp) override;
*/
class FILESymbolizePrinter : public SymbolizePrinter {
public:
- explicit FILESymbolizePrinter(FILE* file, int options=0);
+ explicit FILESymbolizePrinter(FILE* file, int options = 0);
+
private:
void doPrint(StringPiece sp) override;
FILE* const file_ = nullptr;
*/
class StringSymbolizePrinter : public SymbolizePrinter {
public:
- explicit StringSymbolizePrinter(int options=0) : SymbolizePrinter(options) { }
+ explicit StringSymbolizePrinter(int options = 0)
+ : SymbolizePrinter(options) {}
- std::string str() const { return buf_.toStdString(); }
- const fbstring& fbstr() const { return buf_; }
- fbstring moveFbString() { return std::move(buf_); }
+ std::string str() const {
+ return buf_.toStdString();
+ }
+ const fbstring& fbstr() const {
+ return buf_;
+ }
+ fbstring moveFbString() {
+ return std::move(buf_);
+ }
private:
void doPrint(StringPiece sp) override;
std::unique_ptr<FrameArray<kMaxStackTraceDepth>> addresses_;
};
-} // namespace symbolizer
-} // namespace folly
+} // namespace symbolizer
+} // namespace folly
Dwarf::Path path(rawBaseDir, rawSubDir, rawFile);
CHECK_EQ(expectedBaseDir, path.baseDir())
- << "Path(" << rawBaseDir << ", " << rawSubDir << ", " << rawFile << ")";
+ << "Path(" << rawBaseDir << ", " << rawSubDir << ", " << rawFile << ")";
CHECK_EQ(expectedSubDir, path.subDir())
- << "Path(" << rawBaseDir << ", " << rawSubDir << ", " << rawFile << ")";
+ << "Path(" << rawBaseDir << ", " << rawSubDir << ", " << rawFile << ")";
CHECK_EQ(expectedFile, path.file())
- << "Path(" << rawBaseDir << ", " << rawSubDir << ", " << rawFile << ")";
+ << "Path(" << rawBaseDir << ", " << rawSubDir << ", " << rawFile << ")";
CHECK_EQ(expectedPath, path.toString());
}
TEST(Dwarf, Path) {
+ checkPath("hello.cpp", "", "", "hello.cpp", "", "", "hello.cpp");
+ checkPath("foo/hello.cpp", "foo", "", "hello.cpp", "foo", "", "hello.cpp");
+ checkPath("foo/hello.cpp", "foo", "", "hello.cpp", "", "foo", "hello.cpp");
+ checkPath("hello.cpp", "", "", "hello.cpp", "./////", "./////", "hello.cpp");
+ checkPath("/hello.cpp", "/", "", "hello.cpp", "/////", "./////", "hello.cpp");
checkPath(
- "hello.cpp",
- "",
- "",
- "hello.cpp",
- "",
- "",
- "hello.cpp");
- checkPath(
- "foo/hello.cpp",
- "foo",
- "",
- "hello.cpp",
- "foo",
- "",
- "hello.cpp");
- checkPath(
- "foo/hello.cpp",
- "foo",
- "",
- "hello.cpp",
- "",
- "foo",
- "hello.cpp");
- checkPath(
- "hello.cpp",
- "",
- "",
- "hello.cpp",
- "./////",
- "./////",
- "hello.cpp");
- checkPath(
- "/hello.cpp",
- "/",
- "",
- "hello.cpp",
- "/////",
- "./////",
- "hello.cpp");
- checkPath(
- "/hello.cpp",
- "/",
- "",
- "hello.cpp",
- "/./././././././",
- "",
- "hello.cpp");
+ "/hello.cpp", "/", "", "hello.cpp", "/./././././././", "", "hello.cpp");
}
// Path to the test binary itself; set by main()
static std::string binaryPath;
- ElfTest() : elfFile_(binaryPath.c_str()) {
- }
+ ElfTest() : elfFile_(binaryPath.c_str()) {}
~ElfTest() override {}
protected:
TEST_F(ElfTest, IntegerValue) {
auto sym = elfFile_.getSymbolByName("kIntegerValue");
- EXPECT_NE(nullptr, sym.first) <<
- "Failed to look up symbol kIntegerValue";
+ EXPECT_NE(nullptr, sym.first) << "Failed to look up symbol kIntegerValue";
EXPECT_EQ(kIntegerValue, elfFile_.getSymbolValue<uint64_t>(sym.second));
}
TEST_F(ElfTest, PointerValue) {
auto sym = elfFile_.getSymbolByName("kStringValue");
- EXPECT_NE(nullptr, sym.first) <<
- "Failed to look up symbol kStringValue";
+ EXPECT_NE(nullptr, sym.first) << "Failed to look up symbol kStringValue";
ElfW(Addr) addr = elfFile_.getSymbolValue<ElfW(Addr)>(sym.second);
- const char *str = &elfFile_.getAddressValue<const char>(addr);
+ const char* str = &elfFile_.getAddressValue<const char>(addr);
EXPECT_STREQ(kStringValue, str);
}
#include <folly/experimental/TestUtil.h>
#include <folly/portability/GTest.h>
-namespace folly { namespace symbolizer { namespace test {
+namespace folly {
+namespace symbolizer {
+namespace test {
using folly::test::TemporaryFile;
void expect(LineReader& lr, const char* expected) {
StringPiece line;
size_t expectedLen = strlen(expected);
- EXPECT_EQ(expectedLen != 0 ? LineReader::kReading : LineReader::kEof,
- lr.readLine(line));
+ EXPECT_EQ(
+ expectedLen != 0 ? LineReader::kReading : LineReader::kEof,
+ lr.readLine(line));
EXPECT_EQ(expectedLen, line.size());
EXPECT_EQ(std::string(expected, expectedLen), line.str());
}
TEST(LineReader, Simple) {
TemporaryFile file;
int fd = file.fd();
- writeAll(fd,
- "Meow\n"
- "Hello world\n"
- "This is a long line. It is longer than the other lines.\n"
- "\n"
- "Incomplete last line");
+ writeAll(
+ fd,
+ "Meow\n"
+ "Hello world\n"
+ "This is a long line. It is longer than the other lines.\n"
+ "\n"
+ "Incomplete last line");
{
CHECK_ERR(lseek(fd, 0, SEEK_SET));
expect(lr, "");
}
}
-
-}}} // namespaces
+} // namespace test
+} // namespace symbolizer
+} // namespace folly
#include <folly/Range.h>
#include <folly/portability/GTest.h>
-namespace folly { namespace symbolizer { namespace test {
+namespace folly {
+namespace symbolizer {
+namespace test {
namespace {
writeFull(STDERR_FILENO, sp.data(), sp.size());
}
-
void callback1() {
print("Callback1\n");
}
print("Callback2\n");
}
-} // namespace
+} // namespace
TEST(SignalHandler, Simple) {
addFatalSignalCallback(callback1);
"Callback2\n");
#endif
}
-
-
-}}} // namespaces
+} // namespace test
+} // namespace symbolizer
+} // namespace folly
// Can't use initFacebookLight since that would install its own signal handlers
// Can't use initFacebookNoSignals since we cannot depend on common
#pragma once
-namespace folly { namespace symbolizer { namespace test {
+namespace folly {
+namespace symbolizer {
+namespace test {
inline void failHard() {
- *(/* nolint */ volatile char*)42; // SIGSEGV
+ *(/* nolint */ volatile char*)42; // SIGSEGV
}
-
-}}} // namespaces
+} // namespace test
+} // namespace symbolizer
+} // namespace folly
EXPECT_TRUE(handled);
}
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
#include <folly/String.h>
#include <folly/portability/GTest.h>
-namespace folly { namespace symbolizer { namespace test {
+namespace folly {
+namespace symbolizer {
+namespace test {
-void foo() {
-}
+void foo() {}
TEST(Symbolizer, Single) {
Symbolizer symbolizer;
// 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__
+#ifdef __clang__
true;
- #else
+#else
false;
- #endif
+#endif
if (!built_with_clang) {
auto path = a.location.file.toString();
folly::StringPiece basename(path);
runElfCacheTest(symbolizer);
}
}
-
-}}} // namespaces
+} // namespace test
+} // namespace symbolizer
+} // namespace folly
// Can't use initFacebookLight since that would install its own signal handlers
// Can't use initFacebookNoSignals since we cannot depend on common