Index: llvm/trunk/lib/ObjectYAML/CMakeLists.txt =================================================================== --- llvm/trunk/lib/ObjectYAML/CMakeLists.txt +++ llvm/trunk/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: llvm/trunk/lib/ObjectYAML/DWARFEmitter.cpp =================================================================== --- llvm/trunk/lib/ObjectYAML/DWARFEmitter.cpp +++ llvm/trunk/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; @@ -117,130 +119,65 @@ } } -void DWARFYAML::EmitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) { +/// \brief An extension of the DWARFYAML::ConstVisitor which writes compile +/// units and DIEs to a stream. +class DumpVisitor : public DWARFYAML::ConstVisitor { + raw_ostream &OS; + +protected: + virtual void onStartCompileUnit(const DWARFYAML::Unit &CU) { + writeInitialLength(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); + } - for (auto CU : DI.CompileUnits) { - writeInitialLength(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); - } - } + 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: llvm/trunk/lib/ObjectYAML/DWARFVisitor.h =================================================================== --- llvm/trunk/lib/ObjectYAML/DWARFVisitor.h +++ llvm/trunk/lib/ObjectYAML/DWARFVisitor.h @@ -0,0 +1,97 @@ +//===--- 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; + +/// \brief 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 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, 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; +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: llvm/trunk/lib/ObjectYAML/DWARFVisitor.cpp =================================================================== --- llvm/trunk/lib/ObjectYAML/DWARFVisitor.cpp +++ llvm/trunk/lib/ObjectYAML/DWARFVisitor.cpp @@ -0,0 +1,167 @@ +//===--- 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, 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."); + } +} + +unsigned getRefSize(const DWARFYAML::Unit &Unit) { + if (Unit.Version == 2) + return Unit.AddrSize; + return Unit.Length.isDWARF64() ? 8 : 4; +} + +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; + 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_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: + onVariableSizeValue(FormVal->Value, getRefSize(Unit)); + 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;