/* * 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 #include #include #include #include #if FOLLY_HAVE_DWARF && FOLLY_HAVE_ELF #include 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 debugCuIndex; // .debug_cu_index 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 struct that contains the metadata of 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; folly::Optional abbrevOffset; // Compilation directory. folly::StringPiece compDir = "."; // The beginning of the CU's contribution to .debug_addr // DW_AT_addr_base (DWARF 5, DebugFission) folly::Optional addrBase; // The beginning of the CU's contribution to .debug_ranges // DW_AT_ranges_base (DebugFission) folly::Optional rangesBase; // The beginning of the offsets table (immediately following the // header) of the CU's contribution to .debug_loclists folly::Optional 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 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 strOffsetsBase; // DW_AT_str_offsets_base (DWARF 5) // The actual dwo file and id contains the debug sections for this // compilation unit. folly::Optional dwoName; folly::Optional dwoId; // Only the CompilationUnit that contains the caller functions needs this. // Indexed by (abbr.code - 1) if (abbr.code - 1) < abbrCache.size(); folly::Range abbrCache; }; // Contains the main compilation unit in the binary file and an optional // compilation unit in dwo/dwp file if the main one is a skeleton. struct CompilationUnits { CompilationUnit mainCompilationUnit; folly::Optional splitCU; CompilationUnit& defaultCompilationUnit() { if (splitCU.hasValue()) { return *splitCU; } return mainCompilationUnit; } }; // 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 attrValue; }; // Get an ELF section by name. folly::StringPiece getElfSection(const ElfFile* elf, const char* name); // 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 typename std::enable_if< std::is_standard_layout::value && std::is_trivial::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 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); CompilationUnits getCompilationUnits( ElfCacheBase* elfCache, const DebugSections& debugSections, uint64_t offset, bool requireSplitDwarf = false); /** 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 f); } // namespace symbolizer } // namespace folly #endif