folly/experimental/symbolizer/DwarfUtil.h (103 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// DWARF record parser
#pragma once
#include <boost/variant.hpp>
#include <folly/Function.h>
#include <folly/Range.h>
#include <folly/experimental/symbolizer/Elf.h>
#if FOLLY_HAVE_DWARF && FOLLY_HAVE_ELF
#include <dwarf.h>
namespace folly {
namespace symbolizer {
/**
* More than one location info may exist if current frame is an inline
* function call.
*/
const uint32_t kMaxInlineLocationInfoPerFrame = 10;
// Maximum number of DIEAbbreviation to cache in a compilation unit. Used to
// speed up inline function lookup.
const uint32_t kMaxAbbreviationEntries = 1000;
// A struct contains an Elf object and different debug sections.
struct DebugSections {
const ElfFile* elf;
folly::StringPiece debugAbbrev; // .debug_abbrev
folly::StringPiece debugAddr; // .debug_addr (DWARF 5)
folly::StringPiece debugAranges; // .debug_aranges
folly::StringPiece debugInfo; // .debug_info
folly::StringPiece debugLine; // .debug_line
folly::StringPiece debugLineStr; // .debug_line_str (DWARF 5)
folly::StringPiece debugLoclists; // .debug_loclists (DWARF 5)
folly::StringPiece debugRanges; // .debug_ranges
folly::StringPiece debugRnglists; // .debug_rnglists (DWARF 5)
folly::StringPiece debugStr; // .debug_str
folly::StringPiece debugStrOffsets; // .debug_str_offsets (DWARF 5)
};
// Abbreviation for a Debugging Information Entry.
struct DIEAbbreviation {
uint64_t code = 0;
uint64_t tag = 0;
bool hasChildren = false;
folly::StringPiece attributes;
};
// A top level chunk in the .debug_info that contains a compilation unit.
struct CompilationUnit {
DebugSections debugSections;
bool is64Bit = false;
uint8_t version = 0;
uint8_t unitType = DW_UT_compile; // DW_UT_compile or DW_UT_skeleton
uint8_t addrSize = 0;
// Offset in .debug_info of this compilation unit.
uint32_t offset = 0;
uint32_t size = 0;
// Offset in .debug_info for the first DIE in this compilation unit.
uint32_t firstDie = 0;
uint64_t abbrevOffset = 0;
// The beginning of the CU's contribution to .debug_addr
folly::Optional<uint64_t> addrBase; // DW_AT_addr_base (DWARF 5)
// The beginning of the offsets table (immediately following the
// header) of the CU's contribution to .debug_loclists
folly::Optional<uint64_t> loclistsBase; // DW_AT_loclists_base (DWARF 5)
// The beginning of the offsets table (immediately following the
// header) of the CU's contribution to .debug_rnglists
folly::Optional<uint64_t> rnglistsBase; // DW_AT_rnglists_base (DWARF 5)
// Points to the first string offset of the compilation unit’s
// contribution to the .debug_str_offsets (or .debug_str_offsets.dwo) section.
folly::Optional<uint64_t> strOffsetsBase; // DW_AT_str_offsets_base (DWARF 5)
// Only the CompilationUnit that contains the caller functions needs this.
// Indexed by (abbr.code - 1) if (abbr.code - 1) < abbrCache.size();
folly::Range<DIEAbbreviation*> abbrCache;
};
// Debugging information entry to define a low-level representation of a
// source program. Each debugging information entry consists of an identifying
// tag and a series of attributes. An entry, or group of entries together,
// provide a description of a corresponding entity in the source program.
struct Die {
bool is64Bit = false;
// Offset from start to first attribute
uint8_t attrOffset = 0;
// Offset within debug info.
uint32_t offset = 0;
uint64_t code = 0;
DIEAbbreviation abbr;
};
struct AttributeSpec {
uint64_t name = 0;
uint64_t form = 0;
int64_t implicitConst = 0; // only set when form=DW_FORM_implicit_const
explicit operator bool() const { return name != 0 || form != 0; }
};
struct Attribute {
AttributeSpec spec;
const Die& die;
boost::variant<uint64_t, folly::StringPiece> attrValue;
};
// All following read* functions read from a StringPiece, advancing the
// StringPiece, and aborting if there's not enough room.
// Read (bitwise) one object of type T
template <class T>
typename std::enable_if<
std::is_standard_layout<T>::value && std::is_trivial<T>::value,
T>::type
read(folly::StringPiece& sp) {
FOLLY_SAFE_CHECK(sp.size() >= sizeof(T), "underflow");
T x;
memcpy(&x, sp.data(), sizeof(T));
sp.advance(sizeof(T));
return x;
}
// Read (bitwise) an unsigned number of N bytes (N in 1, 2, 3, 4).
template <size_t N>
uint64_t readU64(folly::StringPiece& sp);
// Read ULEB (unsigned) varint value; algorithm from the DWARF spec
uint64_t readULEB(folly::StringPiece& sp, uint8_t& shift, uint8_t& val);
uint64_t readULEB(folly::StringPiece& sp);
// Read SLEB (signed) varint value; algorithm from the DWARF spec
int64_t readSLEB(folly::StringPiece& sp);
// Read a value of "section offset" type, which may be 4 or 8 bytes
uint64_t readOffset(folly::StringPiece& sp, bool is64Bit);
// Read "len" bytes
folly::StringPiece readBytes(folly::StringPiece& sp, uint64_t len);
AttributeSpec readAttributeSpec(folly::StringPiece& sp);
// Reads an abbreviation from a StringPiece, return true if at end; advance sp
bool readAbbreviation(folly::StringPiece& section, DIEAbbreviation& abbr);
// Read a null-terminated string
folly::StringPiece readNullTerminated(folly::StringPiece& sp);
folly::StringPiece getStringFromStringSection(
folly::StringPiece str, uint64_t offset);
CompilationUnit getCompilationUnit(
const DebugSections& debugSections, uint64_t offset);
/** cu must exist during the life cycle of created Die. */
Die getDieAtOffset(const CompilationUnit& cu, uint64_t offset);
// Read attribute value.
Attribute readAttribute(
const CompilationUnit& cu,
const Die& die,
AttributeSpec spec,
folly::StringPiece& info);
/*
* Iterate over all attributes of the given DIE, calling the given callable
* for each. Iteration is stopped early if any of the calls return false.
*/
size_t forEachAttribute(
const CompilationUnit& cu,
const Die& die,
folly::FunctionRef<bool(const Attribute&)> f);
} // namespace symbolizer
} // namespace folly
#endif