| //===--- 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 <unordered_map> | |
| #include "DWARFVisitor.h" | |
| #include "llvm/ObjectYAML/DWARFYAML.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.Length.isDWARF64() ? 8 : 4; | |
| } | |
| static unsigned getRefSize(const DWARFYAML::Unit &Unit) { | |
| if (Unit.Version == 2) | |
| return Unit.AddrSize; | |
| return getOffsetSize(Unit); | |
| } | |
| template <typename T> void DWARFYAML::VisitorImpl<T>::traverseDebugInfo() { | |
| // XXX BINARYEN: Handle multiple linked compile units, each of which can | |
| // refer to a different abbreviation list. | |
| // TODO: This code appears to assume that abbreviation codes increment by 1 | |
| // so that lookups are linear. In LLVM output that is true, but it might not | |
| // be in general. | |
| // Create a map of [byte offset into the abbreviation section] => [index in | |
| // DebugInfo.AbbrevDecls]. This avoids linear search for each CU. | |
| std::unordered_map<size_t, size_t> abbrByteOffsetToDeclsIndex; | |
| for (size_t i = 0; i < DebugInfo.AbbrevDecls.size(); i++) { | |
| auto offset = DebugInfo.AbbrevDecls[i].ListOffset; | |
| // The offset is the same for all entries for the same CU, so only note the | |
| // first as that is where the list for the CU (that LLVM DeclSet) begins. | |
| // That is, DebugInfo.AbbrevDecls looks like this: | |
| // | |
| // i CU Abbrev ListOffset | |
| // ============================ | |
| // 0 X X1 150 | |
| // 1 X X2 150 | |
| // 2 X X3 150 | |
| // .. | |
| // 6 Y Y1 260 | |
| // 7 Y Y2 260 | |
| // | |
| // Note how multiple rows i have the same CU. All those abbrevs have the | |
| // same ListOffset, which is the byte offset into the abbreviation section | |
| // for that set of abbreviations. | |
| if (abbrByteOffsetToDeclsIndex.count(offset)) { | |
| continue; | |
| } | |
| abbrByteOffsetToDeclsIndex[offset] = i; | |
| } | |
| for (auto &Unit : DebugInfo.CompileUnits) { | |
| // AbbrOffset is the byte offset into the abbreviation section, which we | |
| // need to find among the Abbrev's ListOffsets (which are the byte offsets | |
| // of where that abbreviation list begins). | |
| // TODO: Optimize this to not be O(#CUs * #abbrevs). | |
| auto offset = Unit.AbbrOffset; | |
| assert(abbrByteOffsetToDeclsIndex.count(offset)); | |
| size_t AbbrevStart = abbrByteOffsetToDeclsIndex[offset]; | |
| assert(DebugInfo.AbbrevDecls[AbbrevStart].ListOffset == offset); | |
| // Find the last entry in this abbreviation list. | |
| size_t AbbrevEnd = AbbrevStart; | |
| while (AbbrevEnd < DebugInfo.AbbrevDecls.size() && | |
| DebugInfo.AbbrevDecls[AbbrevEnd].Code) { | |
| AbbrevEnd++; | |
| } | |
| // XXX BINARYEN If there are no abbreviations, there is nothing to | |
| // do in this unit. | |
| if (AbbrevStart == AbbrevEnd) { | |
| continue; | |
| } | |
| onStartCompileUnit(Unit); | |
| if (Unit.Entries.empty()) { // XXX BINARYEN | |
| continue; | |
| } | |
| for (auto &Entry : Unit.Entries) { | |
| onStartDIE(Unit, Entry); | |
| if (Entry.AbbrCode == 0u) | |
| continue; | |
| // XXX BINARYEN valid abbreviation codes start from 1, so subtract that, | |
| // and are relative to the start of the abbrev table | |
| auto RelativeAbbrIndex = Entry.AbbrCode - 1 + AbbrevStart; | |
| if (RelativeAbbrIndex >= AbbrevEnd) { | |
| errs() << "warning: invalid abbreviation code " << Entry.AbbrCode | |
| << " (range: " << AbbrevStart << ".." << AbbrevEnd << ")\n"; | |
| continue; | |
| } | |
| auto &Abbrev = DebugInfo.AbbrevDecls[RelativeAbbrIndex]; | |
| 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.data(), | |
| 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.data(), | |
| 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.data(), | |
| 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.data(), | |
| FormVal->BlockData.size()), | |
| "")); | |
| 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: | |
| 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<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; | |
| 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<DWARFYAML::Data>; | |
| template class DWARFYAML::VisitorImpl<const DWARFYAML::Data>; |