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/BinaryFormat/Dwarf.h" 11 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 12 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" 13 #include "llvm/Support/WithColor.h" 14 #include "llvm/Support/raw_ostream.h" 15 #include <cstdint> 16 17 using namespace llvm; 18 using namespace dwarf; 19 20 void DWARFDebugMacro::MacroHeader::dumpMacroHeader(raw_ostream &OS) const { 21 // FIXME: Add support for dumping opcode_operands_table 22 OS << format("macro header: version = 0x%04" PRIx16 ", flags = 0x%02" PRIx8, 23 Version, Flags); 24 if (Flags & MACRO_DEBUG_LINE_OFFSET) 25 OS << format(", debug_line_offset = 0x%04" PRIx64 "\n", DebugLineOffset); 26 else 27 OS << "\n"; 28 } 29 30 void DWARFDebugMacro::dump(raw_ostream &OS) const { 31 unsigned IndLevel = 0; 32 for (const auto &Macros : MacroLists) { 33 OS << format("0x%08" PRIx64 ":\n", Macros.Offset); 34 if (Macros.Header.Version >= 5) 35 Macros.Header.dumpMacroHeader(OS); 36 for (const Entry &E : Macros.Macros) { 37 // There should not be DW_MACINFO_end_file when IndLevel is Zero. However, 38 // this check handles the case of corrupted ".debug_macinfo" section. 39 if (IndLevel > 0) 40 IndLevel -= (E.Type == DW_MACINFO_end_file); 41 // Print indentation. 42 for (unsigned I = 0; I < IndLevel; I++) 43 OS << " "; 44 IndLevel += (E.Type == DW_MACINFO_start_file); 45 // Based on which version we are handling choose appropriate macro forms. 46 if (Macros.Header.Version >= 5) 47 WithColor(OS, HighlightColor::Macro).get() << MacroString(E.Type); 48 else 49 WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type); 50 switch (E.Type) { 51 default: 52 // Got a corrupted ".debug_macinfo/.debug_macro" section (invalid 53 // macinfo type). 54 break; 55 // debug_macro and debug_macinfo share some common encodings. 56 // DW_MACRO_define == DW_MACINFO_define 57 // DW_MACRO_undef == DW_MACINFO_undef 58 // DW_MACRO_start_file == DW_MACINFO_start_file 59 // DW_MACRO_end_file == DW_MACINFO_end_file 60 // For readability/uniformity we are using DW_MACRO_*. 61 case DW_MACRO_define: 62 case DW_MACRO_undef: 63 case DW_MACRO_define_strp: 64 case DW_MACRO_undef_strp: 65 case DW_MACRO_define_strx: 66 case DW_MACRO_undef_strx: 67 OS << " - lineno: " << E.Line; 68 OS << " macro: " << E.MacroStr; 69 break; 70 case DW_MACRO_start_file: 71 OS << " - lineno: " << E.Line; 72 OS << " filenum: " << E.File; 73 break; 74 case DW_MACRO_import: 75 OS << format(" - import offset: 0x%08" PRIx64, E.ImportOffset); 76 break; 77 case DW_MACRO_end_file: 78 break; 79 case DW_MACINFO_vendor_ext: 80 OS << " - constant: " << E.ExtConstant; 81 OS << " string: " << E.ExtStr; 82 break; 83 } 84 OS << "\n"; 85 } 86 } 87 } 88 89 Error DWARFDebugMacro::parseImpl( 90 Optional<DWARFUnitVector::iterator_range> Units, 91 Optional<DataExtractor> StringExtractor, DWARFDataExtractor Data, 92 bool IsMacro) { 93 uint64_t Offset = 0; 94 MacroList *M = nullptr; 95 using MacroToUnitsMap = DenseMap<uint64_t, DWARFUnit *>; 96 MacroToUnitsMap MacroToUnits; 97 if (IsMacro && Data.isValidOffset(Offset)) { 98 // Keep a mapping from Macro contribution to CUs, this will 99 // be needed while retrieving macro from DW_MACRO_define_strx form. 100 for (const auto &U : Units.getValue()) 101 if (auto CUDIE = U->getUnitDIE()) 102 // Skip units which does not contibutes to macro section. 103 if (auto MacroOffset = toSectionOffset(CUDIE.find(DW_AT_macros))) 104 MacroToUnits.try_emplace(*MacroOffset, U.get()); 105 } 106 while (Data.isValidOffset(Offset)) { 107 if (!M) { 108 MacroLists.emplace_back(); 109 M = &MacroLists.back(); 110 M->Offset = Offset; 111 if (IsMacro) { 112 auto Err = M->Header.parseMacroHeader(Data, &Offset); 113 if (Err) 114 return Err; 115 } 116 } 117 // A macro list entry consists of: 118 M->Macros.emplace_back(); 119 Entry &E = M->Macros.back(); 120 // 1. Macinfo type 121 E.Type = Data.getULEB128(&Offset); 122 123 if (E.Type == 0) { 124 // Reached end of a ".debug_macinfo/debug_macro" section contribution. 125 M = nullptr; 126 continue; 127 } 128 129 switch (E.Type) { 130 default: 131 // Got a corrupted ".debug_macinfo" section (invalid macinfo type). 132 // Push the corrupted entry to the list and halt parsing. 133 E.Type = DW_MACINFO_invalid; 134 return Error::success(); 135 // debug_macro and debug_macinfo share some common encodings. 136 // DW_MACRO_define == DW_MACINFO_define 137 // DW_MACRO_undef == DW_MACINFO_undef 138 // DW_MACRO_start_file == DW_MACINFO_start_file 139 // DW_MACRO_end_file == DW_MACINFO_end_file 140 // For readibility/uniformity we are using DW_MACRO_*. 141 case DW_MACRO_define: 142 case DW_MACRO_undef: 143 // 2. Source line 144 E.Line = Data.getULEB128(&Offset); 145 // 3. Macro string 146 E.MacroStr = Data.getCStr(&Offset); 147 break; 148 case DW_MACRO_define_strp: 149 case DW_MACRO_undef_strp: { 150 if (!IsMacro) { 151 // DW_MACRO_define_strp is a new form introduced in DWARFv5, it is 152 // not supported in debug_macinfo[.dwo] sections. Assume it as an 153 // invalid entry, push it and halt parsing. 154 E.Type = DW_MACINFO_invalid; 155 return Error::success(); 156 } 157 uint64_t StrOffset = 0; 158 // 2. Source line 159 E.Line = Data.getULEB128(&Offset); 160 // 3. Macro string 161 // FIXME: Add support for DWARF64 162 StrOffset = Data.getRelocatedValue(/*OffsetSize=*/4, &Offset); 163 assert(StringExtractor && "String Extractor not found"); 164 E.MacroStr = StringExtractor->getCStr(&StrOffset); 165 break; 166 } 167 case DW_MACRO_define_strx: 168 case DW_MACRO_undef_strx: { 169 if (!IsMacro) { 170 // DW_MACRO_define_strx 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 E.Line = Data.getULEB128(&Offset); 177 auto MacroContributionOffset = MacroToUnits.find(M->Offset); 178 if (MacroContributionOffset == MacroToUnits.end()) 179 return createStringError(errc::invalid_argument, 180 "Macro contribution of the unit not found"); 181 Optional<uint64_t> StrOffset = 182 MacroContributionOffset->second->getStringOffsetSectionItem( 183 Data.getULEB128(&Offset)); 184 if (!StrOffset) 185 return createStringError( 186 errc::invalid_argument, 187 "String offsets contribution of the unit not found"); 188 E.MacroStr = 189 MacroContributionOffset->second->getStringExtractor().getCStr( 190 &*StrOffset); 191 break; 192 } 193 case DW_MACRO_start_file: 194 // 2. Source line 195 E.Line = Data.getULEB128(&Offset); 196 // 3. Source file id 197 E.File = Data.getULEB128(&Offset); 198 break; 199 case DW_MACRO_end_file: 200 break; 201 case DW_MACRO_import: 202 // FIXME: Add support for DWARF64 203 E.ImportOffset = Data.getRelocatedValue(/*OffsetSize=*/4, &Offset); 204 break; 205 case DW_MACINFO_vendor_ext: 206 // 2. Vendor extension constant 207 E.ExtConstant = Data.getULEB128(&Offset); 208 // 3. Vendor extension string 209 E.ExtStr = Data.getCStr(&Offset); 210 break; 211 } 212 } 213 return Error::success(); 214 } 215 216 Error DWARFDebugMacro::MacroHeader::parseMacroHeader(DWARFDataExtractor Data, 217 uint64_t *Offset) { 218 Version = Data.getU16(Offset); 219 uint8_t FlagData = Data.getU8(Offset); 220 // FIXME: Add support for DWARF64 221 if (FlagData & MACRO_OFFSET_SIZE) 222 return createStringError(errc::not_supported, "DWARF64 is not supported"); 223 224 // FIXME: Add support for parsing opcode_operands_table 225 if (FlagData & MACRO_OPCODE_OPERANDS_TABLE) 226 return createStringError(errc::not_supported, 227 "opcode_operands_table is not supported"); 228 Flags = FlagData; 229 if (Flags & MACRO_DEBUG_LINE_OFFSET) 230 DebugLineOffset = Data.getU32(Offset); 231 return Error::success(); 232 } 233