diff options
Diffstat (limited to 'gnu/llvm')
-rw-r--r-- | gnu/llvm/tools/clang/lib/Analysis/OSLog.cpp | 3 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/GdbIndex.cpp | 242 | ||||
-rw-r--r-- | gnu/llvm/tools/lld/ELF/GdbIndex.h | 109 | ||||
-rw-r--r-- | gnu/llvm/unittests/Transforms/Utils/FunctionComparator.cpp | 2 |
4 files changed, 244 insertions, 112 deletions
diff --git a/gnu/llvm/tools/clang/lib/Analysis/OSLog.cpp b/gnu/llvm/tools/clang/lib/Analysis/OSLog.cpp index b2983932ea2..3e13a153c65 100644 --- a/gnu/llvm/tools/clang/lib/Analysis/OSLog.cpp +++ b/gnu/llvm/tools/clang/lib/Analysis/OSLog.cpp @@ -10,11 +10,11 @@ #include "llvm/ADT/SmallBitVector.h" using namespace clang; +using llvm::APInt; using clang::analyze_os_log::OSLogBufferItem; using clang::analyze_os_log::OSLogBufferLayout; -namespace { class OSLogFormatStringHandler : public analyze_format_string::FormatStringHandler { private: @@ -166,7 +166,6 @@ public: } } }; -} // end anonymous namespace bool clang::analyze_os_log::computeOSLogBufferLayout( ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) { diff --git a/gnu/llvm/tools/lld/ELF/GdbIndex.cpp b/gnu/llvm/tools/lld/ELF/GdbIndex.cpp index 85449a20064..762144dd0a9 100644 --- a/gnu/llvm/tools/lld/ELF/GdbIndex.cpp +++ b/gnu/llvm/tools/lld/ELF/GdbIndex.cpp @@ -7,95 +7,199 @@ // //===----------------------------------------------------------------------===// // -// The -gdb-index option instructs the linker to emit a .gdb_index section. -// The section contains information to make gdb startup faster. -// The format of the section is described at -// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html. +// File contains classes for implementation of --gdb-index command line option. // +// If that option is used, linker should emit a .gdb_index section that allows +// debugger to locate and read .dwo files, containing neccessary debug +// information. +// More information about implementation can be found in DWARF specification, +// latest version is available at http://dwarfstd.org. +// +// .gdb_index section format: +// (Information is based on/taken from +// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html (*)) +// +// A mapped index consists of several areas, laid out in order: +// 1) The file header. +// 2) "The CU (compilation unit) list. This is a sequence of pairs of 64-bit +// little-endian values, sorted by the CU offset. The first element in each +// pair is the offset of a CU in the .debug_info section. The second element +// in each pair is the length of that CU. References to a CU elsewhere in the +// map are done using a CU index, which is just the 0-based index into this +// table. Note that if there are type CUs, then conceptually CUs and type CUs +// form a single list for the purposes of CU indices."(*) +// 3) The types CU list. Depricated as .debug_types does not appear in the DWARF +// v5 specification. +// 4) The address area. The address area is a sequence of address +// entries, where each entrie contains low address, high address and CU +// index. +// 5) "The symbol table. This is an open-addressed hash table. The size of the +// hash table is always a power of 2. Each slot in the hash table consists of +// a pair of offset_type values. The first value is the offset of the +// symbol's name in the constant pool. The second value is the offset of the +// CU vector in the constant pool."(*) +// 6) "The constant pool. This is simply a bunch of bytes. It is organized so +// that alignment is correct: CU vectors are stored first, followed by +// strings." (*) +// +// For constructing the .gdb_index section following steps should be performed: +// 1) For file header nothing special should be done. It contains the offsets to +// the areas below. +// 2) Scan the compilation unit headers of the .debug_info sections to build a +// list of compilation units. +// 3) CU Types are no longer needed as DWARF skeleton type units never made it +// into the standard. lld does nothing to support parsing of .debug_types +// and generates empty types CU area in .gdb_index section. +// 4) Address area entries are extracted from DW_TAG_compile_unit DIEs of +// .debug_info sections. +// 5) For building the symbol table linker extracts the public names from the +// .debug_gnu_pubnames and .debug_gnu_pubtypes sections. Then it builds the +// hashtable in according to .gdb_index format specification. +// 6) Constant pool is populated at the same time as symbol table. //===----------------------------------------------------------------------===// #include "GdbIndex.h" -#include "Symbols.h" -#include "lld/Common/Memory.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/Object/ELFObjectFile.h" using namespace llvm; using namespace llvm::object; -using namespace lld; using namespace lld::elf; -template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *Obj) { - for (InputSectionBase *Sec : Obj->getSections()) { - if (!Sec) - continue; - if (LLDDWARFSection *M = StringSwitch<LLDDWARFSection *>(Sec->Name) - .Case(".debug_info", &InfoSection) - .Case(".debug_ranges", &RangeSection) - .Case(".debug_line", &LineSection) - .Default(nullptr)) { - Sec->maybeDecompress(); - M->Data = toStringRef(Sec->Data); - M->Sec = Sec; +template <class ELFT> +GdbIndexBuilder<ELFT>::GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec) + : DebugInfoSec(DebugInfoSec) { + if (Expected<std::unique_ptr<object::ObjectFile>> Obj = + object::ObjectFile::createObjectFile(DebugInfoSec->getFile()->MB)) + Dwarf.reset(new DWARFContextInMemory(*Obj.get(), this)); + else + error(toString(DebugInfoSec->getFile()) + ": error creating DWARF context"); +} + +template <class ELFT> +std::vector<std::pair<typename ELFT::uint, typename ELFT::uint>> +GdbIndexBuilder<ELFT>::readCUList() { + std::vector<std::pair<uintX_t, uintX_t>> Ret; + for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units()) + Ret.push_back( + {DebugInfoSec->OutSecOff + CU->getOffset(), CU->getLength() + 4}); + return Ret; +} + +template <class ELFT> +std::vector<std::pair<StringRef, uint8_t>> +GdbIndexBuilder<ELFT>::readPubNamesAndTypes() { + const bool IsLE = ELFT::TargetEndianness == llvm::support::little; + StringRef Data[] = {Dwarf->getGnuPubNamesSection(), + Dwarf->getGnuPubTypesSection()}; + + std::vector<std::pair<StringRef, uint8_t>> Ret; + for (StringRef D : Data) { + DWARFDebugPubTable PubTable(D, IsLE, true); + for (const DWARFDebugPubTable::Set &S : PubTable.getData()) + for (const DWARFDebugPubTable::Entry &E : S.Entries) + Ret.push_back({E.Name, E.Descriptor.toBits()}); + } + return Ret; +} + +std::pair<bool, GdbSymbol *> GdbHashTab::add(uint32_t Hash, size_t Offset) { + if (Size * 4 / 3 >= Table.size()) + expand(); + + GdbSymbol **Slot = findSlot(Hash, Offset); + bool New = false; + if (*Slot == nullptr) { + ++Size; + *Slot = new (Alloc) GdbSymbol(Hash, Offset); + New = true; + } + return {New, *Slot}; +} + +void GdbHashTab::expand() { + if (Table.empty()) { + Table.resize(InitialSize); + return; + } + std::vector<GdbSymbol *> NewTable(Table.size() * 2); + NewTable.swap(Table); + + for (GdbSymbol *Sym : NewTable) { + if (!Sym) continue; - } - if (Sec->Name == ".debug_abbrev") - AbbrevSection = toStringRef(Sec->Data); - else if (Sec->Name == ".debug_gnu_pubnames") - GnuPubNamesSection = toStringRef(Sec->Data); - else if (Sec->Name == ".debug_gnu_pubtypes") - GnuPubTypesSection = toStringRef(Sec->Data); - else if (Sec->Name == ".debug_str") - StrSection = toStringRef(Sec->Data); + GdbSymbol **Slot = findSlot(Sym->NameHash, Sym->NameOffset); + *Slot = Sym; } } -// Find if there is a relocation at Pos in Sec. The code is a bit -// more complicated than usual because we need to pass a section index -// to llvm since it has no idea about InputSection. -template <class ELFT> -template <class RelTy> -Optional<RelocAddrEntry> -LLDDwarfObj<ELFT>::findAux(const InputSectionBase &Sec, uint64_t Pos, - ArrayRef<RelTy> Rels) const { - auto It = std::lower_bound( - Rels.begin(), Rels.end(), Pos, - [](const RelTy &A, uint64_t B) { return A.r_offset < B; }); - if (It == Rels.end() || It->r_offset != Pos) - return None; - const RelTy &Rel = *It; - - const ObjFile<ELFT> *File = Sec.getFile<ELFT>(); - uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); - const typename ELFT::Sym &Sym = File->getELFSyms()[SymIndex]; - uint32_t SecIndex = File->getSectionIndex(Sym); - - // Broken debug info can point to a non-Defined symbol. - auto *DR = dyn_cast<Defined>(&File->getRelocTargetSym(Rel)); - if (!DR) { - error("unsupported relocation target while parsing debug info"); - return None; +// Methods finds a slot for symbol with given hash. The step size used to find +// the next candidate slot when handling a hash collision is specified in +// .gdb_index section format. The hash value for a table entry is computed by +// applying an iterative hash function to the symbol's name. +GdbSymbol **GdbHashTab::findSlot(uint32_t Hash, size_t Offset) { + uint32_t Index = Hash & (Table.size() - 1); + uint32_t Step = ((Hash * 17) & (Table.size() - 1)) | 1; + + for (;;) { + GdbSymbol *S = Table[Index]; + if (!S || ((S->NameOffset == Offset) && (S->NameHash == Hash))) + return &Table[Index]; + Index = (Index + Step) & (Table.size() - 1); } - uint64_t Val = DR->Value + getAddend<ELFT>(Rel); +} - // FIXME: We should be consistent about always adding the file - // offset or not. - if (DR->Section->Flags & ELF::SHF_ALLOC) - Val += cast<InputSection>(DR->Section)->getOffsetInFile(); +template <class ELFT> +static InputSectionBase<ELFT> * +findSection(ArrayRef<InputSectionBase<ELFT> *> Arr, uint64_t Offset) { + for (InputSectionBase<ELFT> *S : Arr) + if (S && S != &InputSection<ELFT>::Discarded) + if (Offset >= S->Offset && Offset < S->Offset + S->getSize()) + return S; + return nullptr; +} - return RelocAddrEntry{SecIndex, Val}; +template <class ELFT> +std::vector<AddressEntry<ELFT>> +GdbIndexBuilder<ELFT>::readAddressArea(size_t CurrentCU) { + std::vector<AddressEntry<ELFT>> Ret; + for (const auto &CU : Dwarf->compile_units()) { + DWARFAddressRangesVector Ranges; + CU->collectAddressRanges(Ranges); + + ArrayRef<InputSectionBase<ELFT> *> Sections = + DebugInfoSec->getFile()->getSections(); + + for (std::pair<uint64_t, uint64_t> &R : Ranges) + if (InputSectionBase<ELFT> *S = findSection(Sections, R.first)) + Ret.push_back( + {S, R.first - S->Offset, R.second - S->Offset, CurrentCU}); + ++CurrentCU; + } + return Ret; +} + +// We return file offset as load address for allocatable sections. That is +// currently used for collecting address ranges in readAddressArea(). We are +// able then to find section index that range belongs to. +template <class ELFT> +uint64_t GdbIndexBuilder<ELFT>::getSectionLoadAddress( + const object::SectionRef &Sec) const { + if (static_cast<const ELFSectionRef &>(Sec).getFlags() & ELF::SHF_ALLOC) + return static_cast<const ELFSectionRef &>(Sec).getOffset(); + return 0; } template <class ELFT> -Optional<RelocAddrEntry> LLDDwarfObj<ELFT>::find(const llvm::DWARFSection &S, - uint64_t Pos) const { - auto &Sec = static_cast<const LLDDWARFSection &>(S); - if (Sec.Sec->AreRelocsRela) - return findAux(*Sec.Sec, Pos, Sec.Sec->template relas<ELFT>()); - return findAux(*Sec.Sec, Pos, Sec.Sec->template rels<ELFT>()); +std::unique_ptr<LoadedObjectInfo> GdbIndexBuilder<ELFT>::clone() const { + return {}; } -template class elf::LLDDwarfObj<ELF32LE>; -template class elf::LLDDwarfObj<ELF32BE>; -template class elf::LLDDwarfObj<ELF64LE>; -template class elf::LLDDwarfObj<ELF64BE>; +namespace lld { +namespace elf { +template class GdbIndexBuilder<ELF32LE>; +template class GdbIndexBuilder<ELF32BE>; +template class GdbIndexBuilder<ELF64LE>; +template class GdbIndexBuilder<ELF64BE>; +} +} diff --git a/gnu/llvm/tools/lld/ELF/GdbIndex.h b/gnu/llvm/tools/lld/ELF/GdbIndex.h index eba1ba22f87..c761ea173a8 100644 --- a/gnu/llvm/tools/lld/ELF/GdbIndex.h +++ b/gnu/llvm/tools/lld/ELF/GdbIndex.h @@ -11,57 +11,86 @@ #define LLD_ELF_GDB_INDEX_H #include "InputFiles.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/Object/ELF.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" namespace lld { namespace elf { -class InputSection; +template <class ELFT> class InputSection; -struct LLDDWARFSection final : public llvm::DWARFSection { - InputSectionBase *Sec = nullptr; +// Struct represents single entry of address area of gdb index. +template <class ELFT> struct AddressEntry { + InputSectionBase<ELFT> *Section; + uint64_t LowAddress; + uint64_t HighAddress; + size_t CuIndex; }; -template <class ELFT> class LLDDwarfObj final : public llvm::DWARFObject { - LLDDWARFSection InfoSection; - LLDDWARFSection RangeSection; - LLDDWARFSection LineSection; - StringRef AbbrevSection; - StringRef GnuPubNamesSection; - StringRef GnuPubTypesSection; - StringRef StrSection; +// GdbIndexBuilder is a helper class used for extracting data required +// for building .gdb_index section from objects. +template <class ELFT> class GdbIndexBuilder : public llvm::LoadedObjectInfo { + typedef typename ELFT::uint uintX_t; + + InputSection<ELFT> *DebugInfoSec; + + std::unique_ptr<llvm::DWARFContext> Dwarf; + +public: + GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec); + + // Extracts the compilation units. Each first element of pair is a offset of a + // CU in the .debug_info section and second is the length of that CU. + std::vector<std::pair<uintX_t, uintX_t>> readCUList(); + + // Extracts the vector of address area entries. Accepts global index of last + // parsed CU. + std::vector<AddressEntry<ELFT>> readAddressArea(size_t CurrentCU); + + // Method extracts public names and types. It returns list of name and + // gnu_pub* kind pairs. + std::vector<std::pair<StringRef, uint8_t>> readPubNamesAndTypes(); - template <class RelTy> - llvm::Optional<llvm::RelocAddrEntry> findAux(const InputSectionBase &Sec, - uint64_t Pos, - ArrayRef<RelTy> Rels) const; +private: + // Method returns section file offset as a load addres for DWARF parser. That + // allows to find the target section index for address ranges. + uint64_t + getSectionLoadAddress(const llvm::object::SectionRef &Sec) const override; + std::unique_ptr<llvm::LoadedObjectInfo> clone() const override; +}; + +// Element of GdbHashTab hash table. +struct GdbSymbol { + GdbSymbol(uint32_t Hash, size_t Offset) + : NameHash(Hash), NameOffset(Offset) {} + uint32_t NameHash; + size_t NameOffset; + size_t CuVectorIndex; +}; +// This class manages the hashed symbol table for the .gdb_index section. +// The hash value for a table entry is computed by applying an iterative hash +// function to the symbol's name. +class GdbHashTab final { public: - explicit LLDDwarfObj(ObjFile<ELFT> *Obj); - const llvm::DWARFSection &getInfoSection() const override { - return InfoSection; - } - const llvm::DWARFSection &getRangeSection() const override { - return RangeSection; - } - const llvm::DWARFSection &getLineSection() const override { - return LineSection; - } - StringRef getFileName() const override { return ""; } - StringRef getAbbrevSection() const override { return AbbrevSection; } - StringRef getStringSection() const override { return StrSection; } - StringRef getGnuPubNamesSection() const override { - return GnuPubNamesSection; - } - StringRef getGnuPubTypesSection() const override { - return GnuPubTypesSection; - } - bool isLittleEndian() const override { - return ELFT::TargetEndianness == llvm::support::little; - } - llvm::Optional<llvm::RelocAddrEntry> find(const llvm::DWARFSection &Sec, - uint64_t Pos) const override; + std::pair<bool, GdbSymbol *> add(uint32_t Hash, size_t Offset); + + size_t getCapacity() { return Table.size(); } + GdbSymbol *getSymbol(size_t I) { return Table[I]; } + +private: + void expand(); + + GdbSymbol **findSlot(uint32_t Hash, size_t Offset); + + llvm::BumpPtrAllocator Alloc; + std::vector<GdbSymbol *> Table; + + // Size keeps the amount of filled entries in Table. + size_t Size = 0; + + // Initial size must be a power of 2. + static const int32_t InitialSize = 1024; }; } // namespace elf diff --git a/gnu/llvm/unittests/Transforms/Utils/FunctionComparator.cpp b/gnu/llvm/unittests/Transforms/Utils/FunctionComparator.cpp index 26e20cd9112..ff68cd6224d 100644 --- a/gnu/llvm/unittests/Transforms/Utils/FunctionComparator.cpp +++ b/gnu/llvm/unittests/Transforms/Utils/FunctionComparator.cpp @@ -10,8 +10,8 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" -#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/LLVMContext.h" #include "gtest/gtest.h" using namespace llvm; |