2018-09-15 07:51:05 +08:00
|
|
|
//===- DWARF.cpp ----------------------------------------------------------===//
|
2016-10-20 17:19:48 +08:00
|
|
|
//
|
|
|
|
// The LLVM Linker
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2017-03-29 08:09:40 +08:00
|
|
|
// 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.
|
2016-10-20 17:19:48 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-09-15 07:51:05 +08:00
|
|
|
#include "DWARF.h"
|
2017-12-10 00:56:18 +08:00
|
|
|
#include "Symbols.h"
|
2018-09-26 16:11:34 +08:00
|
|
|
#include "Target.h"
|
2017-11-29 04:39:17 +08:00
|
|
|
#include "lld/Common/Memory.h"
|
2016-12-17 18:18:05 +08:00
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
|
2016-12-15 17:08:13 +08:00
|
|
|
#include "llvm/Object/ELFObjectFile.h"
|
2016-10-20 17:19:48 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::object;
|
2017-03-02 06:03:17 +08:00
|
|
|
using namespace lld;
|
2016-12-15 17:08:13 +08:00
|
|
|
using namespace lld::elf;
|
2016-10-20 17:19:48 +08:00
|
|
|
|
2017-09-25 07:12:36 +08:00
|
|
|
template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *Obj) {
|
2017-07-20 06:27:35 +08:00
|
|
|
for (InputSectionBase *Sec : Obj->getSections()) {
|
|
|
|
if (!Sec)
|
|
|
|
continue;
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
|
2017-07-20 06:27:35 +08:00
|
|
|
if (LLDDWARFSection *M = StringSwitch<LLDDWARFSection *>(Sec->Name)
|
|
|
|
.Case(".debug_info", &InfoSection)
|
|
|
|
.Case(".debug_ranges", &RangeSection)
|
|
|
|
.Case(".debug_line", &LineSection)
|
|
|
|
.Default(nullptr)) {
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
M->Data = toStringRef(Sec->data());
|
2017-07-20 06:27:35 +08:00
|
|
|
M->Sec = Sec;
|
|
|
|
continue;
|
|
|
|
}
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
|
2017-07-20 06:27:35 +08:00
|
|
|
if (Sec->Name == ".debug_abbrev")
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
AbbrevSection = toStringRef(Sec->data());
|
2017-07-20 06:27:35 +08:00
|
|
|
else if (Sec->Name == ".debug_gnu_pubnames")
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
GnuPubNamesSection = toStringRef(Sec->data());
|
2017-07-20 06:27:35 +08:00
|
|
|
else if (Sec->Name == ".debug_gnu_pubtypes")
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
GnuPubTypesSection = toStringRef(Sec->data());
|
2017-11-17 19:57:47 +08:00
|
|
|
else if (Sec->Name == ".debug_str")
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
StrSection = toStringRef(Sec->data());
|
|
|
|
else if (Sec->Name == ".debug_line_str")
|
|
|
|
LineStringSection = toStringRef(Sec->data());
|
2017-07-20 06:27:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2017-08-01 12:11:03 +08:00
|
|
|
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)
|
2017-07-20 06:27:35 +08:00
|
|
|
return None;
|
2017-08-01 12:11:03 +08:00
|
|
|
const RelTy &Rel = *It;
|
|
|
|
|
2017-07-27 06:13:32 +08:00
|
|
|
const ObjFile<ELFT> *File = Sec.getFile<ELFT>();
|
2017-07-20 06:27:35 +08:00
|
|
|
uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
|
2017-08-03 01:35:18 +08:00
|
|
|
const typename ELFT::Sym &Sym = File->getELFSyms()[SymIndex];
|
2017-07-20 06:27:35 +08:00
|
|
|
uint32_t SecIndex = File->getSectionIndex(Sym);
|
2017-11-30 06:09:16 +08:00
|
|
|
|
2017-11-30 13:37:35 +08:00
|
|
|
// Broken debug info can point to a non-Defined symbol.
|
2017-11-30 06:09:16 +08:00
|
|
|
auto *DR = dyn_cast<Defined>(&File->getRelocTargetSym(Rel));
|
2017-11-30 13:37:35 +08:00
|
|
|
if (!DR) {
|
2018-09-26 16:11:34 +08:00
|
|
|
RelType Type = Rel.getType(Config->IsMips64EL);
|
|
|
|
if (Type != Target->NoneRel)
|
|
|
|
error(toString(File) + ": relocation " + lld::toString(Type) + " at 0x" +
|
|
|
|
llvm::utohexstr(Rel.r_offset) + " has unsupported target");
|
2017-11-30 06:09:16 +08:00
|
|
|
return None;
|
2017-11-30 13:37:35 +08:00
|
|
|
}
|
2017-11-30 06:09:16 +08:00
|
|
|
uint64_t Val = DR->Value + getAddend<ELFT>(Rel);
|
2017-07-20 06:27:35 +08:00
|
|
|
|
|
|
|
// FIXME: We should be consistent about always adding the file
|
|
|
|
// offset or not.
|
2017-11-30 06:09:16 +08:00
|
|
|
if (DR->Section->Flags & ELF::SHF_ALLOC)
|
|
|
|
Val += cast<InputSection>(DR->Section)->getOffsetInFile();
|
2017-07-20 06:27:35 +08:00
|
|
|
|
2017-08-01 12:18:57 +08:00
|
|
|
return RelocAddrEntry{SecIndex, Val};
|
2017-07-20 06:27:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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>());
|
|
|
|
}
|
|
|
|
|
|
|
|
template class elf::LLDDwarfObj<ELF32LE>;
|
|
|
|
template class elf::LLDDwarfObj<ELF32BE>;
|
|
|
|
template class elf::LLDDwarfObj<ELF64LE>;
|
|
|
|
template class elf::LLDDwarfObj<ELF64BE>;
|