128db7e65SEugene Zelenko //===- DWARFDebugMacro.cpp ------------------------------------------------===//
2e59cc3e5SAmjad Aboud //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e59cc3e5SAmjad Aboud //
7e59cc3e5SAmjad Aboud //===----------------------------------------------------------------------===//
8e59cc3e5SAmjad Aboud 
928db7e65SEugene Zelenko #include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
10290e4823Sserge-sans-paille #include "llvm/ADT/DenseMap.h"
11264b5d9eSZachary Turner #include "llvm/BinaryFormat/Dwarf.h"
1269c8fb1cSSourabh Singh Tomar #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
13290e4823Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFDie.h"
14290e4823Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
15290e4823Sserge-sans-paille #include "llvm/Support/Errc.h"
1669217539SJonas Devlieghere #include "llvm/Support/WithColor.h"
17e59cc3e5SAmjad Aboud #include "llvm/Support/raw_ostream.h"
1828db7e65SEugene Zelenko #include <cstdint>
19e59cc3e5SAmjad Aboud 
20e59cc3e5SAmjad Aboud using namespace llvm;
21e59cc3e5SAmjad Aboud using namespace dwarf;
22e59cc3e5SAmjad Aboud 
getDwarfFormat() const23ccbd7e8dSIgor Kudrin DwarfFormat DWARFDebugMacro::MacroHeader::getDwarfFormat() const {
24ccbd7e8dSIgor Kudrin   return Flags & MACRO_OFFSET_SIZE ? DWARF64 : DWARF32;
25ccbd7e8dSIgor Kudrin }
26ccbd7e8dSIgor Kudrin 
getOffsetByteSize() const27ccbd7e8dSIgor Kudrin uint8_t DWARFDebugMacro::MacroHeader::getOffsetByteSize() const {
28ccbd7e8dSIgor Kudrin   return getDwarfOffsetByteSize(getDwarfFormat());
29ccbd7e8dSIgor Kudrin }
30ccbd7e8dSIgor Kudrin 
dumpMacroHeader(raw_ostream & OS) const3169c8fb1cSSourabh Singh Tomar void DWARFDebugMacro::MacroHeader::dumpMacroHeader(raw_ostream &OS) const {
3269c8fb1cSSourabh Singh Tomar   // FIXME: Add support for dumping opcode_operands_table
33ccbd7e8dSIgor Kudrin   OS << format("macro header: version = 0x%04" PRIx16, Version)
34ccbd7e8dSIgor Kudrin      << format(", flags = 0x%02" PRIx8, Flags)
35ccbd7e8dSIgor Kudrin      << ", format = " << FormatString(getDwarfFormat());
3669c8fb1cSSourabh Singh Tomar   if (Flags & MACRO_DEBUG_LINE_OFFSET)
37ccbd7e8dSIgor Kudrin     OS << format(", debug_line_offset = 0x%0*" PRIx64, 2 * getOffsetByteSize(),
38ccbd7e8dSIgor Kudrin                  DebugLineOffset);
3969c8fb1cSSourabh Singh Tomar   OS << "\n";
4069c8fb1cSSourabh Singh Tomar }
4169c8fb1cSSourabh Singh Tomar 
dump(raw_ostream & OS) const42e59cc3e5SAmjad Aboud void DWARFDebugMacro::dump(raw_ostream &OS) const {
43e59cc3e5SAmjad Aboud   unsigned IndLevel = 0;
4439c308f6SDavid Blaikie   for (const auto &Macros : MacroLists) {
454ce3e507SDavid Blaikie     OS << format("0x%08" PRIx64 ":\n", Macros.Offset);
4691bd9db2SDavid Stenberg     if (Macros.IsDebugMacro)
4769c8fb1cSSourabh Singh Tomar       Macros.Header.dumpMacroHeader(OS);
484ce3e507SDavid Blaikie     for (const Entry &E : Macros.Macros) {
49e59cc3e5SAmjad Aboud       // There should not be DW_MACINFO_end_file when IndLevel is Zero. However,
50e59cc3e5SAmjad Aboud       // this check handles the case of corrupted ".debug_macinfo" section.
51e59cc3e5SAmjad Aboud       if (IndLevel > 0)
52e59cc3e5SAmjad Aboud         IndLevel -= (E.Type == DW_MACINFO_end_file);
53e59cc3e5SAmjad Aboud       // Print indentation.
54e59cc3e5SAmjad Aboud       for (unsigned I = 0; I < IndLevel; I++)
55e59cc3e5SAmjad Aboud         OS << "  ";
56e59cc3e5SAmjad Aboud       IndLevel += (E.Type == DW_MACINFO_start_file);
5769c8fb1cSSourabh Singh Tomar       // Based on which version we are handling choose appropriate macro forms.
5891bd9db2SDavid Stenberg       if (Macros.IsDebugMacro)
5991bd9db2SDavid Stenberg         WithColor(OS, HighlightColor::Macro).get()
6091bd9db2SDavid Stenberg             << (Macros.Header.Version < 5 ? GnuMacroString(E.Type)
6191bd9db2SDavid Stenberg                                           : MacroString(E.Type));
6269c8fb1cSSourabh Singh Tomar       else
6369217539SJonas Devlieghere         WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type);
64e59cc3e5SAmjad Aboud       switch (E.Type) {
65e59cc3e5SAmjad Aboud       default:
6669c8fb1cSSourabh Singh Tomar         // Got a corrupted ".debug_macinfo/.debug_macro" section (invalid
6769c8fb1cSSourabh Singh Tomar         // macinfo type).
68e59cc3e5SAmjad Aboud         break;
6969c8fb1cSSourabh Singh Tomar         // debug_macro and debug_macinfo share some common encodings.
7069c8fb1cSSourabh Singh Tomar         // DW_MACRO_define     == DW_MACINFO_define
7169c8fb1cSSourabh Singh Tomar         // DW_MACRO_undef      == DW_MACINFO_undef
7269c8fb1cSSourabh Singh Tomar         // DW_MACRO_start_file == DW_MACINFO_start_file
7369c8fb1cSSourabh Singh Tomar         // DW_MACRO_end_file   == DW_MACINFO_end_file
7469c8fb1cSSourabh Singh Tomar         // For readability/uniformity we are using DW_MACRO_*.
7591bd9db2SDavid Stenberg         //
7691bd9db2SDavid Stenberg         // The GNU .debug_macro extension's entries have the same encoding
7791bd9db2SDavid Stenberg         // as DWARF 5's DW_MACRO_* entries, so we only use the latter here.
7869c8fb1cSSourabh Singh Tomar       case DW_MACRO_define:
7969c8fb1cSSourabh Singh Tomar       case DW_MACRO_undef:
8069c8fb1cSSourabh Singh Tomar       case DW_MACRO_define_strp:
8169c8fb1cSSourabh Singh Tomar       case DW_MACRO_undef_strp:
8293aee9caSSourabh Singh Tomar       case DW_MACRO_define_strx:
8393aee9caSSourabh Singh Tomar       case DW_MACRO_undef_strx:
84e59cc3e5SAmjad Aboud         OS << " - lineno: " << E.Line;
85e59cc3e5SAmjad Aboud         OS << " macro: " << E.MacroStr;
86e59cc3e5SAmjad Aboud         break;
8769c8fb1cSSourabh Singh Tomar       case DW_MACRO_start_file:
88e59cc3e5SAmjad Aboud         OS << " - lineno: " << E.Line;
89e59cc3e5SAmjad Aboud         OS << " filenum: " << E.File;
90e59cc3e5SAmjad Aboud         break;
9185b49ecbSSourabh Singh Tomar       case DW_MACRO_import:
92ccbd7e8dSIgor Kudrin         OS << format(" - import offset: 0x%0*" PRIx64,
93ccbd7e8dSIgor Kudrin                      2 * Macros.Header.getOffsetByteSize(), E.ImportOffset);
9485b49ecbSSourabh Singh Tomar         break;
9569c8fb1cSSourabh Singh Tomar       case DW_MACRO_end_file:
96e59cc3e5SAmjad Aboud         break;
97e59cc3e5SAmjad Aboud       case DW_MACINFO_vendor_ext:
98e59cc3e5SAmjad Aboud         OS << " - constant: " << E.ExtConstant;
99e59cc3e5SAmjad Aboud         OS << " string: " << E.ExtStr;
100e59cc3e5SAmjad Aboud         break;
101e59cc3e5SAmjad Aboud       }
102e59cc3e5SAmjad Aboud       OS << "\n";
103e59cc3e5SAmjad Aboud     }
10439c308f6SDavid Blaikie   }
105e59cc3e5SAmjad Aboud }
106e59cc3e5SAmjad Aboud 
parseImpl(Optional<DWARFUnitVector::compile_unit_range> Units,Optional<DataExtractor> StringExtractor,DWARFDataExtractor Data,bool IsMacro)10793aee9caSSourabh Singh Tomar Error DWARFDebugMacro::parseImpl(
1080328feb0SDavid Blaikie     Optional<DWARFUnitVector::compile_unit_range> Units,
10993aee9caSSourabh Singh Tomar     Optional<DataExtractor> StringExtractor, DWARFDataExtractor Data,
11093aee9caSSourabh Singh Tomar     bool IsMacro) {
111f26a70a5SIgor Kudrin   uint64_t Offset = 0;
11239c308f6SDavid Blaikie   MacroList *M = nullptr;
11393aee9caSSourabh Singh Tomar   using MacroToUnitsMap = DenseMap<uint64_t, DWARFUnit *>;
11493aee9caSSourabh Singh Tomar   MacroToUnitsMap MacroToUnits;
11593aee9caSSourabh Singh Tomar   if (IsMacro && Data.isValidOffset(Offset)) {
11693aee9caSSourabh Singh Tomar     // Keep a mapping from Macro contribution to CUs, this will
11793aee9caSSourabh Singh Tomar     // be needed while retrieving macro from DW_MACRO_define_strx form.
118*7a47ee51SKazu Hirata     for (const auto &U : *Units)
11993aee9caSSourabh Singh Tomar       if (auto CUDIE = U->getUnitDIE())
12093aee9caSSourabh Singh Tomar         // Skip units which does not contibutes to macro section.
12193aee9caSSourabh Singh Tomar         if (auto MacroOffset = toSectionOffset(CUDIE.find(DW_AT_macros)))
12293aee9caSSourabh Singh Tomar           MacroToUnits.try_emplace(*MacroOffset, U.get());
12393aee9caSSourabh Singh Tomar   }
12469c8fb1cSSourabh Singh Tomar   while (Data.isValidOffset(Offset)) {
12539c308f6SDavid Blaikie     if (!M) {
12639c308f6SDavid Blaikie       MacroLists.emplace_back();
12739c308f6SDavid Blaikie       M = &MacroLists.back();
1284ce3e507SDavid Blaikie       M->Offset = Offset;
12991bd9db2SDavid Stenberg       M->IsDebugMacro = IsMacro;
13069c8fb1cSSourabh Singh Tomar       if (IsMacro) {
13169c8fb1cSSourabh Singh Tomar         auto Err = M->Header.parseMacroHeader(Data, &Offset);
13269c8fb1cSSourabh Singh Tomar         if (Err)
1330a3845b7Sscentini           return Err;
13469c8fb1cSSourabh Singh Tomar       }
13539c308f6SDavid Blaikie     }
136e59cc3e5SAmjad Aboud     // A macro list entry consists of:
1374ce3e507SDavid Blaikie     M->Macros.emplace_back();
1384ce3e507SDavid Blaikie     Entry &E = M->Macros.back();
139e59cc3e5SAmjad Aboud     // 1. Macinfo type
14069c8fb1cSSourabh Singh Tomar     E.Type = Data.getULEB128(&Offset);
141e59cc3e5SAmjad Aboud 
142e59cc3e5SAmjad Aboud     if (E.Type == 0) {
14369c8fb1cSSourabh Singh Tomar       // Reached end of a ".debug_macinfo/debug_macro" section contribution.
1444ce3e507SDavid Blaikie       M = nullptr;
14539c308f6SDavid Blaikie       continue;
146e59cc3e5SAmjad Aboud     }
147e59cc3e5SAmjad Aboud 
148e59cc3e5SAmjad Aboud     switch (E.Type) {
149e59cc3e5SAmjad Aboud     default:
150e59cc3e5SAmjad Aboud       // Got a corrupted ".debug_macinfo" section (invalid macinfo type).
151e59cc3e5SAmjad Aboud       // Push the corrupted entry to the list and halt parsing.
152e59cc3e5SAmjad Aboud       E.Type = DW_MACINFO_invalid;
15369c8fb1cSSourabh Singh Tomar       return Error::success();
15469c8fb1cSSourabh Singh Tomar     // debug_macro and debug_macinfo share some common encodings.
15569c8fb1cSSourabh Singh Tomar     // DW_MACRO_define     == DW_MACINFO_define
15669c8fb1cSSourabh Singh Tomar     // DW_MACRO_undef      == DW_MACINFO_undef
15769c8fb1cSSourabh Singh Tomar     // DW_MACRO_start_file == DW_MACINFO_start_file
15869c8fb1cSSourabh Singh Tomar     // DW_MACRO_end_file   == DW_MACINFO_end_file
15969c8fb1cSSourabh Singh Tomar     // For readibility/uniformity we are using DW_MACRO_*.
16069c8fb1cSSourabh Singh Tomar     case DW_MACRO_define:
16169c8fb1cSSourabh Singh Tomar     case DW_MACRO_undef:
162e59cc3e5SAmjad Aboud       // 2. Source line
16369c8fb1cSSourabh Singh Tomar       E.Line = Data.getULEB128(&Offset);
164e59cc3e5SAmjad Aboud       // 3. Macro string
16569c8fb1cSSourabh Singh Tomar       E.MacroStr = Data.getCStr(&Offset);
166e59cc3e5SAmjad Aboud       break;
16769c8fb1cSSourabh Singh Tomar     case DW_MACRO_define_strp:
16869c8fb1cSSourabh Singh Tomar     case DW_MACRO_undef_strp: {
16993aee9caSSourabh Singh Tomar       if (!IsMacro) {
17093aee9caSSourabh Singh Tomar         // DW_MACRO_define_strp is a new form introduced in DWARFv5, it is
17193aee9caSSourabh Singh Tomar         // not supported in debug_macinfo[.dwo] sections. Assume it as an
17293aee9caSSourabh Singh Tomar         // invalid entry, push it and halt parsing.
17393aee9caSSourabh Singh Tomar         E.Type = DW_MACINFO_invalid;
17493aee9caSSourabh Singh Tomar         return Error::success();
17593aee9caSSourabh Singh Tomar       }
17669c8fb1cSSourabh Singh Tomar       uint64_t StrOffset = 0;
177e59cc3e5SAmjad Aboud       // 2. Source line
17869c8fb1cSSourabh Singh Tomar       E.Line = Data.getULEB128(&Offset);
17969c8fb1cSSourabh Singh Tomar       // 3. Macro string
180ccbd7e8dSIgor Kudrin       StrOffset =
181ccbd7e8dSIgor Kudrin           Data.getRelocatedValue(M->Header.getOffsetByteSize(), &Offset);
18293aee9caSSourabh Singh Tomar       assert(StringExtractor && "String Extractor not found");
18393aee9caSSourabh Singh Tomar       E.MacroStr = StringExtractor->getCStr(&StrOffset);
18493aee9caSSourabh Singh Tomar       break;
18593aee9caSSourabh Singh Tomar     }
18693aee9caSSourabh Singh Tomar     case DW_MACRO_define_strx:
18793aee9caSSourabh Singh Tomar     case DW_MACRO_undef_strx: {
18893aee9caSSourabh Singh Tomar       if (!IsMacro) {
18993aee9caSSourabh Singh Tomar         // DW_MACRO_define_strx is a new form introduced in DWARFv5, it is
19093aee9caSSourabh Singh Tomar         // not supported in debug_macinfo[.dwo] sections. Assume it as an
19193aee9caSSourabh Singh Tomar         // invalid entry, push it and halt parsing.
19293aee9caSSourabh Singh Tomar         E.Type = DW_MACINFO_invalid;
19393aee9caSSourabh Singh Tomar         return Error::success();
19493aee9caSSourabh Singh Tomar       }
19593aee9caSSourabh Singh Tomar       E.Line = Data.getULEB128(&Offset);
19693aee9caSSourabh Singh Tomar       auto MacroContributionOffset = MacroToUnits.find(M->Offset);
19793aee9caSSourabh Singh Tomar       if (MacroContributionOffset == MacroToUnits.end())
19893aee9caSSourabh Singh Tomar         return createStringError(errc::invalid_argument,
19993aee9caSSourabh Singh Tomar                                  "Macro contribution of the unit not found");
20092f2d02bSDavid Blaikie       Expected<uint64_t> StrOffset =
20193aee9caSSourabh Singh Tomar           MacroContributionOffset->second->getStringOffsetSectionItem(
20293aee9caSSourabh Singh Tomar               Data.getULEB128(&Offset));
20393aee9caSSourabh Singh Tomar       if (!StrOffset)
20492f2d02bSDavid Blaikie         return StrOffset.takeError();
20593aee9caSSourabh Singh Tomar       E.MacroStr =
20693aee9caSSourabh Singh Tomar           MacroContributionOffset->second->getStringExtractor().getCStr(
20793aee9caSSourabh Singh Tomar               &*StrOffset);
208e59cc3e5SAmjad Aboud       break;
20969c8fb1cSSourabh Singh Tomar     }
21069c8fb1cSSourabh Singh Tomar     case DW_MACRO_start_file:
21169c8fb1cSSourabh Singh Tomar       // 2. Source line
21269c8fb1cSSourabh Singh Tomar       E.Line = Data.getULEB128(&Offset);
21369c8fb1cSSourabh Singh Tomar       // 3. Source file id
21469c8fb1cSSourabh Singh Tomar       E.File = Data.getULEB128(&Offset);
21569c8fb1cSSourabh Singh Tomar       break;
21669c8fb1cSSourabh Singh Tomar     case DW_MACRO_end_file:
217e59cc3e5SAmjad Aboud       break;
21885b49ecbSSourabh Singh Tomar     case DW_MACRO_import:
219ccbd7e8dSIgor Kudrin       E.ImportOffset =
220ccbd7e8dSIgor Kudrin           Data.getRelocatedValue(M->Header.getOffsetByteSize(), &Offset);
22185b49ecbSSourabh Singh Tomar       break;
222e59cc3e5SAmjad Aboud     case DW_MACINFO_vendor_ext:
223e59cc3e5SAmjad Aboud       // 2. Vendor extension constant
22469c8fb1cSSourabh Singh Tomar       E.ExtConstant = Data.getULEB128(&Offset);
225e59cc3e5SAmjad Aboud       // 3. Vendor extension string
22669c8fb1cSSourabh Singh Tomar       E.ExtStr = Data.getCStr(&Offset);
227e59cc3e5SAmjad Aboud       break;
228e59cc3e5SAmjad Aboud     }
229e59cc3e5SAmjad Aboud   }
23069c8fb1cSSourabh Singh Tomar   return Error::success();
23169c8fb1cSSourabh Singh Tomar }
23269c8fb1cSSourabh Singh Tomar 
parseMacroHeader(DWARFDataExtractor Data,uint64_t * Offset)23369c8fb1cSSourabh Singh Tomar Error DWARFDebugMacro::MacroHeader::parseMacroHeader(DWARFDataExtractor Data,
23469c8fb1cSSourabh Singh Tomar                                                      uint64_t *Offset) {
23569c8fb1cSSourabh Singh Tomar   Version = Data.getU16(Offset);
23669c8fb1cSSourabh Singh Tomar   uint8_t FlagData = Data.getU8(Offset);
23769c8fb1cSSourabh Singh Tomar 
23869c8fb1cSSourabh Singh Tomar   // FIXME: Add support for parsing opcode_operands_table
23969c8fb1cSSourabh Singh Tomar   if (FlagData & MACRO_OPCODE_OPERANDS_TABLE)
24069c8fb1cSSourabh Singh Tomar     return createStringError(errc::not_supported,
24169c8fb1cSSourabh Singh Tomar                              "opcode_operands_table is not supported");
24269c8fb1cSSourabh Singh Tomar   Flags = FlagData;
24369c8fb1cSSourabh Singh Tomar   if (Flags & MACRO_DEBUG_LINE_OFFSET)
244ccbd7e8dSIgor Kudrin     DebugLineOffset = Data.getUnsigned(Offset, getOffsetByteSize());
24569c8fb1cSSourabh Singh Tomar   return Error::success();
246e59cc3e5SAmjad Aboud }
247