[ELF] - Partial support of --gdb-index command line option (Part 2).
Patch continues work started in D24706, in this patch address area was added to .gdb_index section output. Differential revision: https://reviews.llvm.org/D25821 llvm-svn: 289790
This commit is contained in:
parent
76e56c6777
commit
8b54739328
|
@ -57,34 +57,33 @@
|
|||
// hashtable in according to .gdb_index format specification.
|
||||
// 6) Constant pool is populated at the same time as symbol table.
|
||||
//
|
||||
// Current version of implementation has 1, 2, 3 steps. So it writes .gdb_index
|
||||
// header and list of compilation units. Since we so not plan to support types
|
||||
// CU list area, it is also empty and so far is "implemented".
|
||||
// Current version implements steps 1-4. So it writes .gdb_index
|
||||
// header, list of compilation units and address area. Since we so not plan to
|
||||
// support types CU list area, it is also empty and so far is "implemented".
|
||||
// Other data areas are not yet implemented.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GdbIndex.h"
|
||||
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/Object/ELFObjectFile.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
using namespace lld::elf;
|
||||
|
||||
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>>
|
||||
lld::elf::readCuList(InputSection<ELFT> *DebugInfoSec) {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
|
||||
std::unique_ptr<DWARFContext> Dwarf;
|
||||
if (Expected<std::unique_ptr<object::ObjectFile>> Obj =
|
||||
object::ObjectFile::createObjectFile(DebugInfoSec->getFile()->MB))
|
||||
Dwarf.reset(new DWARFContextInMemory(*Obj.get()));
|
||||
|
||||
if (!Dwarf) {
|
||||
error(toString(DebugInfoSec->getFile()) + ": error creating DWARF context");
|
||||
return {};
|
||||
}
|
||||
|
||||
GdbIndexBuilder<ELFT>::readCUList() {
|
||||
std::vector<std::pair<uintX_t, uintX_t>> Ret;
|
||||
for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units())
|
||||
Ret.push_back(
|
||||
|
@ -92,11 +91,52 @@ lld::elf::readCuList(InputSection<ELFT> *DebugInfoSec) {
|
|||
return Ret;
|
||||
}
|
||||
|
||||
template std::vector<std::pair<uint32_t, uint32_t>>
|
||||
lld::elf::readCuList<ELF32LE>(InputSection<ELF32LE> *);
|
||||
template std::vector<std::pair<uint32_t, uint32_t>>
|
||||
lld::elf::readCuList<ELF32BE>(InputSection<ELF32BE> *);
|
||||
template std::vector<std::pair<uint64_t, uint64_t>>
|
||||
lld::elf::readCuList<ELF64LE>(InputSection<ELF64LE> *);
|
||||
template std::vector<std::pair<uint64_t, uint64_t>>
|
||||
lld::elf::readCuList<ELF64BE>(InputSection<ELF64BE> *);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
uint64_t GdbIndexBuilder<ELFT>::getSectionLoadAddress(
|
||||
const object::SectionRef &Sec) const {
|
||||
return static_cast<const ELFSectionRef &>(Sec).getOffset();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
std::unique_ptr<LoadedObjectInfo> GdbIndexBuilder<ELFT>::clone() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
template class GdbIndexBuilder<ELF32LE>;
|
||||
template class GdbIndexBuilder<ELF32BE>;
|
||||
template class GdbIndexBuilder<ELF64LE>;
|
||||
template class GdbIndexBuilder<ELF64BE>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,15 +12,48 @@
|
|||
|
||||
#include "InputFiles.h"
|
||||
#include "llvm/Object/ELF.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
template <class ELFT> class InputSection;
|
||||
|
||||
template <class ELFT>
|
||||
std::vector<std::pair<typename ELFT::uint, typename ELFT::uint>>
|
||||
readCuList(InputSection<ELFT> *Sec);
|
||||
// Struct represents single entry of address area of gdb index.
|
||||
template <class ELFT> struct AddressEntry {
|
||||
InputSectionBase<ELFT> *Section;
|
||||
uint64_t LowAddress;
|
||||
uint64_t HighAddress;
|
||||
uint32_t CuIndex;
|
||||
};
|
||||
|
||||
// GdbIndexBuilder is a helper class used for extracting data required
|
||||
// for building .gdb_index section from objects.
|
||||
template <class ELFT> class GdbIndexBuilder : public 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);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace elf
|
||||
} // namespace lld
|
||||
|
|
|
@ -1460,34 +1460,51 @@ GdbIndexSection<ELFT>::GdbIndexSection()
|
|||
: SyntheticSection<ELFT>(0, SHT_PROGBITS, 1, ".gdb_index") {}
|
||||
|
||||
template <class ELFT> void GdbIndexSection<ELFT>::parseDebugSections() {
|
||||
std::vector<InputSection<ELFT> *> &IS =
|
||||
static_cast<OutputSection<ELFT> *>(Out<ELFT>::DebugInfo)->Sections;
|
||||
|
||||
for (InputSection<ELFT> *I : IS)
|
||||
readDwarf(I);
|
||||
for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections)
|
||||
if (InputSection<ELFT> *IS = dyn_cast<InputSection<ELFT>>(S))
|
||||
if (IS->OutSec && IS->Name == ".debug_info")
|
||||
readDwarf(IS);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void GdbIndexSection<ELFT>::readDwarf(InputSection<ELFT> *I) {
|
||||
std::vector<std::pair<uintX_t, uintX_t>> CuList = readCuList(I);
|
||||
GdbIndexBuilder<ELFT> Builder(I);
|
||||
if (ErrorCount)
|
||||
return;
|
||||
|
||||
size_t CuId = CompilationUnits.size();
|
||||
std::vector<std::pair<uintX_t, uintX_t>> CuList = Builder.readCUList();
|
||||
CompilationUnits.insert(CompilationUnits.end(), CuList.begin(), CuList.end());
|
||||
|
||||
std::vector<AddressEntry<ELFT>> AddrArea = Builder.readAddressArea(CuId);
|
||||
AddressArea.insert(AddressArea.end(), AddrArea.begin(), AddrArea.end());
|
||||
}
|
||||
|
||||
template <class ELFT> void GdbIndexSection<ELFT>::finalize() {
|
||||
if (Finalized)
|
||||
return;
|
||||
Finalized = true;
|
||||
|
||||
parseDebugSections();
|
||||
|
||||
// GdbIndex header consist from version fields
|
||||
// and 5 more fields with different kinds of offsets.
|
||||
CuTypesOffset = CuListOffset + CompilationUnits.size() * CompilationUnitSize;
|
||||
SymTabOffset = CuTypesOffset + AddressArea.size() * AddressEntrySize;
|
||||
}
|
||||
|
||||
template <class ELFT> size_t GdbIndexSection<ELFT>::getSize() const {
|
||||
const_cast<GdbIndexSection<ELFT> *>(this)->finalize();
|
||||
return SymTabOffset;
|
||||
}
|
||||
|
||||
template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
write32le(Buf, 7); // Write Version
|
||||
write32le(Buf + 4, CuListOffset); // CU list offset
|
||||
write32le(Buf + 8, CuTypesOffset); // Types CU list offset
|
||||
write32le(Buf + 12, CuTypesOffset); // Address area offset
|
||||
write32le(Buf + 16, CuTypesOffset); // Symbol table offset
|
||||
write32le(Buf + 20, CuTypesOffset); // Constant pool offset
|
||||
write32le(Buf, 7); // Write version.
|
||||
write32le(Buf + 4, CuListOffset); // CU list offset.
|
||||
write32le(Buf + 8, CuTypesOffset); // Types CU list offset.
|
||||
write32le(Buf + 12, CuTypesOffset); // Address area offset.
|
||||
write32le(Buf + 16, SymTabOffset); // Symbol table offset.
|
||||
write32le(Buf + 20, SymTabOffset); // Constant pool offset.
|
||||
Buf += 24;
|
||||
|
||||
// Write the CU list.
|
||||
|
@ -1496,6 +1513,15 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
write64le(Buf + 8, CU.second);
|
||||
Buf += 16;
|
||||
}
|
||||
|
||||
// Write the address area.
|
||||
for (AddressEntry<ELFT> &E : AddressArea) {
|
||||
uintX_t BaseAddr = E.Section->OutSec->Addr + E.Section->getOffset(0);
|
||||
write64le(Buf, BaseAddr + E.LowAddress);
|
||||
write64le(Buf + 8, BaseAddr + E.HighAddress);
|
||||
write32le(Buf + 16, E.CuIndex);
|
||||
Buf += 20;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> bool GdbIndexSection<ELFT>::empty() const {
|
||||
|
|
|
@ -479,17 +479,22 @@ public:
|
|||
GdbIndexSection();
|
||||
void finalize() override;
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
size_t getSize() const override { return CuTypesOffset; }
|
||||
size_t getSize() const override;
|
||||
bool empty() const override;
|
||||
|
||||
// Pairs of [CU Offset, CU length].
|
||||
std::vector<std::pair<uintX_t, uintX_t>> CompilationUnits;
|
||||
|
||||
std::vector<AddressEntry<ELFT>> AddressArea;
|
||||
|
||||
private:
|
||||
void parseDebugSections();
|
||||
void readDwarf(InputSection<ELFT> *I);
|
||||
|
||||
uint32_t CuTypesOffset;
|
||||
uint32_t SymTabOffset;
|
||||
|
||||
bool Finalized = false;
|
||||
};
|
||||
|
||||
// --eh-frame-hdr option tells linker to construct a header for all the
|
||||
|
|
|
@ -31,8 +31,10 @@
|
|||
# CHECK: .gnu_index contents:
|
||||
# CHECK-NEXT: Version = 7
|
||||
# CHECK: CU list offset = 0x18, has 2 entries:
|
||||
# CHECK-NEXT: 0: Offset = 0x0, Length = 0x34
|
||||
# CHECK-NEXT: 1: Offset = 0x34, Length = 0x34
|
||||
# CHECK: Address area offset = 0x38, has 0 entries:
|
||||
# CHECK: Symbol table offset = 0x38, size = 0, filled slots:
|
||||
# CHECK: Constant pool offset = 0x38, has 0 CU vectors:
|
||||
# CHECK-NEXT: 0: Offset = 0x0, Length = 0x34
|
||||
# CHECK-NEXT: 1: Offset = 0x34, Length = 0x34
|
||||
# CHECK: Address area offset = 0x38, has 2 entries:
|
||||
# CHECK-NEXT: Low address = 0x201000, High address = 0x20100b, CU index = 0
|
||||
# CHECK-NEXT: Low address = 0x20100b, High address = 0x201016, CU index = 1
|
||||
# CHECK: Symbol table offset = 0x60, size = 0, filled slots:
|
||||
# CHECK: Constant pool offset = 0x60, has 0 CU vectors:
|
||||
|
|
Loading…
Reference in New Issue