Index: lib/ObjectYAML/CMakeLists.txt =================================================================== --- lib/ObjectYAML/CMakeLists.txt +++ lib/ObjectYAML/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_library(LLVMObjectYAML COFFYAML.cpp DWARFEmitter.cpp + DWARFVisitor.cpp DWARFYAML.cpp ELFYAML.cpp MachOYAML.cpp Index: lib/ObjectYAML/DWARFEmitter.cpp =================================================================== --- lib/ObjectYAML/DWARFEmitter.cpp +++ lib/ObjectYAML/DWARFEmitter.cpp @@ -19,6 +19,8 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SwapByteOrder.h" +#include "DWARFVisitor.h" + #include using namespace llvm; @@ -110,130 +112,63 @@ } } -void DWARFYAML::EmitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) { +class DumpVisitor : public DWARFYAML::ConstVisitor { + raw_ostream &OS; - for (auto CU : DI.CompileUnits) { - writeInteger((uint32_t)CU.Length, OS, DI.IsLittleEndian); - writeInteger((uint16_t)CU.Version, OS, DI.IsLittleEndian); - writeInteger((uint32_t)CU.AbbrOffset, OS, DI.IsLittleEndian); - writeInteger((uint8_t)CU.AddrSize, OS, DI.IsLittleEndian); - - auto FirstAbbrevCode = CU.Entries[0].AbbrCode; - - for (auto Entry : CU.Entries) { - encodeULEB128(Entry.AbbrCode, OS); - if (Entry.AbbrCode == 0u) - continue; - bool Indirect = false; - assert(Entry.AbbrCode - FirstAbbrevCode < DI.AbbrevDecls.size() && - "Out of range AbbCode"); - auto &Abbrev = DI.AbbrevDecls[Entry.AbbrCode - FirstAbbrevCode]; - - 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; - do { - Indirect = false; - switch (Form) { - case dwarf::DW_FORM_addr: - writeVariableSizedInteger(FormVal->Value, CU.AddrSize, OS, - DI.IsLittleEndian); - break; - case dwarf::DW_FORM_ref_addr: { - // TODO: Handle DWARF32/DWARF64 after Line Table data is done - auto writeSize = CU.Version == 2 ? CU.AddrSize : 4; - writeVariableSizedInteger(FormVal->Value, writeSize, OS, - DI.IsLittleEndian); - break; - } - case dwarf::DW_FORM_exprloc: - case dwarf::DW_FORM_block: - encodeULEB128(FormVal->BlockData.size(), OS); - OS.write(reinterpret_cast(&FormVal->BlockData[0]), - FormVal->BlockData.size()); - break; - case dwarf::DW_FORM_block1: { - auto writeSize = FormVal->BlockData.size(); - writeInteger((uint8_t)writeSize, OS, DI.IsLittleEndian); - OS.write(reinterpret_cast(&FormVal->BlockData[0]), - FormVal->BlockData.size()); - break; - } - case dwarf::DW_FORM_block2: { - auto writeSize = FormVal->BlockData.size(); - writeInteger((uint16_t)writeSize, OS, DI.IsLittleEndian); - OS.write(reinterpret_cast(&FormVal->BlockData[0]), - FormVal->BlockData.size()); - break; - } - case dwarf::DW_FORM_block4: { - auto writeSize = FormVal->BlockData.size(); - writeInteger((uint32_t)writeSize, OS, DI.IsLittleEndian); - OS.write(reinterpret_cast(&FormVal->BlockData[0]), - FormVal->BlockData.size()); - break; - } - case dwarf::DW_FORM_data1: - case dwarf::DW_FORM_ref1: - case dwarf::DW_FORM_flag: - writeInteger((uint8_t)FormVal->Value, OS, DI.IsLittleEndian); - break; - case dwarf::DW_FORM_data2: - case dwarf::DW_FORM_ref2: - writeInteger((uint16_t)FormVal->Value, OS, DI.IsLittleEndian); - break; - case dwarf::DW_FORM_data4: - case dwarf::DW_FORM_ref4: - writeInteger((uint32_t)FormVal->Value, OS, DI.IsLittleEndian); - break; - case dwarf::DW_FORM_data8: - case dwarf::DW_FORM_ref8: - writeInteger((uint64_t)FormVal->Value, OS, DI.IsLittleEndian); - break; - case dwarf::DW_FORM_sdata: - encodeSLEB128(FormVal->Value, OS); - break; - case dwarf::DW_FORM_udata: - case dwarf::DW_FORM_ref_udata: - encodeULEB128(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((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: - case dwarf::DW_FORM_ref_sup: - // TODO: Handle DWARF32/64 - writeInteger((uint32_t)FormVal->Value, OS, DI.IsLittleEndian); - break; - case dwarf::DW_FORM_ref_sig8: - writeInteger((uint64_t)FormVal->Value, OS, DI.IsLittleEndian); - break; - case dwarf::DW_FORM_GNU_addr_index: - case dwarf::DW_FORM_GNU_str_index: - encodeULEB128(FormVal->Value, OS); - break; - default: - break; - } - } while (Indirect); - } - } +protected: + virtual void OnStartCompileUnit(const DWARFYAML::Unit &CU) { + writeInteger((uint32_t)CU.Length, OS, DebugInfo.IsLittleEndian); + writeInteger((uint16_t)CU.Version, OS, DebugInfo.IsLittleEndian); + writeInteger((uint32_t)CU.AbbrOffset, OS, DebugInfo.IsLittleEndian); + writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian); + } + + virtual void OnStartDIE(const DWARFYAML::Unit &CU, + const DWARFYAML::Entry &DIE) { + encodeULEB128(DIE.AbbrCode, OS); } + + virtual void OnValue(const uint8_t U) { + writeInteger(U, OS, DebugInfo.IsLittleEndian); + } + + virtual void OnValue(const uint16_t U) { + writeInteger(U, OS, DebugInfo.IsLittleEndian); + } + virtual void OnValue(const uint32_t U) { + writeInteger(U, OS, DebugInfo.IsLittleEndian); + } + virtual void OnValue(const uint64_t U, const bool LEB = false) { + if (LEB) + encodeULEB128(U, OS); + else + writeInteger(U, OS, DebugInfo.IsLittleEndian); + } + + virtual void OnValue(const int64_t S, const bool LEB = false) { + if (LEB) + encodeSLEB128(S, OS); + else + writeInteger(S, OS, DebugInfo.IsLittleEndian); + } + + virtual void OnValue(const StringRef String) { + OS.write(String.data(), String.size()); + OS.write('\0'); + } + + virtual void OnValue(const MemoryBufferRef MBR) { + OS.write(MBR.getBufferStart(), MBR.getBufferSize()); + } + +public: + DumpVisitor(const DWARFYAML::Data &DI, raw_ostream &Out) + : DWARFYAML::ConstVisitor(DI), OS(Out) {} +}; + +void DWARFYAML::EmitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) { + DumpVisitor Visitor(DI, OS); + Visitor.TraverseDebugInfo(); } static void EmitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) { Index: lib/ObjectYAML/DWARFVisitor.h =================================================================== --- /dev/null +++ lib/ObjectYAML/DWARFVisitor.h @@ -0,0 +1,87 @@ +//===--- DWARFVisitor.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTYAML_DWARFVISITOR_H +#define LLVM_OBJECTYAML_DWARFVISITOR_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace llvm { + +namespace DWARFYAML { + +struct Data; +struct Unit; +struct Entry; +struct FormValue; +struct AttributeAbbrev; + +template 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() {} + + void TraverseDebugInfo(); + +private: + void OnVariableSizeValue(uint64_t U, size_t 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; +extern template class VisitorImpl; + +class Visitor : public VisitorImpl { +public: + Visitor(Data &DI) : VisitorImpl(DI) {} +}; + +class ConstVisitor : public VisitorImpl { +public: + ConstVisitor(const Data &DI) : VisitorImpl(DI) {} +}; + +} // namespace DWARFYAML +} // namespace llvm + +#endif Index: lib/ObjectYAML/DWARFVisitor.cpp =================================================================== --- /dev/null +++ lib/ObjectYAML/DWARFVisitor.cpp @@ -0,0 +1,165 @@ +//===--- DWARFVisitor.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#include "DWARFVisitor.h" +#include "llvm/ObjectYAML/DWARFYAML.h" + +using namespace llvm; + +template +void DWARFYAML::VisitorImpl::OnVariableSizeValue(uint64_t U, size_t Size) { + if (8 == Size) + OnValue((uint64_t)U); + else if (4 == Size) + OnValue((uint32_t)U); + else if (2 == Size) + OnValue((uint16_t)U); + else if (1 == Size) + OnValue((uint8_t)U); + else + assert(false && "Invalid integer write size."); +} + +template void DWARFYAML::VisitorImpl::TraverseDebugInfo() { + for (auto &Unit : DebugInfo.CompileUnits) { + OnStartCompileUnit(Unit); + auto FirstAbbrevCode = Unit.Entries[0].AbbrCode; + + for (auto &Entry : Unit.Entries) { + OnStartDIE(Unit, Entry); + if (Entry.AbbrCode == 0u) + continue; + auto &Abbrev = DebugInfo.AbbrevDecls[Entry.AbbrCode - FirstAbbrevCode]; + 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 = false; + do { + Indirect = false; + switch (Form) { + case dwarf::DW_FORM_addr: + OnVariableSizeValue(FormVal->Value, Unit.AddrSize); + break; + case dwarf::DW_FORM_ref_addr: { + auto writeSize = Unit.Version == 2 ? Unit.AddrSize : 4; + if (!DebugInfo.DebugLines.empty()) + writeSize = + DebugInfo.DebugLines[0].TotalLength == UINT32_MAX ? 8 : 4; + OnVariableSizeValue(FormVal->Value, writeSize); + 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_data1: + case dwarf::DW_FORM_ref1: + case dwarf::DW_FORM_flag: + OnValue((uint8_t)FormVal->Value); + break; + case dwarf::DW_FORM_data2: + case dwarf::DW_FORM_ref2: + OnValue((uint16_t)FormVal->Value); + break; + case dwarf::DW_FORM_data4: + case dwarf::DW_FORM_ref4: + OnValue((uint32_t)FormVal->Value); + break; + case dwarf::DW_FORM_data8: + case dwarf::DW_FORM_ref8: + OnValue((uint64_t)FormVal->Value); + break; + case dwarf::DW_FORM_sdata: + OnValue((int64_t)FormVal->Value, true); + break; + case dwarf::DW_FORM_udata: + case dwarf::DW_FORM_ref_udata: + OnValue((uint64_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((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: + case dwarf::DW_FORM_ref_sup: { + auto writeSize = 4; + if (!DebugInfo.DebugLines.empty()) + writeSize = + DebugInfo.DebugLines[0].TotalLength == 0xffffffffU ? 8 : 4; + OnVariableSizeValue(FormVal->Value, writeSize); + break; + } + case dwarf::DW_FORM_ref_sig8: + OnValue((uint64_t)FormVal->Value); + break; + case dwarf::DW_FORM_GNU_addr_index: + case dwarf::DW_FORM_GNU_str_index: + OnValue((uint64_t)FormVal->Value, true); + break; + default: + break; + } + } while (Indirect); + } + OnEndDIE(Unit, Entry); + } + OnEndCompileUnit(Unit); + } +} + +// Explicitly instantiate the two template expansions. +template class DWARFYAML::VisitorImpl; +template class DWARFYAML::VisitorImpl;