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