summaryrefslogtreecommitdiff
path: root/gnu/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm')
-rw-r--r--gnu/llvm/tools/clang/lib/Analysis/OSLog.cpp3
-rw-r--r--gnu/llvm/tools/lld/ELF/GdbIndex.cpp242
-rw-r--r--gnu/llvm/tools/lld/ELF/GdbIndex.h109
-rw-r--r--gnu/llvm/unittests/Transforms/Utils/FunctionComparator.cpp2
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;