diff options
Diffstat (limited to 'llvm/lib/ObjectYAML/DWARFEmitter.cpp')
-rw-r--r-- | llvm/lib/ObjectYAML/DWARFEmitter.cpp | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/llvm/lib/ObjectYAML/DWARFEmitter.cpp b/llvm/lib/ObjectYAML/DWARFEmitter.cpp new file mode 100644 index 00000000000..7282384e8ff --- /dev/null +++ b/llvm/lib/ObjectYAML/DWARFEmitter.cpp @@ -0,0 +1,332 @@ +//===- DWARFEmitter - Convert YAML to DWARF binary data -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief The DWARF component of yaml2obj. Provided as library code for tests. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/ObjectYAML/DWARFEmitter.h" +#include "llvm/ObjectYAML/DWARFYAML.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SwapByteOrder.h" + +#include <algorithm> + +using namespace llvm; + +template <typename T> +void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian) { + if (IsLittleEndian != sys::IsLittleEndianHost) + sys::swapByteOrder(Integer); + OS.write(reinterpret_cast<char *>(&Integer), sizeof(T)); +} + +void writeVariableSizedInteger(uint64_t Integer, size_t Size, raw_ostream &OS, + bool IsLittleEndian) { + if (8 == Size) + writeInteger((uint64_t)Integer, OS, IsLittleEndian); + else if (4 == Size) + writeInteger((uint32_t)Integer, OS, IsLittleEndian); + else if (2 == Size) + writeInteger((uint16_t)Integer, OS, IsLittleEndian); + else if (1 == Size) + writeInteger((uint8_t)Integer, OS, IsLittleEndian); + else + assert(false && "Invalid integer write size."); +} + +void ZeroFillBytes(raw_ostream &OS, size_t Size) { + std::vector<uint8_t> FillData; + FillData.insert(FillData.begin(), Size, 0); + OS.write(reinterpret_cast<char *>(FillData.data()), Size); +} + +void DWARFYAML::EmitDebugStr(raw_ostream &OS, const DWARFYAML::Data &DI) { + for (auto Str : DI.DebugStrings) { + OS.write(Str.data(), Str.size()); + OS.write('\0'); + } +} + +void DWARFYAML::EmitDebugAbbrev(raw_ostream &OS, const DWARFYAML::Data &DI) { + for (auto AbbrevDecl : DI.AbbrevDecls) { + encodeULEB128(AbbrevDecl.Code, OS); + encodeULEB128(AbbrevDecl.Tag, OS); + OS.write(AbbrevDecl.Children); + for (auto Attr : AbbrevDecl.Attributes) { + encodeULEB128(Attr.Attribute, OS); + encodeULEB128(Attr.Form, OS); + } + encodeULEB128(0, OS); + encodeULEB128(0, OS); + } +} + +void DWARFYAML::EmitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) { + for (auto Range : DI.ARanges) { + auto HeaderStart = OS.tell(); + writeInteger((uint32_t)Range.Length, OS, DI.IsLittleEndian); + writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian); + writeInteger((uint32_t)Range.CuOffset, OS, DI.IsLittleEndian); + writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian); + writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian); + + auto HeaderSize = OS.tell() - HeaderStart; + auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2); + ZeroFillBytes(OS, FirstDescriptor - HeaderSize); + + for (auto Descriptor : Range.Descriptors) { + writeVariableSizedInteger(Descriptor.Address, Range.AddrSize, OS, + DI.IsLittleEndian); + writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS, + DI.IsLittleEndian); + } + ZeroFillBytes(OS, Range.AddrSize * 2); + } +} + +void DWARFYAML::EmitPubSection(raw_ostream &OS, + const DWARFYAML::PubSection &Sect, + bool IsLittleEndian) { + writeInteger((uint32_t)Sect.Length, OS, IsLittleEndian); + writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian); + writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian); + writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian); + for (auto Entry : Sect.Entries) { + writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian); + if (Sect.IsGNUStyle) + writeInteger((uint32_t)Entry.Descriptor, OS, IsLittleEndian); + OS.write(Entry.Name.data(), Entry.Name.size()); + OS.write('\0'); + } +} + +void DWARFYAML::EmitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) { + + 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<char *>(&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<char *>(&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<char *>(&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<char *>(&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<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: + 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); + } + } + } +} + +void EmitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) { + OS.write(File.Name.data(), File.Name.size()); + OS.write('\0'); + encodeULEB128(File.DirIdx, OS); + encodeULEB128(File.ModTime, OS); + encodeULEB128(File.Length, OS); +} + +void DWARFYAML::EmitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) { + for (const auto LineTable : DI.DebugLines) { + writeInteger((uint32_t)LineTable.TotalLength, OS, DI.IsLittleEndian); + uint64_t SizeOfPrologueLength = 4; + if (LineTable.TotalLength == UINT32_MAX) { + writeInteger((uint64_t)LineTable.TotalLength64, OS, DI.IsLittleEndian); + SizeOfPrologueLength = 8; + } + writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian); + writeVariableSizedInteger(LineTable.PrologueLength, SizeOfPrologueLength, + OS, DI.IsLittleEndian); + writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian); + if (LineTable.Version >= 4) + writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian); + writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian); + writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian); + writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian); + writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian); + + for (auto OpcodeLength : LineTable.StandardOpcodeLengths) + writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian); + + for (auto IncludeDir : LineTable.IncludeDirs) { + OS.write(IncludeDir.data(), IncludeDir.size()); + OS.write('\0'); + } + OS.write('\0'); + + for (auto File : LineTable.Files) + EmitFileEntry(OS, File); + OS.write('\0'); + + for (auto Op : LineTable.Opcodes) { + writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian); + if (Op.Opcode == 0) { + encodeULEB128(Op.ExtLen, OS); + writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian); + switch (Op.SubOpcode) { + case dwarf::DW_LNE_set_address: + case dwarf::DW_LNE_set_discriminator: + writeVariableSizedInteger(Op.Data, DI.CompileUnits[0].AddrSize, OS, + DI.IsLittleEndian); + break; + case dwarf::DW_LNE_define_file: + EmitFileEntry(OS, Op.FileEntry); + break; + case dwarf::DW_LNE_end_sequence: + break; + default: + for (auto OpByte : Op.UnknownOpcodeData) + writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian); + } + } else if (Op.Opcode < LineTable.OpcodeBase) { + switch (Op.Opcode) { + case dwarf::DW_LNS_copy: + case dwarf::DW_LNS_negate_stmt: + case dwarf::DW_LNS_set_basic_block: + case dwarf::DW_LNS_const_add_pc: + case dwarf::DW_LNS_set_prologue_end: + case dwarf::DW_LNS_set_epilogue_begin: + break; + + case dwarf::DW_LNS_advance_pc: + case dwarf::DW_LNS_set_file: + case dwarf::DW_LNS_set_column: + case dwarf::DW_LNS_set_isa: + encodeULEB128(Op.Data, OS); + break; + + case dwarf::DW_LNS_advance_line: + encodeSLEB128(Op.SData, OS); + break; + + case dwarf::DW_LNS_fixed_advance_pc: + writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian); + break; + + default: + for (auto OpData : Op.StandardOpcodeData) { + encodeULEB128(OpData, OS); + } + } + } + } + } +} |