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-exception 6 // 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 20 using namespace llvm; 21 using namespace dwarf; 22 23 DwarfFormat DWARFDebugMacro::MacroHeader::getDwarfFormat() const { 24 return Flags & MACRO_OFFSET_SIZE ? DWARF64 : DWARF32; 25 } 26 27 uint8_t DWARFDebugMacro::MacroHeader::getOffsetByteSize() const { 28 return getDwarfOffsetByteSize(getDwarfFormat()); 29 } 30 31 void DWARFDebugMacro::MacroHeader::dumpMacroHeader(raw_ostream &OS) const { 32 // FIXME: Add support for dumping opcode_operands_table 33 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 42 void 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 else 63 WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type); 64 switch (E.Type) { 65 default: 66 // Got a corrupted ".debug_macinfo/.debug_macro" section (invalid 67 // macinfo type). 68 break; 69 // debug_macro and debug_macinfo share some common encodings. 70 // DW_MACRO_define == DW_MACINFO_define 71 // DW_MACRO_undef == DW_MACINFO_undef 72 // DW_MACRO_start_file == DW_MACINFO_start_file 73 // DW_MACRO_end_file == DW_MACINFO_end_file 74 // For readability/uniformity we are using DW_MACRO_*. 75 // 76 // The GNU .debug_macro extension's entries have the same encoding 77 // 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 107 Error 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 will 117 // 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 type 140 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_define 156 // DW_MACRO_undef == DW_MACINFO_undef 157 // DW_MACRO_start_file == DW_MACINFO_start_file 158 // DW_MACRO_end_file == DW_MACINFO_end_file 159 // For readibility/uniformity we are using DW_MACRO_*. 160 case DW_MACRO_define: 161 case DW_MACRO_undef: 162 // 2. Source line 163 E.Line = Data.getULEB128(&Offset); 164 // 3. Macro string 165 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 is 171 // not supported in debug_macinfo[.dwo] sections. Assume it as an 172 // 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 line 178 E.Line = Data.getULEB128(&Offset); 179 // 3. Macro string 180 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 is 190 // not supported in debug_macinfo[.dwo] sections. Assume it as an 191 // 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 line 212 E.Line = Data.getULEB128(&Offset); 213 // 3. Source file id 214 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 constant 224 E.ExtConstant = Data.getULEB128(&Offset); 225 // 3. Vendor extension string 226 E.ExtStr = Data.getCStr(&Offset); 227 break; 228 } 229 } 230 return Error::success(); 231 } 232 233 Error 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_table 239 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