Home | History | Annotate | Line # | Download | only in DWARF
      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