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 OS << " - lineno: " << E.Line; 66 OS << " macro: " << E.MacroStr; 67 break; 68 case DW_MACRO_start_file: 69 OS << " - lineno: " << E.Line; 70 OS << " filenum: " << E.File; 71 break; 72 case DW_MACRO_import: 73 OS << format(" - import offset: 0x%08" PRIx64, E.ImportOffset); 74 break; 75 case DW_MACRO_end_file: 76 break; 77 case DW_MACINFO_vendor_ext: 78 OS << " - constant: " << E.ExtConstant; 79 OS << " string: " << E.ExtStr; 80 break; 81 } 82 OS << "\n"; 83 } 84 } 85 } 86 87 Error DWARFDebugMacro::parse(DataExtractor StringExtractor, 88 DWARFDataExtractor Data, bool IsMacro) { 89 uint64_t Offset = 0; 90 MacroList *M = nullptr; 91 while (Data.isValidOffset(Offset)) { 92 if (!M) { 93 MacroLists.emplace_back(); 94 M = &MacroLists.back(); 95 M->Offset = Offset; 96 if (IsMacro) { 97 auto Err = M->Header.parseMacroHeader(Data, &Offset); 98 if (Err) 99 return Err; 100 } 101 } 102 // A macro list entry consists of: 103 M->Macros.emplace_back(); 104 Entry &E = M->Macros.back(); 105 // 1. Macinfo type 106 E.Type = Data.getULEB128(&Offset); 107 108 if (E.Type == 0) { 109 // Reached end of a ".debug_macinfo/debug_macro" section contribution. 110 M = nullptr; 111 continue; 112 } 113 114 switch (E.Type) { 115 default: 116 // Got a corrupted ".debug_macinfo" section (invalid macinfo type). 117 // Push the corrupted entry to the list and halt parsing. 118 E.Type = DW_MACINFO_invalid; 119 return Error::success(); 120 // debug_macro and debug_macinfo share some common encodings. 121 // DW_MACRO_define == DW_MACINFO_define 122 // DW_MACRO_undef == DW_MACINFO_undef 123 // DW_MACRO_start_file == DW_MACINFO_start_file 124 // DW_MACRO_end_file == DW_MACINFO_end_file 125 // For readibility/uniformity we are using DW_MACRO_*. 126 case DW_MACRO_define: 127 case DW_MACRO_undef: 128 // 2. Source line 129 E.Line = Data.getULEB128(&Offset); 130 // 3. Macro string 131 E.MacroStr = Data.getCStr(&Offset); 132 break; 133 case DW_MACRO_define_strp: 134 case DW_MACRO_undef_strp: { 135 uint64_t StrOffset = 0; 136 // 2. Source line 137 E.Line = Data.getULEB128(&Offset); 138 // 3. Macro string 139 // FIXME: Add support for DWARF64 140 StrOffset = Data.getRelocatedValue(/*OffsetSize=*/4, &Offset); 141 E.MacroStr = StringExtractor.getCStr(&StrOffset); 142 break; 143 } 144 case DW_MACRO_start_file: 145 // 2. Source line 146 E.Line = Data.getULEB128(&Offset); 147 // 3. Source file id 148 E.File = Data.getULEB128(&Offset); 149 break; 150 case DW_MACRO_end_file: 151 break; 152 case DW_MACRO_import: 153 // FIXME: Add support for DWARF64 154 E.ImportOffset = Data.getRelocatedValue(/*OffsetSize=*/4, &Offset); 155 break; 156 case DW_MACINFO_vendor_ext: 157 // 2. Vendor extension constant 158 E.ExtConstant = Data.getULEB128(&Offset); 159 // 3. Vendor extension string 160 E.ExtStr = Data.getCStr(&Offset); 161 break; 162 } 163 } 164 return Error::success(); 165 } 166 167 Error DWARFDebugMacro::MacroHeader::parseMacroHeader(DWARFDataExtractor Data, 168 uint64_t *Offset) { 169 Version = Data.getU16(Offset); 170 uint8_t FlagData = Data.getU8(Offset); 171 // FIXME: Add support for DWARF64 172 if (FlagData & MACRO_OFFSET_SIZE) 173 return createStringError(errc::not_supported, "DWARF64 is not supported"); 174 175 // FIXME: Add support for parsing opcode_operands_table 176 if (FlagData & MACRO_OPCODE_OPERANDS_TABLE) 177 return createStringError(errc::not_supported, 178 "opcode_operands_table is not supported"); 179 Flags = FlagData; 180 if (Flags & MACRO_DEBUG_LINE_OFFSET) 181 DebugLineOffset = Data.getU32(Offset); 182 return Error::success(); 183 } 184