247 lines · cpp
1//===- DWARFDebugMacro.cpp ------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"10#include "llvm/ADT/DenseMap.h"11#include "llvm/BinaryFormat/Dwarf.h"12#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"13#include "llvm/DebugInfo/DWARF/DWARFDie.h"14#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"15#include "llvm/Support/Errc.h"16#include "llvm/Support/WithColor.h"17#include "llvm/Support/raw_ostream.h"18#include <cstdint>19 20using namespace llvm;21using namespace dwarf;22 23DwarfFormat DWARFDebugMacro::MacroHeader::getDwarfFormat() const {24 return Flags & MACRO_OFFSET_SIZE ? DWARF64 : DWARF32;25}26 27uint8_t DWARFDebugMacro::MacroHeader::getOffsetByteSize() const {28 return getDwarfOffsetByteSize(getDwarfFormat());29}30 31void DWARFDebugMacro::MacroHeader::dumpMacroHeader(raw_ostream &OS) const {32 // FIXME: Add support for dumping opcode_operands_table33 OS << format("macro header: version = 0x%04" PRIx16, Version)34 << format(", flags = 0x%02" PRIx8, Flags)35 << ", format = " << FormatString(getDwarfFormat());36 if (Flags & MACRO_DEBUG_LINE_OFFSET)37 OS << format(", debug_line_offset = 0x%0*" PRIx64, 2 * getOffsetByteSize(),38 DebugLineOffset);39 OS << "\n";40}41 42void DWARFDebugMacro::dump(raw_ostream &OS) const {43 unsigned IndLevel = 0;44 for (const auto &Macros : MacroLists) {45 OS << format("0x%08" PRIx64 ":\n", Macros.Offset);46 if (Macros.IsDebugMacro)47 Macros.Header.dumpMacroHeader(OS);48 for (const Entry &E : Macros.Macros) {49 // There should not be DW_MACINFO_end_file when IndLevel is Zero. However,50 // this check handles the case of corrupted ".debug_macinfo" section.51 if (IndLevel > 0)52 IndLevel -= (E.Type == DW_MACINFO_end_file);53 // Print indentation.54 for (unsigned I = 0; I < IndLevel; I++)55 OS << " ";56 IndLevel += (E.Type == DW_MACINFO_start_file);57 // Based on which version we are handling choose appropriate macro forms.58 if (Macros.IsDebugMacro)59 WithColor(OS, HighlightColor::Macro).get()60 << (Macros.Header.Version < 5 ? GnuMacroString(E.Type)61 : MacroString(E.Type));62 else63 WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type);64 switch (E.Type) {65 default:66 // Got a corrupted ".debug_macinfo/.debug_macro" section (invalid67 // macinfo type).68 break;69 // debug_macro and debug_macinfo share some common encodings.70 // DW_MACRO_define == DW_MACINFO_define71 // DW_MACRO_undef == DW_MACINFO_undef72 // DW_MACRO_start_file == DW_MACINFO_start_file73 // DW_MACRO_end_file == DW_MACINFO_end_file74 // For readability/uniformity we are using DW_MACRO_*.75 //76 // The GNU .debug_macro extension's entries have the same encoding77 // as DWARF 5's DW_MACRO_* entries, so we only use the latter here.78 case DW_MACRO_define:79 case DW_MACRO_undef:80 case DW_MACRO_define_strp:81 case DW_MACRO_undef_strp:82 case DW_MACRO_define_strx:83 case DW_MACRO_undef_strx:84 OS << " - lineno: " << E.Line;85 OS << " macro: " << E.MacroStr;86 break;87 case DW_MACRO_start_file:88 OS << " - lineno: " << E.Line;89 OS << " filenum: " << E.File;90 break;91 case DW_MACRO_import:92 OS << format(" - import offset: 0x%0*" PRIx64,93 2 * Macros.Header.getOffsetByteSize(), E.ImportOffset);94 break;95 case DW_MACRO_end_file:96 break;97 case DW_MACINFO_vendor_ext:98 OS << " - constant: " << E.ExtConstant;99 OS << " string: " << E.ExtStr;100 break;101 }102 OS << "\n";103 }104 }105}106 107Error DWARFDebugMacro::parseImpl(108 std::optional<DWARFUnitVector::compile_unit_range> Units,109 std::optional<DataExtractor> StringExtractor, DWARFDataExtractor Data,110 bool IsMacro) {111 uint64_t Offset = 0;112 MacroList *M = nullptr;113 using MacroToUnitsMap = DenseMap<uint64_t, DWARFUnit *>;114 MacroToUnitsMap MacroToUnits;115 if (IsMacro && Data.isValidOffset(Offset)) {116 // Keep a mapping from Macro contribution to CUs, this will117 // be needed while retrieving macro from DW_MACRO_define_strx form.118 for (const auto &U : *Units)119 if (auto CUDIE = U->getUnitDIE())120 // Skip units which does not contibutes to macro section.121 if (auto MacroOffset = toSectionOffset(CUDIE.find(DW_AT_macros)))122 MacroToUnits.try_emplace(*MacroOffset, U.get());123 }124 while (Data.isValidOffset(Offset)) {125 if (!M) {126 MacroLists.emplace_back();127 M = &MacroLists.back();128 M->Offset = Offset;129 M->IsDebugMacro = IsMacro;130 if (IsMacro) {131 auto Err = M->Header.parseMacroHeader(Data, &Offset);132 if (Err)133 return Err;134 }135 }136 // A macro list entry consists of:137 M->Macros.emplace_back();138 Entry &E = M->Macros.back();139 // 1. Macinfo type140 E.Type = Data.getULEB128(&Offset);141 142 if (E.Type == 0) {143 // Reached end of a ".debug_macinfo/debug_macro" section contribution.144 M = nullptr;145 continue;146 }147 148 switch (E.Type) {149 default:150 // Got a corrupted ".debug_macinfo" section (invalid macinfo type).151 // Push the corrupted entry to the list and halt parsing.152 E.Type = DW_MACINFO_invalid;153 return Error::success();154 // debug_macro and debug_macinfo share some common encodings.155 // DW_MACRO_define == DW_MACINFO_define156 // DW_MACRO_undef == DW_MACINFO_undef157 // DW_MACRO_start_file == DW_MACINFO_start_file158 // DW_MACRO_end_file == DW_MACINFO_end_file159 // For readibility/uniformity we are using DW_MACRO_*.160 case DW_MACRO_define:161 case DW_MACRO_undef:162 // 2. Source line163 E.Line = Data.getULEB128(&Offset);164 // 3. Macro string165 E.MacroStr = Data.getCStr(&Offset);166 break;167 case DW_MACRO_define_strp:168 case DW_MACRO_undef_strp: {169 if (!IsMacro) {170 // DW_MACRO_define_strp is a new form introduced in DWARFv5, it is171 // not supported in debug_macinfo[.dwo] sections. Assume it as an172 // invalid entry, push it and halt parsing.173 E.Type = DW_MACINFO_invalid;174 return Error::success();175 }176 uint64_t StrOffset = 0;177 // 2. Source line178 E.Line = Data.getULEB128(&Offset);179 // 3. Macro string180 StrOffset =181 Data.getRelocatedValue(M->Header.getOffsetByteSize(), &Offset);182 assert(StringExtractor && "String Extractor not found");183 E.MacroStr = StringExtractor->getCStr(&StrOffset);184 break;185 }186 case DW_MACRO_define_strx:187 case DW_MACRO_undef_strx: {188 if (!IsMacro) {189 // DW_MACRO_define_strx is a new form introduced in DWARFv5, it is190 // not supported in debug_macinfo[.dwo] sections. Assume it as an191 // invalid entry, push it and halt parsing.192 E.Type = DW_MACINFO_invalid;193 return Error::success();194 }195 E.Line = Data.getULEB128(&Offset);196 auto MacroContributionOffset = MacroToUnits.find(M->Offset);197 if (MacroContributionOffset == MacroToUnits.end())198 return createStringError(errc::invalid_argument,199 "Macro contribution of the unit not found");200 Expected<uint64_t> StrOffset =201 MacroContributionOffset->second->getStringOffsetSectionItem(202 Data.getULEB128(&Offset));203 if (!StrOffset)204 return StrOffset.takeError();205 E.MacroStr =206 MacroContributionOffset->second->getStringExtractor().getCStr(207 &*StrOffset);208 break;209 }210 case DW_MACRO_start_file:211 // 2. Source line212 E.Line = Data.getULEB128(&Offset);213 // 3. Source file id214 E.File = Data.getULEB128(&Offset);215 break;216 case DW_MACRO_end_file:217 break;218 case DW_MACRO_import:219 E.ImportOffset =220 Data.getRelocatedValue(M->Header.getOffsetByteSize(), &Offset);221 break;222 case DW_MACINFO_vendor_ext:223 // 2. Vendor extension constant224 E.ExtConstant = Data.getULEB128(&Offset);225 // 3. Vendor extension string226 E.ExtStr = Data.getCStr(&Offset);227 break;228 }229 }230 return Error::success();231}232 233Error DWARFDebugMacro::MacroHeader::parseMacroHeader(DWARFDataExtractor Data,234 uint64_t *Offset) {235 Version = Data.getU16(Offset);236 uint8_t FlagData = Data.getU8(Offset);237 238 // FIXME: Add support for parsing opcode_operands_table239 if (FlagData & MACRO_OPCODE_OPERANDS_TABLE)240 return createStringError(errc::not_supported,241 "opcode_operands_table is not supported");242 Flags = FlagData;243 if (Flags & MACRO_DEBUG_LINE_OFFSET)244 DebugLineOffset = Data.getUnsigned(Offset, getOffsetByteSize());245 return Error::success();246}247