1 //===- DWARFDebugMacro.cpp ------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
10 #include "llvm/ADT/DenseMap.h"
11 #include "llvm/BinaryFormat/Dwarf.h"
12 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
13 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
14 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
15 #include "llvm/Support/Errc.h"
16 #include "llvm/Support/WithColor.h"
17 #include "llvm/Support/raw_ostream.h"
21 using namespace dwarf
;
23 DwarfFormat
DWARFDebugMacro::MacroHeader::getDwarfFormat() const {
24 return Flags
& MACRO_OFFSET_SIZE
? DWARF64
: DWARF32
;
27 uint8_t DWARFDebugMacro::MacroHeader::getOffsetByteSize() const {
28 return getDwarfOffsetByteSize(getDwarfFormat());
31 void DWARFDebugMacro::MacroHeader::dumpMacroHeader(raw_ostream
&OS
) const {
32 // FIXME: Add support for dumping opcode_operands_table
33 OS
<< format("macro header: version = 0x%04" PRIx16
, Version
)
34 << format(", flags = 0x%02" PRIx8
, Flags
)
35 << ", format = " << FormatString(getDwarfFormat());
36 if (Flags
& MACRO_DEBUG_LINE_OFFSET
)
37 OS
<< format(", debug_line_offset = 0x%0*" PRIx64
, 2 * getOffsetByteSize(),
42 void DWARFDebugMacro::dump(raw_ostream
&OS
) const {
43 unsigned IndLevel
= 0;
44 for (const auto &Macros
: MacroLists
) {
45 OS
<< format("0x%08" PRIx64
":\n", Macros
.Offset
);
46 if (Macros
.IsDebugMacro
)
47 Macros
.Header
.dumpMacroHeader(OS
);
48 for (const Entry
&E
: Macros
.Macros
) {
49 // There should not be DW_MACINFO_end_file when IndLevel is Zero. However,
50 // this check handles the case of corrupted ".debug_macinfo" section.
52 IndLevel
-= (E
.Type
== DW_MACINFO_end_file
);
54 for (unsigned I
= 0; I
< IndLevel
; I
++)
56 IndLevel
+= (E
.Type
== DW_MACINFO_start_file
);
57 // Based on which version we are handling choose appropriate macro forms.
58 if (Macros
.IsDebugMacro
)
59 WithColor(OS
, HighlightColor::Macro
).get()
60 << (Macros
.Header
.Version
< 5 ? GnuMacroString(E
.Type
)
61 : MacroString(E
.Type
));
63 WithColor(OS
, HighlightColor::Macro
).get() << MacinfoString(E
.Type
);
66 // Got a corrupted ".debug_macinfo/.debug_macro" section (invalid
69 // debug_macro and debug_macinfo share some common encodings.
70 // DW_MACRO_define == DW_MACINFO_define
71 // DW_MACRO_undef == DW_MACINFO_undef
72 // DW_MACRO_start_file == DW_MACINFO_start_file
73 // DW_MACRO_end_file == DW_MACINFO_end_file
74 // For readability/uniformity we are using DW_MACRO_*.
76 // The GNU .debug_macro extension's entries have the same encoding
77 // as DWARF 5's DW_MACRO_* entries, so we only use the latter here.
80 case DW_MACRO_define_strp
:
81 case DW_MACRO_undef_strp
:
82 case DW_MACRO_define_strx
:
83 case DW_MACRO_undef_strx
:
84 OS
<< " - lineno: " << E
.Line
;
85 OS
<< " macro: " << E
.MacroStr
;
87 case DW_MACRO_start_file
:
88 OS
<< " - lineno: " << E
.Line
;
89 OS
<< " filenum: " << E
.File
;
92 OS
<< format(" - import offset: 0x%0*" PRIx64
,
93 2 * Macros
.Header
.getOffsetByteSize(), E
.ImportOffset
);
95 case DW_MACRO_end_file
:
97 case DW_MACINFO_vendor_ext
:
98 OS
<< " - constant: " << E
.ExtConstant
;
99 OS
<< " string: " << E
.ExtStr
;
107 Error
DWARFDebugMacro::parseImpl(
108 std::optional
<DWARFUnitVector::compile_unit_range
> Units
,
109 std::optional
<DataExtractor
> StringExtractor
, DWARFDataExtractor Data
,
112 MacroList
*M
= nullptr;
113 using MacroToUnitsMap
= DenseMap
<uint64_t, DWARFUnit
*>;
114 MacroToUnitsMap MacroToUnits
;
115 if (IsMacro
&& Data
.isValidOffset(Offset
)) {
116 // Keep a mapping from Macro contribution to CUs, this will
117 // be needed while retrieving macro from DW_MACRO_define_strx form.
118 for (const auto &U
: *Units
)
119 if (auto CUDIE
= U
->getUnitDIE())
120 // Skip units which does not contibutes to macro section.
121 if (auto MacroOffset
= toSectionOffset(CUDIE
.find(DW_AT_macros
)))
122 MacroToUnits
.try_emplace(*MacroOffset
, U
.get());
124 while (Data
.isValidOffset(Offset
)) {
126 MacroLists
.emplace_back();
127 M
= &MacroLists
.back();
129 M
->IsDebugMacro
= IsMacro
;
131 auto Err
= M
->Header
.parseMacroHeader(Data
, &Offset
);
136 // A macro list entry consists of:
137 M
->Macros
.emplace_back();
138 Entry
&E
= M
->Macros
.back();
140 E
.Type
= Data
.getULEB128(&Offset
);
143 // Reached end of a ".debug_macinfo/debug_macro" section contribution.
150 // Got a corrupted ".debug_macinfo" section (invalid macinfo type).
151 // Push the corrupted entry to the list and halt parsing.
152 E
.Type
= DW_MACINFO_invalid
;
153 return Error::success();
154 // debug_macro and debug_macinfo share some common encodings.
155 // DW_MACRO_define == DW_MACINFO_define
156 // DW_MACRO_undef == DW_MACINFO_undef
157 // DW_MACRO_start_file == DW_MACINFO_start_file
158 // DW_MACRO_end_file == DW_MACINFO_end_file
159 // For readibility/uniformity we are using DW_MACRO_*.
160 case DW_MACRO_define
:
163 E
.Line
= Data
.getULEB128(&Offset
);
165 E
.MacroStr
= Data
.getCStr(&Offset
);
167 case DW_MACRO_define_strp
:
168 case DW_MACRO_undef_strp
: {
170 // DW_MACRO_define_strp is a new form introduced in DWARFv5, it is
171 // not supported in debug_macinfo[.dwo] sections. Assume it as an
172 // invalid entry, push it and halt parsing.
173 E
.Type
= DW_MACINFO_invalid
;
174 return Error::success();
176 uint64_t StrOffset
= 0;
178 E
.Line
= Data
.getULEB128(&Offset
);
181 Data
.getRelocatedValue(M
->Header
.getOffsetByteSize(), &Offset
);
182 assert(StringExtractor
&& "String Extractor not found");
183 E
.MacroStr
= StringExtractor
->getCStr(&StrOffset
);
186 case DW_MACRO_define_strx
:
187 case DW_MACRO_undef_strx
: {
189 // DW_MACRO_define_strx is a new form introduced in DWARFv5, it is
190 // not supported in debug_macinfo[.dwo] sections. Assume it as an
191 // invalid entry, push it and halt parsing.
192 E
.Type
= DW_MACINFO_invalid
;
193 return Error::success();
195 E
.Line
= Data
.getULEB128(&Offset
);
196 auto MacroContributionOffset
= MacroToUnits
.find(M
->Offset
);
197 if (MacroContributionOffset
== MacroToUnits
.end())
198 return createStringError(errc::invalid_argument
,
199 "Macro contribution of the unit not found");
200 Expected
<uint64_t> StrOffset
=
201 MacroContributionOffset
->second
->getStringOffsetSectionItem(
202 Data
.getULEB128(&Offset
));
204 return StrOffset
.takeError();
206 MacroContributionOffset
->second
->getStringExtractor().getCStr(
210 case DW_MACRO_start_file
:
212 E
.Line
= Data
.getULEB128(&Offset
);
214 E
.File
= Data
.getULEB128(&Offset
);
216 case DW_MACRO_end_file
:
218 case DW_MACRO_import
:
220 Data
.getRelocatedValue(M
->Header
.getOffsetByteSize(), &Offset
);
222 case DW_MACINFO_vendor_ext
:
223 // 2. Vendor extension constant
224 E
.ExtConstant
= Data
.getULEB128(&Offset
);
225 // 3. Vendor extension string
226 E
.ExtStr
= Data
.getCStr(&Offset
);
230 return Error::success();
233 Error
DWARFDebugMacro::MacroHeader::parseMacroHeader(DWARFDataExtractor Data
,
235 Version
= Data
.getU16(Offset
);
236 uint8_t FlagData
= Data
.getU8(Offset
);
238 // FIXME: Add support for parsing opcode_operands_table
239 if (FlagData
& MACRO_OPCODE_OPERANDS_TABLE
)
240 return createStringError(errc::not_supported
,
241 "opcode_operands_table is not supported");
243 if (Flags
& MACRO_DEBUG_LINE_OFFSET
)
244 DebugLineOffset
= Data
.getUnsigned(Offset
, getOffsetByteSize());
245 return Error::success();