[DWARFYAML] Refactor emitDebugInfo() to make the length be inferred.
This patch refactors `emitDebugInfo()` to make the length field be inferred from its content. Besides, the `Visitor` class is removed in this patch. The original `Visitor` class helps us determine an appropriate length and emit the .debug_info section. These two processes can be merged into one process. Besides, the length field should be inferred when it's missing rather than when it's zero. Reviewed By: jhenderson, labath Differential Revision: https://reviews.llvm.org/D84008
This commit is contained in:
parent
a997e6edb9
commit
92874d2866
|
@ -93,7 +93,7 @@ public:
|
||||||
|
|
||||||
YAMLModuleTester::YAMLModuleTester(llvm::StringRef yaml_data,
|
YAMLModuleTester::YAMLModuleTester(llvm::StringRef yaml_data,
|
||||||
llvm::StringRef triple) {
|
llvm::StringRef triple) {
|
||||||
auto sections_map = llvm::DWARFYAML::emitDebugSections(yaml_data, true);
|
auto sections_map = llvm::DWARFYAML::emitDebugSections(yaml_data);
|
||||||
if (!sections_map)
|
if (!sections_map)
|
||||||
return;
|
return;
|
||||||
m_sections_map = std::move(*sections_map);
|
m_sections_map = std::move(*sections_map);
|
||||||
|
|
|
@ -42,7 +42,7 @@ Error emitDebugStrOffsets(raw_ostream &OS, const Data &DI);
|
||||||
Error emitDebugRnglists(raw_ostream &OS, const Data &DI);
|
Error emitDebugRnglists(raw_ostream &OS, const Data &DI);
|
||||||
|
|
||||||
Expected<StringMap<std::unique_ptr<MemoryBuffer>>>
|
Expected<StringMap<std::unique_ptr<MemoryBuffer>>>
|
||||||
emitDebugSections(StringRef YAMLString, bool ApplyFixups = false,
|
emitDebugSections(StringRef YAMLString,
|
||||||
bool IsLittleEndian = sys::IsLittleEndianHost);
|
bool IsLittleEndian = sys::IsLittleEndianHost);
|
||||||
} // end namespace DWARFYAML
|
} // end namespace DWARFYAML
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
|
@ -120,7 +120,7 @@ struct DWARFContext {
|
||||||
|
|
||||||
struct Unit {
|
struct Unit {
|
||||||
dwarf::DwarfFormat Format;
|
dwarf::DwarfFormat Format;
|
||||||
yaml::Hex64 Length;
|
Optional<yaml::Hex64> Length;
|
||||||
uint16_t Version;
|
uint16_t Version;
|
||||||
llvm::dwarf::UnitType Type; // Added in DWARF 5
|
llvm::dwarf::UnitType Type; // Added in DWARF 5
|
||||||
yaml::Hex64 AbbrOffset;
|
yaml::Hex64 AbbrOffset;
|
||||||
|
|
|
@ -6,7 +6,6 @@ add_llvm_component_library(LLVMObjectYAML
|
||||||
COFFEmitter.cpp
|
COFFEmitter.cpp
|
||||||
COFFYAML.cpp
|
COFFYAML.cpp
|
||||||
DWARFEmitter.cpp
|
DWARFEmitter.cpp
|
||||||
DWARFVisitor.cpp
|
|
||||||
DWARFYAML.cpp
|
DWARFYAML.cpp
|
||||||
ELFEmitter.cpp
|
ELFEmitter.cpp
|
||||||
ELFYAML.cpp
|
ELFYAML.cpp
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "llvm/ObjectYAML/DWARFEmitter.h"
|
#include "llvm/ObjectYAML/DWARFEmitter.h"
|
||||||
#include "DWARFVisitor.h"
|
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
@ -205,79 +204,194 @@ Error DWARFYAML::emitPubSection(raw_ostream &OS,
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
static unsigned getOffsetSize(const DWARFYAML::Unit &Unit) {
|
||||||
/// An extension of the DWARFYAML::ConstVisitor which writes compile
|
return Unit.Format == dwarf::DWARF64 ? 8 : 4;
|
||||||
/// units and DIEs to a stream.
|
}
|
||||||
class DumpVisitor : public DWARFYAML::ConstVisitor {
|
|
||||||
raw_ostream &OS;
|
|
||||||
|
|
||||||
protected:
|
static unsigned getRefSize(const DWARFYAML::Unit &Unit) {
|
||||||
void onStartCompileUnit(const DWARFYAML::Unit &CU) override {
|
if (Unit.Version == 2)
|
||||||
writeInitialLength(CU.Format, CU.Length, OS, DebugInfo.IsLittleEndian);
|
return Unit.AddrSize;
|
||||||
writeInteger((uint16_t)CU.Version, OS, DebugInfo.IsLittleEndian);
|
return getOffsetSize(Unit);
|
||||||
if (CU.Version >= 5) {
|
}
|
||||||
writeInteger((uint8_t)CU.Type, OS, DebugInfo.IsLittleEndian);
|
|
||||||
writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian);
|
static Expected<uint64_t> writeDIE(ArrayRef<DWARFYAML::Abbrev> AbbrevDecls,
|
||||||
cantFail(writeVariableSizedInteger(CU.AbbrOffset,
|
const DWARFYAML::Unit &Unit,
|
||||||
CU.Format == dwarf::DWARF64 ? 8 : 4,
|
const DWARFYAML::Entry &Entry,
|
||||||
OS, DebugInfo.IsLittleEndian));
|
raw_ostream &OS, bool IsLittleEndian) {
|
||||||
} else {
|
uint64_t EntryBegin = OS.tell();
|
||||||
cantFail(writeVariableSizedInteger(CU.AbbrOffset,
|
encodeULEB128(Entry.AbbrCode, OS);
|
||||||
CU.Format == dwarf::DWARF64 ? 8 : 4,
|
uint32_t AbbrCode = Entry.AbbrCode;
|
||||||
OS, DebugInfo.IsLittleEndian));
|
if (AbbrCode == 0 || Entry.Values.empty())
|
||||||
writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian);
|
return OS.tell() - EntryBegin;
|
||||||
}
|
|
||||||
|
if (AbbrCode > AbbrevDecls.size())
|
||||||
|
return createStringError(
|
||||||
|
errc::invalid_argument,
|
||||||
|
"abbrev code must be less than or equal to the number of "
|
||||||
|
"entries in abbreviation table");
|
||||||
|
const DWARFYAML::Abbrev &Abbrev = AbbrevDecls[AbbrCode - 1];
|
||||||
|
auto FormVal = Entry.Values.begin();
|
||||||
|
auto AbbrForm = Abbrev.Attributes.begin();
|
||||||
|
for (; FormVal != Entry.Values.end() && AbbrForm != Abbrev.Attributes.end();
|
||||||
|
++FormVal, ++AbbrForm) {
|
||||||
|
dwarf::Form Form = AbbrForm->Form;
|
||||||
|
bool Indirect;
|
||||||
|
do {
|
||||||
|
Indirect = false;
|
||||||
|
switch (Form) {
|
||||||
|
case dwarf::DW_FORM_addr:
|
||||||
|
// TODO: Test this error.
|
||||||
|
if (Error Err = writeVariableSizedInteger(FormVal->Value, Unit.AddrSize,
|
||||||
|
OS, IsLittleEndian))
|
||||||
|
return std::move(Err);
|
||||||
|
break;
|
||||||
|
case dwarf::DW_FORM_ref_addr:
|
||||||
|
// TODO: Test this error.
|
||||||
|
if (Error Err = writeVariableSizedInteger(
|
||||||
|
FormVal->Value, getRefSize(Unit), OS, IsLittleEndian))
|
||||||
|
return std::move(Err);
|
||||||
|
break;
|
||||||
|
case dwarf::DW_FORM_exprloc:
|
||||||
|
case dwarf::DW_FORM_block:
|
||||||
|
encodeULEB128(FormVal->BlockData.size(), OS);
|
||||||
|
OS.write((const char *)FormVal->BlockData.data(),
|
||||||
|
FormVal->BlockData.size());
|
||||||
|
break;
|
||||||
|
case dwarf::DW_FORM_block1: {
|
||||||
|
writeInteger((uint8_t)FormVal->BlockData.size(), OS, IsLittleEndian);
|
||||||
|
OS.write((const char *)FormVal->BlockData.data(),
|
||||||
|
FormVal->BlockData.size());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case dwarf::DW_FORM_block2: {
|
||||||
|
writeInteger((uint16_t)FormVal->BlockData.size(), OS, IsLittleEndian);
|
||||||
|
OS.write((const char *)FormVal->BlockData.data(),
|
||||||
|
FormVal->BlockData.size());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case dwarf::DW_FORM_block4: {
|
||||||
|
writeInteger((uint32_t)FormVal->BlockData.size(), OS, IsLittleEndian);
|
||||||
|
OS.write((const char *)FormVal->BlockData.data(),
|
||||||
|
FormVal->BlockData.size());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case dwarf::DW_FORM_strx:
|
||||||
|
case dwarf::DW_FORM_addrx:
|
||||||
|
case dwarf::DW_FORM_rnglistx:
|
||||||
|
case dwarf::DW_FORM_loclistx:
|
||||||
|
case dwarf::DW_FORM_udata:
|
||||||
|
case dwarf::DW_FORM_ref_udata:
|
||||||
|
case dwarf::DW_FORM_GNU_addr_index:
|
||||||
|
case dwarf::DW_FORM_GNU_str_index:
|
||||||
|
encodeULEB128(FormVal->Value, OS);
|
||||||
|
break;
|
||||||
|
case dwarf::DW_FORM_data1:
|
||||||
|
case dwarf::DW_FORM_ref1:
|
||||||
|
case dwarf::DW_FORM_flag:
|
||||||
|
case dwarf::DW_FORM_strx1:
|
||||||
|
case dwarf::DW_FORM_addrx1:
|
||||||
|
writeInteger((uint8_t)FormVal->Value, OS, IsLittleEndian);
|
||||||
|
break;
|
||||||
|
case dwarf::DW_FORM_data2:
|
||||||
|
case dwarf::DW_FORM_ref2:
|
||||||
|
case dwarf::DW_FORM_strx2:
|
||||||
|
case dwarf::DW_FORM_addrx2:
|
||||||
|
writeInteger((uint16_t)FormVal->Value, OS, IsLittleEndian);
|
||||||
|
break;
|
||||||
|
case dwarf::DW_FORM_data4:
|
||||||
|
case dwarf::DW_FORM_ref4:
|
||||||
|
case dwarf::DW_FORM_ref_sup4:
|
||||||
|
case dwarf::DW_FORM_strx4:
|
||||||
|
case dwarf::DW_FORM_addrx4:
|
||||||
|
writeInteger((uint32_t)FormVal->Value, OS, IsLittleEndian);
|
||||||
|
break;
|
||||||
|
case dwarf::DW_FORM_data8:
|
||||||
|
case dwarf::DW_FORM_ref8:
|
||||||
|
case dwarf::DW_FORM_ref_sup8:
|
||||||
|
case dwarf::DW_FORM_ref_sig8:
|
||||||
|
writeInteger((uint64_t)FormVal->Value, OS, IsLittleEndian);
|
||||||
|
break;
|
||||||
|
case dwarf::DW_FORM_sdata:
|
||||||
|
encodeSLEB128(FormVal->Value, OS);
|
||||||
|
break;
|
||||||
|
case dwarf::DW_FORM_string:
|
||||||
|
OS.write(FormVal->CStr.data(), FormVal->CStr.size());
|
||||||
|
OS.write('\0');
|
||||||
|
break;
|
||||||
|
case dwarf::DW_FORM_indirect:
|
||||||
|
encodeULEB128(FormVal->Value, OS);
|
||||||
|
Indirect = true;
|
||||||
|
Form = static_cast<dwarf::Form>((uint64_t)FormVal->Value);
|
||||||
|
++FormVal;
|
||||||
|
break;
|
||||||
|
case dwarf::DW_FORM_strp:
|
||||||
|
case dwarf::DW_FORM_sec_offset:
|
||||||
|
case dwarf::DW_FORM_GNU_ref_alt:
|
||||||
|
case dwarf::DW_FORM_GNU_strp_alt:
|
||||||
|
case dwarf::DW_FORM_line_strp:
|
||||||
|
case dwarf::DW_FORM_strp_sup:
|
||||||
|
// TODO: Test this error.
|
||||||
|
if (Error Err = writeVariableSizedInteger(
|
||||||
|
FormVal->Value, getOffsetSize(Unit), OS, IsLittleEndian))
|
||||||
|
return std::move(Err);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (Indirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onStartDIE(const DWARFYAML::Unit &CU,
|
return OS.tell() - EntryBegin;
|
||||||
const DWARFYAML::Entry &DIE) override {
|
}
|
||||||
encodeULEB128(DIE.AbbrCode, OS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onValue(const uint8_t U) override {
|
static void writeDWARFOffset(uint64_t Offset, dwarf::DwarfFormat Format,
|
||||||
writeInteger(U, OS, DebugInfo.IsLittleEndian);
|
raw_ostream &OS, bool IsLittleEndian) {
|
||||||
}
|
cantFail(writeVariableSizedInteger(Offset, Format == dwarf::DWARF64 ? 8 : 4,
|
||||||
|
OS, IsLittleEndian));
|
||||||
void onValue(const uint16_t U) override {
|
}
|
||||||
writeInteger(U, OS, DebugInfo.IsLittleEndian);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onValue(const uint32_t U) override {
|
|
||||||
writeInteger(U, OS, DebugInfo.IsLittleEndian);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onValue(const uint64_t U, const bool LEB = false) override {
|
|
||||||
if (LEB)
|
|
||||||
encodeULEB128(U, OS);
|
|
||||||
else
|
|
||||||
writeInteger(U, OS, DebugInfo.IsLittleEndian);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onValue(const int64_t S, const bool LEB = false) override {
|
|
||||||
if (LEB)
|
|
||||||
encodeSLEB128(S, OS);
|
|
||||||
else
|
|
||||||
writeInteger(S, OS, DebugInfo.IsLittleEndian);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onValue(const StringRef String) override {
|
|
||||||
OS.write(String.data(), String.size());
|
|
||||||
OS.write('\0');
|
|
||||||
}
|
|
||||||
|
|
||||||
void onValue(const MemoryBufferRef MBR) override {
|
|
||||||
OS.write(MBR.getBufferStart(), MBR.getBufferSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
DumpVisitor(const DWARFYAML::Data &DI, raw_ostream &Out)
|
|
||||||
: DWARFYAML::ConstVisitor(DI), OS(Out) {}
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
Error DWARFYAML::emitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) {
|
Error DWARFYAML::emitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) {
|
||||||
DumpVisitor Visitor(DI, OS);
|
for (const DWARFYAML::Unit &Unit : DI.CompileUnits) {
|
||||||
return Visitor.traverseDebugInfo();
|
uint64_t Length = 3; // sizeof(version) + sizeof(address_size)
|
||||||
|
Length += Unit.Version >= 5 ? 1 : 0; // sizeof(unit_type)
|
||||||
|
Length +=
|
||||||
|
Unit.Format == dwarf::DWARF64 ? 8 : 4; // sizeof(debug_abbrev_offset)
|
||||||
|
|
||||||
|
// Since the length of the current compilation unit is undetermined yet, we
|
||||||
|
// firstly write the content of the compilation unit to a buffer to
|
||||||
|
// calculate it and then serialize the buffer content to the actual output
|
||||||
|
// stream.
|
||||||
|
std::string EntryBuffer;
|
||||||
|
raw_string_ostream EntryBufferOS(EntryBuffer);
|
||||||
|
|
||||||
|
for (const DWARFYAML::Entry &Entry : Unit.Entries) {
|
||||||
|
if (Expected<uint64_t> EntryLength = writeDIE(
|
||||||
|
DI.AbbrevDecls, Unit, Entry, EntryBufferOS, DI.IsLittleEndian))
|
||||||
|
Length += *EntryLength;
|
||||||
|
else
|
||||||
|
return EntryLength.takeError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the length is specified in the YAML description, we use it instead of
|
||||||
|
// the actual length.
|
||||||
|
if (Unit.Length)
|
||||||
|
Length = *Unit.Length;
|
||||||
|
|
||||||
|
writeInitialLength(Unit.Format, Length, OS, DI.IsLittleEndian);
|
||||||
|
writeInteger((uint16_t)Unit.Version, OS, DI.IsLittleEndian);
|
||||||
|
if (Unit.Version >= 5) {
|
||||||
|
writeInteger((uint8_t)Unit.Type, OS, DI.IsLittleEndian);
|
||||||
|
writeInteger((uint8_t)Unit.AddrSize, OS, DI.IsLittleEndian);
|
||||||
|
writeDWARFOffset(Unit.AbbrOffset, Unit.Format, OS, DI.IsLittleEndian);
|
||||||
|
} else {
|
||||||
|
writeDWARFOffset(Unit.AbbrOffset, Unit.Format, OS, DI.IsLittleEndian);
|
||||||
|
writeInteger((uint8_t)Unit.AddrSize, OS, DI.IsLittleEndian);
|
||||||
|
}
|
||||||
|
|
||||||
|
OS.write(EntryBuffer.data(), EntryBuffer.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) {
|
static void emitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) {
|
||||||
|
@ -634,51 +748,8 @@ emitDebugSectionImpl(const DWARFYAML::Data &DI, EmitFuncType EmitFunc,
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
class DIEFixupVisitor : public DWARFYAML::Visitor {
|
|
||||||
uint64_t Length;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DIEFixupVisitor(DWARFYAML::Data &DI) : DWARFYAML::Visitor(DI){};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onStartCompileUnit(DWARFYAML::Unit &CU) override {
|
|
||||||
// Size of the unit header, excluding the length field itself.
|
|
||||||
Length = CU.Version >= 5 ? 8 : 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onEndCompileUnit(DWARFYAML::Unit &CU) override { CU.Length = Length; }
|
|
||||||
|
|
||||||
void onStartDIE(DWARFYAML::Unit &CU, DWARFYAML::Entry &DIE) override {
|
|
||||||
Length += getULEB128Size(DIE.AbbrCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onValue(const uint8_t U) override { Length += 1; }
|
|
||||||
void onValue(const uint16_t U) override { Length += 2; }
|
|
||||||
void onValue(const uint32_t U) override { Length += 4; }
|
|
||||||
void onValue(const uint64_t U, const bool LEB = false) override {
|
|
||||||
if (LEB)
|
|
||||||
Length += getULEB128Size(U);
|
|
||||||
else
|
|
||||||
Length += 8;
|
|
||||||
}
|
|
||||||
void onValue(const int64_t S, const bool LEB = false) override {
|
|
||||||
if (LEB)
|
|
||||||
Length += getSLEB128Size(S);
|
|
||||||
else
|
|
||||||
Length += 8;
|
|
||||||
}
|
|
||||||
void onValue(const StringRef String) override { Length += String.size() + 1; }
|
|
||||||
|
|
||||||
void onValue(const MemoryBufferRef MBR) override {
|
|
||||||
Length += MBR.getBufferSize();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
Expected<StringMap<std::unique_ptr<MemoryBuffer>>>
|
Expected<StringMap<std::unique_ptr<MemoryBuffer>>>
|
||||||
DWARFYAML::emitDebugSections(StringRef YAMLString, bool ApplyFixups,
|
DWARFYAML::emitDebugSections(StringRef YAMLString, bool IsLittleEndian) {
|
||||||
bool IsLittleEndian) {
|
|
||||||
auto CollectDiagnostic = [](const SMDiagnostic &Diag, void *DiagContext) {
|
auto CollectDiagnostic = [](const SMDiagnostic &Diag, void *DiagContext) {
|
||||||
*static_cast<SMDiagnostic *>(DiagContext) = Diag;
|
*static_cast<SMDiagnostic *>(DiagContext) = Diag;
|
||||||
};
|
};
|
||||||
|
@ -693,12 +764,6 @@ DWARFYAML::emitDebugSections(StringRef YAMLString, bool ApplyFixups,
|
||||||
if (YIn.error())
|
if (YIn.error())
|
||||||
return createStringError(YIn.error(), GeneratedDiag.getMessage());
|
return createStringError(YIn.error(), GeneratedDiag.getMessage());
|
||||||
|
|
||||||
if (ApplyFixups) {
|
|
||||||
DIEFixupVisitor DIFixer(DI);
|
|
||||||
if (Error Err = DIFixer.traverseDebugInfo())
|
|
||||||
return std::move(Err);
|
|
||||||
}
|
|
||||||
|
|
||||||
StringMap<std::unique_ptr<MemoryBuffer>> DebugSections;
|
StringMap<std::unique_ptr<MemoryBuffer>> DebugSections;
|
||||||
Error Err = emitDebugSectionImpl(DI, &DWARFYAML::emitDebugInfo, "debug_info",
|
Error Err = emitDebugSectionImpl(DI, &DWARFYAML::emitDebugInfo, "debug_info",
|
||||||
DebugSections);
|
DebugSections);
|
||||||
|
|
|
@ -1,188 +0,0 @@
|
||||||
//===--- DWARFVisitor.cpp ---------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "DWARFVisitor.h"
|
|
||||||
#include "llvm/BinaryFormat/Dwarf.h"
|
|
||||||
#include "llvm/ObjectYAML/DWARFYAML.h"
|
|
||||||
#include "llvm/Support/Errc.h"
|
|
||||||
#include "llvm/Support/Error.h"
|
|
||||||
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void DWARFYAML::VisitorImpl<T>::onVariableSizeValue(uint64_t U, unsigned Size) {
|
|
||||||
switch (Size) {
|
|
||||||
case 8:
|
|
||||||
onValue((uint64_t)U);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
onValue((uint32_t)U);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
onValue((uint16_t)U);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
onValue((uint8_t)U);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
llvm_unreachable("Invalid integer write size.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned getOffsetSize(const DWARFYAML::Unit &Unit) {
|
|
||||||
return Unit.Format == dwarf::DWARF64 ? 8 : 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned getRefSize(const DWARFYAML::Unit &Unit) {
|
|
||||||
if (Unit.Version == 2)
|
|
||||||
return Unit.AddrSize;
|
|
||||||
return getOffsetSize(Unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> Error DWARFYAML::VisitorImpl<T>::traverseDebugInfo() {
|
|
||||||
for (auto &Unit : DebugInfo.CompileUnits) {
|
|
||||||
onStartCompileUnit(Unit);
|
|
||||||
|
|
||||||
for (auto &Entry : Unit.Entries) {
|
|
||||||
onStartDIE(Unit, Entry);
|
|
||||||
uint32_t AbbrCode = Entry.AbbrCode;
|
|
||||||
if (AbbrCode == 0 || Entry.Values.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (AbbrCode > DebugInfo.AbbrevDecls.size())
|
|
||||||
return createStringError(
|
|
||||||
errc::invalid_argument,
|
|
||||||
"abbrev code must be less than or equal to the number of "
|
|
||||||
"entries in abbreviation table");
|
|
||||||
const DWARFYAML::Abbrev &Abbrev = DebugInfo.AbbrevDecls[AbbrCode - 1];
|
|
||||||
auto FormVal = Entry.Values.begin();
|
|
||||||
auto AbbrForm = Abbrev.Attributes.begin();
|
|
||||||
for (;
|
|
||||||
FormVal != Entry.Values.end() && AbbrForm != Abbrev.Attributes.end();
|
|
||||||
++FormVal, ++AbbrForm) {
|
|
||||||
onForm(*AbbrForm, *FormVal);
|
|
||||||
dwarf::Form Form = AbbrForm->Form;
|
|
||||||
bool Indirect;
|
|
||||||
do {
|
|
||||||
Indirect = false;
|
|
||||||
switch (Form) {
|
|
||||||
case dwarf::DW_FORM_addr:
|
|
||||||
onVariableSizeValue(FormVal->Value, Unit.AddrSize);
|
|
||||||
break;
|
|
||||||
case dwarf::DW_FORM_ref_addr:
|
|
||||||
onVariableSizeValue(FormVal->Value, getRefSize(Unit));
|
|
||||||
break;
|
|
||||||
case dwarf::DW_FORM_exprloc:
|
|
||||||
case dwarf::DW_FORM_block:
|
|
||||||
onValue((uint64_t)FormVal->BlockData.size(), true);
|
|
||||||
onValue(
|
|
||||||
MemoryBufferRef(StringRef((const char *)&FormVal->BlockData[0],
|
|
||||||
FormVal->BlockData.size()),
|
|
||||||
""));
|
|
||||||
break;
|
|
||||||
case dwarf::DW_FORM_block1: {
|
|
||||||
auto writeSize = FormVal->BlockData.size();
|
|
||||||
onValue((uint8_t)writeSize);
|
|
||||||
onValue(
|
|
||||||
MemoryBufferRef(StringRef((const char *)&FormVal->BlockData[0],
|
|
||||||
FormVal->BlockData.size()),
|
|
||||||
""));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case dwarf::DW_FORM_block2: {
|
|
||||||
auto writeSize = FormVal->BlockData.size();
|
|
||||||
onValue((uint16_t)writeSize);
|
|
||||||
onValue(
|
|
||||||
MemoryBufferRef(StringRef((const char *)&FormVal->BlockData[0],
|
|
||||||
FormVal->BlockData.size()),
|
|
||||||
""));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case dwarf::DW_FORM_block4: {
|
|
||||||
auto writeSize = FormVal->BlockData.size();
|
|
||||||
onValue((uint32_t)writeSize);
|
|
||||||
onValue(
|
|
||||||
MemoryBufferRef(StringRef((const char *)&FormVal->BlockData[0],
|
|
||||||
FormVal->BlockData.size()),
|
|
||||||
""));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case dwarf::DW_FORM_strx:
|
|
||||||
case dwarf::DW_FORM_addrx:
|
|
||||||
case dwarf::DW_FORM_rnglistx:
|
|
||||||
case dwarf::DW_FORM_loclistx:
|
|
||||||
case dwarf::DW_FORM_udata:
|
|
||||||
case dwarf::DW_FORM_ref_udata:
|
|
||||||
case dwarf::DW_FORM_GNU_addr_index:
|
|
||||||
case dwarf::DW_FORM_GNU_str_index:
|
|
||||||
onValue((uint64_t)FormVal->Value, /*LEB=*/true);
|
|
||||||
break;
|
|
||||||
case dwarf::DW_FORM_data1:
|
|
||||||
case dwarf::DW_FORM_ref1:
|
|
||||||
case dwarf::DW_FORM_flag:
|
|
||||||
case dwarf::DW_FORM_strx1:
|
|
||||||
case dwarf::DW_FORM_addrx1:
|
|
||||||
onValue((uint8_t)FormVal->Value);
|
|
||||||
break;
|
|
||||||
case dwarf::DW_FORM_data2:
|
|
||||||
case dwarf::DW_FORM_ref2:
|
|
||||||
case dwarf::DW_FORM_strx2:
|
|
||||||
case dwarf::DW_FORM_addrx2:
|
|
||||||
onValue((uint16_t)FormVal->Value);
|
|
||||||
break;
|
|
||||||
case dwarf::DW_FORM_data4:
|
|
||||||
case dwarf::DW_FORM_ref4:
|
|
||||||
case dwarf::DW_FORM_ref_sup4:
|
|
||||||
case dwarf::DW_FORM_strx4:
|
|
||||||
case dwarf::DW_FORM_addrx4:
|
|
||||||
onValue((uint32_t)FormVal->Value);
|
|
||||||
break;
|
|
||||||
case dwarf::DW_FORM_data8:
|
|
||||||
case dwarf::DW_FORM_ref8:
|
|
||||||
case dwarf::DW_FORM_ref_sup8:
|
|
||||||
case dwarf::DW_FORM_ref_sig8:
|
|
||||||
onValue((uint64_t)FormVal->Value);
|
|
||||||
break;
|
|
||||||
case dwarf::DW_FORM_sdata:
|
|
||||||
onValue((int64_t)FormVal->Value, true);
|
|
||||||
break;
|
|
||||||
case dwarf::DW_FORM_string:
|
|
||||||
onValue(FormVal->CStr);
|
|
||||||
break;
|
|
||||||
case dwarf::DW_FORM_indirect:
|
|
||||||
onValue((uint64_t)FormVal->Value, true);
|
|
||||||
Indirect = true;
|
|
||||||
Form = static_cast<dwarf::Form>((uint64_t)FormVal->Value);
|
|
||||||
++FormVal;
|
|
||||||
break;
|
|
||||||
case dwarf::DW_FORM_strp:
|
|
||||||
case dwarf::DW_FORM_sec_offset:
|
|
||||||
case dwarf::DW_FORM_GNU_ref_alt:
|
|
||||||
case dwarf::DW_FORM_GNU_strp_alt:
|
|
||||||
case dwarf::DW_FORM_line_strp:
|
|
||||||
case dwarf::DW_FORM_strp_sup:
|
|
||||||
onVariableSizeValue(FormVal->Value, getOffsetSize(Unit));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (Indirect);
|
|
||||||
}
|
|
||||||
onEndDIE(Unit, Entry);
|
|
||||||
}
|
|
||||||
onEndCompileUnit(Unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Error::success();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Explicitly instantiate the two template expansions.
|
|
||||||
template class DWARFYAML::VisitorImpl<DWARFYAML::Data>;
|
|
||||||
template class DWARFYAML::VisitorImpl<const DWARFYAML::Data>;
|
|
|
@ -1,97 +0,0 @@
|
||||||
//===--- DWARFVisitor.h -----------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef LLVM_OBJECTYAML_DWARFVISITOR_H
|
|
||||||
#define LLVM_OBJECTYAML_DWARFVISITOR_H
|
|
||||||
|
|
||||||
#include "llvm/ADT/StringRef.h"
|
|
||||||
#include "llvm/BinaryFormat/Dwarf.h"
|
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
class Error;
|
|
||||||
|
|
||||||
namespace DWARFYAML {
|
|
||||||
|
|
||||||
struct Data;
|
|
||||||
struct Unit;
|
|
||||||
struct Entry;
|
|
||||||
struct FormValue;
|
|
||||||
struct AttributeAbbrev;
|
|
||||||
|
|
||||||
/// A class to visits DWARFYAML Compile Units and DIEs in preorder.
|
|
||||||
///
|
|
||||||
/// Extensions of this class can either maintain const or non-const references
|
|
||||||
/// to the DWARFYAML::Data object.
|
|
||||||
template <typename T> class VisitorImpl {
|
|
||||||
protected:
|
|
||||||
T &DebugInfo;
|
|
||||||
|
|
||||||
/// Visitor Functions
|
|
||||||
/// @{
|
|
||||||
virtual void onStartCompileUnit(Unit &CU) {}
|
|
||||||
virtual void onEndCompileUnit(Unit &CU) {}
|
|
||||||
virtual void onStartDIE(Unit &CU, Entry &DIE) {}
|
|
||||||
virtual void onEndDIE(Unit &CU, Entry &DIE) {}
|
|
||||||
virtual void onForm(AttributeAbbrev &AttAbbrev, FormValue &Value) {}
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
/// Const Visitor Functions
|
|
||||||
/// @{
|
|
||||||
virtual void onStartCompileUnit(const Unit &CU) {}
|
|
||||||
virtual void onEndCompileUnit(const Unit &CU) {}
|
|
||||||
virtual void onStartDIE(const Unit &CU, const Entry &DIE) {}
|
|
||||||
virtual void onEndDIE(const Unit &CU, const Entry &DIE) {}
|
|
||||||
virtual void onForm(const AttributeAbbrev &AttAbbrev,
|
|
||||||
const FormValue &Value) {}
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
/// Value visitors
|
|
||||||
/// @{
|
|
||||||
virtual void onValue(const uint8_t U) {}
|
|
||||||
virtual void onValue(const uint16_t U) {}
|
|
||||||
virtual void onValue(const uint32_t U) {}
|
|
||||||
virtual void onValue(const uint64_t U, const bool LEB = false) {}
|
|
||||||
virtual void onValue(const int64_t S, const bool LEB = false) {}
|
|
||||||
virtual void onValue(const StringRef String) {}
|
|
||||||
virtual void onValue(const MemoryBufferRef MBR) {}
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
public:
|
|
||||||
VisitorImpl(T &DI) : DebugInfo(DI) {}
|
|
||||||
|
|
||||||
virtual ~VisitorImpl() {}
|
|
||||||
|
|
||||||
Error traverseDebugInfo();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void onVariableSizeValue(uint64_t U, unsigned Size);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Making the visior instantiations extern and explicit in the cpp file. This
|
|
||||||
// prevents them from being instantiated in every compile unit that uses the
|
|
||||||
// visitors.
|
|
||||||
extern template class VisitorImpl<DWARFYAML::Data>;
|
|
||||||
extern template class VisitorImpl<const DWARFYAML::Data>;
|
|
||||||
|
|
||||||
class Visitor : public VisitorImpl<Data> {
|
|
||||||
public:
|
|
||||||
Visitor(Data &DI) : VisitorImpl<Data>(DI) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ConstVisitor : public VisitorImpl<const Data> {
|
|
||||||
public:
|
|
||||||
ConstVisitor(const Data &DI) : VisitorImpl<const Data>(DI) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace DWARFYAML
|
|
||||||
} // namespace llvm
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -143,7 +143,7 @@ void MappingTraits<DWARFYAML::PubSection>::mapping(
|
||||||
|
|
||||||
void MappingTraits<DWARFYAML::Unit>::mapping(IO &IO, DWARFYAML::Unit &Unit) {
|
void MappingTraits<DWARFYAML::Unit>::mapping(IO &IO, DWARFYAML::Unit &Unit) {
|
||||||
IO.mapOptional("Format", Unit.Format, dwarf::DWARF32);
|
IO.mapOptional("Format", Unit.Format, dwarf::DWARF32);
|
||||||
IO.mapOptional("Length", Unit.Length, 0);
|
IO.mapOptional("Length", Unit.Length);
|
||||||
IO.mapRequired("Version", Unit.Version);
|
IO.mapRequired("Version", Unit.Version);
|
||||||
if (Unit.Version >= 5)
|
if (Unit.Version >= 5)
|
||||||
IO.mapRequired("UnitType", Unit.Type);
|
IO.mapRequired("UnitType", Unit.Type);
|
||||||
|
|
|
@ -735,3 +735,110 @@ DWARF:
|
||||||
AbbrOffset: 0x1234
|
AbbrOffset: 0x1234
|
||||||
AddrSize: 8
|
AddrSize: 8
|
||||||
Entries: []
|
Entries: []
|
||||||
|
|
||||||
|
## k) Test that yaml2obj is able to emit a correct length for compilation units.
|
||||||
|
|
||||||
|
# RUN: yaml2obj --docnum=13 %s -o %t13.o
|
||||||
|
# RUN: llvm-readelf --hex-dump=.debug_info %t13.o | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=INFER-LENGTH
|
||||||
|
|
||||||
|
# INFER-LENGTH: Hex dump of section '.debug_info':
|
||||||
|
# INFER-LENGTH-NEXT: 0x00000000 37000000 04000000 00000801 00000000 7...............
|
||||||
|
## ^------- unit_length (0x37)
|
||||||
|
## ^--- version (2-byte)
|
||||||
|
## ^-------- debug_abbrev_offset (4-byte)
|
||||||
|
## ^- address_size (1-byte)
|
||||||
|
## ^- abbrev code (ULEB128) 0x01
|
||||||
|
## ^------- Form: DW_FORM_strp (4-byte)
|
||||||
|
# INFER-LENGTH-NEXT: 0x00000010 0c001600 00000000 00001e00 00002011 .............. .
|
||||||
|
## ^--- Form: DW_FORM_data2 (2-byte)
|
||||||
|
## ^-------- Form: DW_FORM_strp (4-byte)
|
||||||
|
## ^-------- Form: DW_FORM_sec_offset (4-byte)
|
||||||
|
## ^-------- Form: DW_FORM_strp (4-byte)
|
||||||
|
## ^--- Form: DW_FORM_addr (8-byte)
|
||||||
|
# INFER-LENGTH-NEXT: 0x00000020 00000000 00003300 00000220 11000000 ......3.... ....
|
||||||
|
## -------------
|
||||||
|
## ^-------- Form: DW_FORM_data4 (4-byte)
|
||||||
|
## ^- abbrev code (ULEB128) 0x02
|
||||||
|
## ^---------- Form: DW_FORM_addr (8-byte)
|
||||||
|
# INFER-LENGTH-NEXT: 0x00000030 00000006 00000038 000000 .......8...
|
||||||
|
## ------
|
||||||
|
## ^-------- Form: DW_FORM_data4 (4-byte)
|
||||||
|
## ^-------- Form: DW_FORM_strp (4-byte)
|
||||||
|
|
||||||
|
## The handwritten DIEs should look like:
|
||||||
|
|
||||||
|
## 0x0000000b: DW_TAG_compile_unit [1] *
|
||||||
|
## DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000000] = "clang version 10.0.0 ")
|
||||||
|
## DW_AT_language [DW_FORM_data2] (DW_LANG_C99)
|
||||||
|
## DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000016] = "hello.c")
|
||||||
|
## DW_AT_stmt_list [DW_FORM_sec_offset] (0x00000000)
|
||||||
|
## DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x0000001e] = "/home/v/x/llvm/playground")
|
||||||
|
## DW_AT_low_pc [DW_FORM_addr] (0x0000000000001120)
|
||||||
|
## DW_AT_high_pc [DW_FORM_data4] (0x00000033)
|
||||||
|
##
|
||||||
|
## 0x0000002a: DW_TAG_subprogram [2]
|
||||||
|
## DW_AT_low_pc [DW_FORM_addr] (0x0000000000001120)
|
||||||
|
## DW_AT_high_pc [DW_FORM_data4] (0x00000006)
|
||||||
|
## DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000038] = "main")
|
||||||
|
|
||||||
|
--- !ELF
|
||||||
|
FileHeader:
|
||||||
|
Class: ELFCLASS64
|
||||||
|
Data: ELFDATA2LSB
|
||||||
|
Type: ET_EXEC
|
||||||
|
Machine: EM_X86_64
|
||||||
|
DWARF:
|
||||||
|
debug_str:
|
||||||
|
- "clang version 10.0.0 "
|
||||||
|
- "hello.c"
|
||||||
|
- "/home/v/x/llvm/playground"
|
||||||
|
- "main"
|
||||||
|
debug_abbrev:
|
||||||
|
- Code: 1
|
||||||
|
Tag: DW_TAG_compile_unit
|
||||||
|
Children: DW_CHILDREN_yes
|
||||||
|
Attributes:
|
||||||
|
- Attribute: DW_AT_producer
|
||||||
|
Form: DW_FORM_strp
|
||||||
|
- Attribute: DW_AT_language
|
||||||
|
Form: DW_FORM_data2
|
||||||
|
- Attribute: DW_AT_name
|
||||||
|
Form: DW_FORM_strp
|
||||||
|
- Attribute: DW_AT_stmt_list
|
||||||
|
Form: DW_FORM_sec_offset
|
||||||
|
- Attribute: DW_AT_comp_dir
|
||||||
|
Form: DW_FORM_strp
|
||||||
|
- Attribute: DW_AT_low_pc
|
||||||
|
Form: DW_FORM_addr
|
||||||
|
- Attribute: DW_AT_high_pc
|
||||||
|
Form: DW_FORM_data4
|
||||||
|
- Code: 2
|
||||||
|
Tag: DW_TAG_subprogram
|
||||||
|
Children: DW_CHILDREN_no
|
||||||
|
Attributes:
|
||||||
|
- Attribute: DW_AT_low_pc
|
||||||
|
Form: DW_FORM_addr
|
||||||
|
- Attribute: DW_AT_high_pc
|
||||||
|
Form: DW_FORM_data4
|
||||||
|
- Attribute: DW_AT_name
|
||||||
|
Form: DW_FORM_strp
|
||||||
|
debug_info:
|
||||||
|
- Version: 4
|
||||||
|
AbbrOffset: 0x00
|
||||||
|
AddrSize: 0x08
|
||||||
|
Entries:
|
||||||
|
- AbbrCode: 1
|
||||||
|
Values:
|
||||||
|
- Value: 0x00 ## DW_AT_producer [DW_FORM_strp]
|
||||||
|
- Value: 0x0c ## DW_LANG_C99, DW_AT_language [DW_FORM_data2]
|
||||||
|
- Value: 0x16 ## DW_AT_name [DW_FORM_strp]
|
||||||
|
- Value: 0x00 ## DW_AT_stmt_list [DW_FORM_sec_offset]
|
||||||
|
- Value: 0x1e ## DW_AT_comp_dir [DW_FORM_strp]
|
||||||
|
- Value: 0x1120 ## DW_AT_low_pc [DW_FORM_addr]
|
||||||
|
- Value: 0x33 ## DW_AT_high_pc [DW_FORM_data4]
|
||||||
|
- AbbrCode: 2
|
||||||
|
Values:
|
||||||
|
- Value: 0x1120 ## DW_AT_low_pc [DW_FORM_addr]
|
||||||
|
- Value: 0x06 ## DW_AT_high_pc [DW_FORM_data4]
|
||||||
|
- Value: 0x38 ## DW_AT_name [DW_FORM_strp]
|
||||||
|
|
|
@ -1377,7 +1377,7 @@ TEST(DWARFDebugInfo, TestEmptyChildren) {
|
||||||
" - AbbrCode: 0x00000000\n"
|
" - AbbrCode: 0x00000000\n"
|
||||||
" Values:\n";
|
" Values:\n";
|
||||||
|
|
||||||
auto ErrOrSections = DWARFYAML::emitDebugSections(StringRef(yamldata), true);
|
auto ErrOrSections = DWARFYAML::emitDebugSections(StringRef(yamldata));
|
||||||
ASSERT_TRUE((bool)ErrOrSections);
|
ASSERT_TRUE((bool)ErrOrSections);
|
||||||
std::unique_ptr<DWARFContext> DwarfContext =
|
std::unique_ptr<DWARFContext> DwarfContext =
|
||||||
DWARFContext::create(*ErrOrSections, 8);
|
DWARFContext::create(*ErrOrSections, 8);
|
||||||
|
|
|
@ -48,7 +48,7 @@ TEST(DWARFDie, getLocations) {
|
||||||
- Value: 25
|
- Value: 25
|
||||||
)";
|
)";
|
||||||
Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections =
|
Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections =
|
||||||
DWARFYAML::emitDebugSections(StringRef(yamldata), /*ApplyFixups=*/true,
|
DWARFYAML::emitDebugSections(StringRef(yamldata),
|
||||||
/*IsLittleEndian=*/true);
|
/*IsLittleEndian=*/true);
|
||||||
ASSERT_THAT_EXPECTED(Sections, Succeeded());
|
ASSERT_THAT_EXPECTED(Sections, Succeeded());
|
||||||
std::vector<uint8_t> Loclists{
|
std::vector<uint8_t> Loclists{
|
||||||
|
|
Loading…
Reference in New Issue