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