Mercurial > hg > CbC > CbC_llvm
diff tools/obj2yaml/dwarf2yaml.cpp @ 121:803732b1fca8
LLVM 5.0
author | kono |
---|---|
date | Fri, 27 Oct 2017 17:07:41 +0900 |
parents | |
children | c2174574ed3a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/obj2yaml/dwarf2yaml.cpp Fri Oct 27 17:07:41 2017 +0900 @@ -0,0 +1,357 @@ +//===------ dwarf2yaml.cpp - obj2yaml conversion tool -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/ObjectYAML/DWARFYAML.h" + +#include <algorithm> + +using namespace llvm; + +void dumpInitialLength(DataExtractor &Data, uint32_t &Offset, + DWARFYAML::InitialLength &InitialLength) { + InitialLength.TotalLength = Data.getU32(&Offset); + if (InitialLength.isDWARF64()) + InitialLength.TotalLength64 = Data.getU64(&Offset); +} + +void dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) { + auto AbbrevSetPtr = DCtx.getDebugAbbrev(); + if (AbbrevSetPtr) { + for (auto AbbrvDeclSet : *AbbrevSetPtr) { + for (auto AbbrvDecl : AbbrvDeclSet.second) { + DWARFYAML::Abbrev Abbrv; + Abbrv.Code = AbbrvDecl.getCode(); + Abbrv.Tag = AbbrvDecl.getTag(); + Abbrv.Children = AbbrvDecl.hasChildren() ? dwarf::DW_CHILDREN_yes + : dwarf::DW_CHILDREN_no; + for (auto Attribute : AbbrvDecl.attributes()) { + DWARFYAML::AttributeAbbrev AttAbrv; + AttAbrv.Attribute = Attribute.Attr; + AttAbrv.Form = Attribute.Form; + if (AttAbrv.Form == dwarf::DW_FORM_implicit_const) + AttAbrv.Value = Attribute.getImplicitConstValue(); + Abbrv.Attributes.push_back(AttAbrv); + } + Y.AbbrevDecls.push_back(Abbrv); + } + } + } +} + +void dumpDebugStrings(DWARFContext &DCtx, DWARFYAML::Data &Y) { + StringRef RemainingTable = DCtx.getDWARFObj().getStringSection(); + while (RemainingTable.size() > 0) { + auto SymbolPair = RemainingTable.split('\0'); + RemainingTable = SymbolPair.second; + Y.DebugStrings.push_back(SymbolPair.first); + } +} + +void dumpDebugARanges(DWARFContext &DCtx, DWARFYAML::Data &Y) { + DataExtractor ArangesData(DCtx.getDWARFObj().getARangeSection(), + DCtx.isLittleEndian(), 0); + uint32_t Offset = 0; + DWARFDebugArangeSet Set; + + while (Set.extract(ArangesData, &Offset)) { + DWARFYAML::ARange Range; + Range.Length.setLength(Set.getHeader().Length); + Range.Version = Set.getHeader().Version; + Range.CuOffset = Set.getHeader().CuOffset; + Range.AddrSize = Set.getHeader().AddrSize; + Range.SegSize = Set.getHeader().SegSize; + for (auto Descriptor : Set.descriptors()) { + DWARFYAML::ARangeDescriptor Desc; + Desc.Address = Descriptor.Address; + Desc.Length = Descriptor.Length; + Range.Descriptors.push_back(Desc); + } + Y.ARanges.push_back(Range); + } +} + +void dumpPubSection(DWARFContext &DCtx, DWARFYAML::PubSection &Y, + StringRef Section) { + DataExtractor PubSectionData(Section, DCtx.isLittleEndian(), 0); + uint32_t Offset = 0; + dumpInitialLength(PubSectionData, Offset, Y.Length); + Y.Version = PubSectionData.getU16(&Offset); + Y.UnitOffset = PubSectionData.getU32(&Offset); + Y.UnitSize = PubSectionData.getU32(&Offset); + while (Offset < Y.Length.getLength()) { + DWARFYAML::PubEntry NewEntry; + NewEntry.DieOffset = PubSectionData.getU32(&Offset); + if (Y.IsGNUStyle) + NewEntry.Descriptor = PubSectionData.getU8(&Offset); + NewEntry.Name = PubSectionData.getCStr(&Offset); + Y.Entries.push_back(NewEntry); + } +} + +void dumpDebugPubSections(DWARFContext &DCtx, DWARFYAML::Data &Y) { + const DWARFObject &D = DCtx.getDWARFObj(); + Y.PubNames.IsGNUStyle = false; + dumpPubSection(DCtx, Y.PubNames, D.getPubNamesSection()); + + Y.PubTypes.IsGNUStyle = false; + dumpPubSection(DCtx, Y.PubTypes, D.getPubTypesSection()); + + Y.GNUPubNames.IsGNUStyle = true; + dumpPubSection(DCtx, Y.GNUPubNames, D.getGnuPubNamesSection()); + + Y.GNUPubTypes.IsGNUStyle = true; + dumpPubSection(DCtx, Y.GNUPubTypes, D.getGnuPubTypesSection()); +} + +void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) { + for (const auto &CU : DCtx.compile_units()) { + DWARFYAML::Unit NewUnit; + NewUnit.Length.setLength(CU->getLength()); + NewUnit.Version = CU->getVersion(); + if(NewUnit.Version >= 5) + NewUnit.Type = (dwarf::UnitType)CU->getUnitType(); + NewUnit.AbbrOffset = CU->getAbbreviations()->getOffset(); + NewUnit.AddrSize = CU->getAddressByteSize(); + for (auto DIE : CU->dies()) { + DWARFYAML::Entry NewEntry; + DataExtractor EntryData = CU->getDebugInfoExtractor(); + uint32_t offset = DIE.getOffset(); + + assert(EntryData.isValidOffset(offset) && "Invalid DIE Offset"); + if (!EntryData.isValidOffset(offset)) + continue; + + NewEntry.AbbrCode = EntryData.getULEB128(&offset); + + auto AbbrevDecl = DIE.getAbbreviationDeclarationPtr(); + if (AbbrevDecl) { + for (const auto &AttrSpec : AbbrevDecl->attributes()) { + DWARFYAML::FormValue NewValue; + NewValue.Value = 0xDEADBEEFDEADBEEF; + DWARFDie DIEWrapper(CU.get(), &DIE); + auto FormValue = DIEWrapper.find(AttrSpec.Attr); + if (!FormValue) + return; + auto Form = FormValue.getValue().getForm(); + bool indirect = false; + do { + indirect = false; + switch (Form) { + case dwarf::DW_FORM_addr: + case dwarf::DW_FORM_GNU_addr_index: + if (auto Val = FormValue.getValue().getAsAddress()) + NewValue.Value = Val.getValue(); + break; + case dwarf::DW_FORM_ref_addr: + case dwarf::DW_FORM_ref1: + case dwarf::DW_FORM_ref2: + case dwarf::DW_FORM_ref4: + case dwarf::DW_FORM_ref8: + case dwarf::DW_FORM_ref_udata: + case dwarf::DW_FORM_ref_sig8: + if (auto Val = FormValue.getValue().getAsReferenceUVal()) + NewValue.Value = Val.getValue(); + break; + case dwarf::DW_FORM_exprloc: + case dwarf::DW_FORM_block: + case dwarf::DW_FORM_block1: + case dwarf::DW_FORM_block2: + case dwarf::DW_FORM_block4: + if (auto Val = FormValue.getValue().getAsBlock()) { + auto BlockData = Val.getValue(); + std::copy(BlockData.begin(), BlockData.end(), + std::back_inserter(NewValue.BlockData)); + } + NewValue.Value = NewValue.BlockData.size(); + break; + case dwarf::DW_FORM_data1: + case dwarf::DW_FORM_flag: + case dwarf::DW_FORM_data2: + case dwarf::DW_FORM_data4: + case dwarf::DW_FORM_data8: + case dwarf::DW_FORM_sdata: + case dwarf::DW_FORM_udata: + case dwarf::DW_FORM_ref_sup4: + case dwarf::DW_FORM_ref_sup8: + if (auto Val = FormValue.getValue().getAsUnsignedConstant()) + NewValue.Value = Val.getValue(); + break; + case dwarf::DW_FORM_string: + if (auto Val = FormValue.getValue().getAsCString()) + NewValue.CStr = Val.getValue(); + break; + case dwarf::DW_FORM_indirect: + indirect = true; + if (auto Val = FormValue.getValue().getAsUnsignedConstant()) { + NewValue.Value = Val.getValue(); + NewEntry.Values.push_back(NewValue); + Form = static_cast<dwarf::Form>(Val.getValue()); + } + 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_GNU_str_index: + case dwarf::DW_FORM_strx: + if (auto Val = FormValue.getValue().getAsCStringOffset()) + NewValue.Value = Val.getValue(); + break; + case dwarf::DW_FORM_flag_present: + NewValue.Value = 1; + break; + default: + break; + } + } while (indirect); + NewEntry.Values.push_back(NewValue); + } + } + + NewUnit.Entries.push_back(NewEntry); + } + Y.CompileUnits.push_back(NewUnit); + } +} + +bool dumpFileEntry(DataExtractor &Data, uint32_t &Offset, + DWARFYAML::File &File) { + File.Name = Data.getCStr(&Offset); + if (File.Name.empty()) + return false; + File.DirIdx = Data.getULEB128(&Offset); + File.ModTime = Data.getULEB128(&Offset); + File.Length = Data.getULEB128(&Offset); + return true; +} + +void dumpDebugLines(DWARFContext &DCtx, DWARFYAML::Data &Y) { + for (const auto &CU : DCtx.compile_units()) { + auto CUDIE = CU->getUnitDIE(); + if (!CUDIE) + continue; + if (auto StmtOffset = + dwarf::toSectionOffset(CUDIE.find(dwarf::DW_AT_stmt_list))) { + DWARFYAML::LineTable DebugLines; + DataExtractor LineData(DCtx.getDWARFObj().getLineSection().Data, + DCtx.isLittleEndian(), CU->getAddressByteSize()); + uint32_t Offset = *StmtOffset; + dumpInitialLength(LineData, Offset, DebugLines.Length); + uint64_t LineTableLength = DebugLines.Length.getLength(); + uint64_t SizeOfPrologueLength = DebugLines.Length.isDWARF64() ? 8 : 4; + DebugLines.Version = LineData.getU16(&Offset); + DebugLines.PrologueLength = + LineData.getUnsigned(&Offset, SizeOfPrologueLength); + const uint64_t EndPrologue = DebugLines.PrologueLength + Offset; + + DebugLines.MinInstLength = LineData.getU8(&Offset); + if (DebugLines.Version >= 4) + DebugLines.MaxOpsPerInst = LineData.getU8(&Offset); + DebugLines.DefaultIsStmt = LineData.getU8(&Offset); + DebugLines.LineBase = LineData.getU8(&Offset); + DebugLines.LineRange = LineData.getU8(&Offset); + DebugLines.OpcodeBase = LineData.getU8(&Offset); + + DebugLines.StandardOpcodeLengths.reserve(DebugLines.OpcodeBase - 1); + for (uint8_t i = 1; i < DebugLines.OpcodeBase; ++i) + DebugLines.StandardOpcodeLengths.push_back(LineData.getU8(&Offset)); + + while (Offset < EndPrologue) { + StringRef Dir = LineData.getCStr(&Offset); + if (!Dir.empty()) + DebugLines.IncludeDirs.push_back(Dir); + else + break; + } + + while (Offset < EndPrologue) { + DWARFYAML::File TmpFile; + if (dumpFileEntry(LineData, Offset, TmpFile)) + DebugLines.Files.push_back(TmpFile); + else + break; + } + + const uint64_t LineEnd = + LineTableLength + *StmtOffset + SizeOfPrologueLength; + while (Offset < LineEnd) { + DWARFYAML::LineTableOpcode NewOp; + NewOp.Opcode = (dwarf::LineNumberOps)LineData.getU8(&Offset); + if (NewOp.Opcode == 0) { + auto StartExt = Offset; + NewOp.ExtLen = LineData.getULEB128(&Offset); + NewOp.SubOpcode = + (dwarf::LineNumberExtendedOps)LineData.getU8(&Offset); + switch (NewOp.SubOpcode) { + case dwarf::DW_LNE_set_address: + case dwarf::DW_LNE_set_discriminator: + NewOp.Data = LineData.getAddress(&Offset); + break; + case dwarf::DW_LNE_define_file: + dumpFileEntry(LineData, Offset, NewOp.FileEntry); + break; + case dwarf::DW_LNE_end_sequence: + break; + default: + while (Offset < StartExt + NewOp.ExtLen) + NewOp.UnknownOpcodeData.push_back(LineData.getU8(&Offset)); + } + } else if (NewOp.Opcode < DebugLines.OpcodeBase) { + switch (NewOp.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: + NewOp.Data = LineData.getULEB128(&Offset); + break; + + case dwarf::DW_LNS_advance_line: + NewOp.SData = LineData.getSLEB128(&Offset); + break; + + case dwarf::DW_LNS_fixed_advance_pc: + NewOp.Data = LineData.getU16(&Offset); + break; + + default: + for (uint8_t i = 0; + i < DebugLines.StandardOpcodeLengths[NewOp.Opcode - 1]; ++i) + NewOp.StandardOpcodeData.push_back(LineData.getULEB128(&Offset)); + } + } + DebugLines.Opcodes.push_back(NewOp); + } + Y.DebugLines.push_back(DebugLines); + } + } +} + +std::error_code dwarf2yaml(DWARFContext &DCtx, DWARFYAML::Data &Y) { + dumpDebugAbbrev(DCtx, Y); + dumpDebugStrings(DCtx, Y); + dumpDebugARanges(DCtx, Y); + dumpDebugPubSections(DCtx, Y); + dumpDebugInfo(DCtx, Y); + dumpDebugLines(DCtx, Y); + return obj2yaml_error::success; +}