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