1 //===- DWARFEmitter - Convert YAML to DWARF binary data -------------------===//
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 //===----------------------------------------------------------------------===//
10 /// The DWARF component of yaml2obj. Provided as library code for tests.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ObjectYAML/DWARFEmitter.h"
15 #include "DWARFVisitor.h"
16 #include "llvm/ADT/StringMap.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ObjectYAML/DWARFYAML.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/Host.h"
21 #include "llvm/Support/LEB128.h"
22 #include "llvm/Support/MathExtras.h"
23 #include "llvm/Support/MemoryBuffer.h"
24 #include "llvm/Support/SwapByteOrder.h"
25 #include "llvm/Support/YAMLTraits.h"
26 #include "llvm/Support/raw_ostream.h"
38 static void writeInteger(T Integer
, raw_ostream
&OS
, bool IsLittleEndian
) {
39 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
40 sys::swapByteOrder(Integer
);
41 OS
.write(reinterpret_cast<char *>(&Integer
), sizeof(T
));
44 static void writeVariableSizedInteger(uint64_t Integer
, size_t Size
,
45 raw_ostream
&OS
, bool IsLittleEndian
) {
47 writeInteger((uint64_t)Integer
, OS
, IsLittleEndian
);
49 writeInteger((uint32_t)Integer
, OS
, IsLittleEndian
);
51 writeInteger((uint16_t)Integer
, OS
, IsLittleEndian
);
53 writeInteger((uint8_t)Integer
, OS
, IsLittleEndian
);
55 assert(false && "Invalid integer write size.");
58 static void ZeroFillBytes(raw_ostream
&OS
, size_t Size
) {
59 std::vector
<uint8_t> FillData
;
60 FillData
.insert(FillData
.begin(), Size
, 0);
61 OS
.write(reinterpret_cast<char *>(FillData
.data()), Size
);
64 static void writeInitialLength(const DWARFYAML::InitialLength
&Length
,
65 raw_ostream
&OS
, bool IsLittleEndian
) {
66 writeInteger((uint32_t)Length
.TotalLength
, OS
, IsLittleEndian
);
67 if (Length
.isDWARF64())
68 writeInteger((uint64_t)Length
.TotalLength64
, OS
, IsLittleEndian
);
71 void DWARFYAML::EmitDebugStr(raw_ostream
&OS
, const DWARFYAML::Data
&DI
) {
72 for (auto Str
: DI
.DebugStrings
) {
73 OS
.write(Str
.data(), Str
.size());
78 void DWARFYAML::EmitDebugAbbrev(raw_ostream
&OS
, const DWARFYAML::Data
&DI
) {
79 for (auto AbbrevDecl
: DI
.AbbrevDecls
) {
80 encodeULEB128(AbbrevDecl
.Code
, OS
);
81 encodeULEB128(AbbrevDecl
.Tag
, OS
);
82 OS
.write(AbbrevDecl
.Children
);
83 for (auto Attr
: AbbrevDecl
.Attributes
) {
84 encodeULEB128(Attr
.Attribute
, OS
);
85 encodeULEB128(Attr
.Form
, OS
);
86 if (Attr
.Form
== dwarf::DW_FORM_implicit_const
)
87 encodeSLEB128(Attr
.Value
, OS
);
94 void DWARFYAML::EmitDebugAranges(raw_ostream
&OS
, const DWARFYAML::Data
&DI
) {
95 for (auto Range
: DI
.ARanges
) {
96 auto HeaderStart
= OS
.tell();
97 writeInitialLength(Range
.Length
, OS
, DI
.IsLittleEndian
);
98 writeInteger((uint16_t)Range
.Version
, OS
, DI
.IsLittleEndian
);
99 writeInteger((uint32_t)Range
.CuOffset
, OS
, DI
.IsLittleEndian
);
100 writeInteger((uint8_t)Range
.AddrSize
, OS
, DI
.IsLittleEndian
);
101 writeInteger((uint8_t)Range
.SegSize
, OS
, DI
.IsLittleEndian
);
103 auto HeaderSize
= OS
.tell() - HeaderStart
;
104 auto FirstDescriptor
= alignTo(HeaderSize
, Range
.AddrSize
* 2);
105 ZeroFillBytes(OS
, FirstDescriptor
- HeaderSize
);
107 for (auto Descriptor
: Range
.Descriptors
) {
108 writeVariableSizedInteger(Descriptor
.Address
, Range
.AddrSize
, OS
,
110 writeVariableSizedInteger(Descriptor
.Length
, Range
.AddrSize
, OS
,
113 ZeroFillBytes(OS
, Range
.AddrSize
* 2);
117 void DWARFYAML::EmitPubSection(raw_ostream
&OS
,
118 const DWARFYAML::PubSection
&Sect
,
119 bool IsLittleEndian
) {
120 writeInitialLength(Sect
.Length
, OS
, IsLittleEndian
);
121 writeInteger((uint16_t)Sect
.Version
, OS
, IsLittleEndian
);
122 writeInteger((uint32_t)Sect
.UnitOffset
, OS
, IsLittleEndian
);
123 writeInteger((uint32_t)Sect
.UnitSize
, OS
, IsLittleEndian
);
124 for (auto Entry
: Sect
.Entries
) {
125 writeInteger((uint32_t)Entry
.DieOffset
, OS
, IsLittleEndian
);
127 writeInteger((uint32_t)Entry
.Descriptor
, OS
, IsLittleEndian
);
128 OS
.write(Entry
.Name
.data(), Entry
.Name
.size());
134 /// An extension of the DWARFYAML::ConstVisitor which writes compile
135 /// units and DIEs to a stream.
136 class DumpVisitor
: public DWARFYAML::ConstVisitor
{
140 void onStartCompileUnit(const DWARFYAML::Unit
&CU
) override
{
141 writeInitialLength(CU
.Length
, OS
, DebugInfo
.IsLittleEndian
);
142 writeInteger((uint16_t)CU
.Version
, OS
, DebugInfo
.IsLittleEndian
);
143 if(CU
.Version
>= 5) {
144 writeInteger((uint8_t)CU
.Type
, OS
, DebugInfo
.IsLittleEndian
);
145 writeInteger((uint8_t)CU
.AddrSize
, OS
, DebugInfo
.IsLittleEndian
);
146 writeInteger((uint32_t)CU
.AbbrOffset
, OS
, DebugInfo
.IsLittleEndian
);
148 writeInteger((uint32_t)CU
.AbbrOffset
, OS
, DebugInfo
.IsLittleEndian
);
149 writeInteger((uint8_t)CU
.AddrSize
, OS
, DebugInfo
.IsLittleEndian
);
153 void onStartDIE(const DWARFYAML::Unit
&CU
,
154 const DWARFYAML::Entry
&DIE
) override
{
155 encodeULEB128(DIE
.AbbrCode
, OS
);
158 void onValue(const uint8_t U
) override
{
159 writeInteger(U
, OS
, DebugInfo
.IsLittleEndian
);
162 void onValue(const uint16_t U
) override
{
163 writeInteger(U
, OS
, DebugInfo
.IsLittleEndian
);
166 void onValue(const uint32_t U
) override
{
167 writeInteger(U
, OS
, DebugInfo
.IsLittleEndian
);
170 void onValue(const uint64_t U
, const bool LEB
= false) override
{
172 encodeULEB128(U
, OS
);
174 writeInteger(U
, OS
, DebugInfo
.IsLittleEndian
);
177 void onValue(const int64_t S
, const bool LEB
= false) override
{
179 encodeSLEB128(S
, OS
);
181 writeInteger(S
, OS
, DebugInfo
.IsLittleEndian
);
184 void onValue(const StringRef String
) override
{
185 OS
.write(String
.data(), String
.size());
189 void onValue(const MemoryBufferRef MBR
) override
{
190 OS
.write(MBR
.getBufferStart(), MBR
.getBufferSize());
194 DumpVisitor(const DWARFYAML::Data
&DI
, raw_ostream
&Out
)
195 : DWARFYAML::ConstVisitor(DI
), OS(Out
) {}
199 void DWARFYAML::EmitDebugInfo(raw_ostream
&OS
, const DWARFYAML::Data
&DI
) {
200 DumpVisitor
Visitor(DI
, OS
);
201 Visitor
.traverseDebugInfo();
204 static void EmitFileEntry(raw_ostream
&OS
, const DWARFYAML::File
&File
) {
205 OS
.write(File
.Name
.data(), File
.Name
.size());
207 encodeULEB128(File
.DirIdx
, OS
);
208 encodeULEB128(File
.ModTime
, OS
);
209 encodeULEB128(File
.Length
, OS
);
212 void DWARFYAML::EmitDebugLine(raw_ostream
&OS
, const DWARFYAML::Data
&DI
) {
213 for (const auto &LineTable
: DI
.DebugLines
) {
214 writeInitialLength(LineTable
.Length
, OS
, DI
.IsLittleEndian
);
215 uint64_t SizeOfPrologueLength
= LineTable
.Length
.isDWARF64() ? 8 : 4;
216 writeInteger((uint16_t)LineTable
.Version
, OS
, DI
.IsLittleEndian
);
217 writeVariableSizedInteger(LineTable
.PrologueLength
, SizeOfPrologueLength
,
218 OS
, DI
.IsLittleEndian
);
219 writeInteger((uint8_t)LineTable
.MinInstLength
, OS
, DI
.IsLittleEndian
);
220 if (LineTable
.Version
>= 4)
221 writeInteger((uint8_t)LineTable
.MaxOpsPerInst
, OS
, DI
.IsLittleEndian
);
222 writeInteger((uint8_t)LineTable
.DefaultIsStmt
, OS
, DI
.IsLittleEndian
);
223 writeInteger((uint8_t)LineTable
.LineBase
, OS
, DI
.IsLittleEndian
);
224 writeInteger((uint8_t)LineTable
.LineRange
, OS
, DI
.IsLittleEndian
);
225 writeInteger((uint8_t)LineTable
.OpcodeBase
, OS
, DI
.IsLittleEndian
);
227 for (auto OpcodeLength
: LineTable
.StandardOpcodeLengths
)
228 writeInteger((uint8_t)OpcodeLength
, OS
, DI
.IsLittleEndian
);
230 for (auto IncludeDir
: LineTable
.IncludeDirs
) {
231 OS
.write(IncludeDir
.data(), IncludeDir
.size());
236 for (auto File
: LineTable
.Files
)
237 EmitFileEntry(OS
, File
);
240 for (auto Op
: LineTable
.Opcodes
) {
241 writeInteger((uint8_t)Op
.Opcode
, OS
, DI
.IsLittleEndian
);
242 if (Op
.Opcode
== 0) {
243 encodeULEB128(Op
.ExtLen
, OS
);
244 writeInteger((uint8_t)Op
.SubOpcode
, OS
, DI
.IsLittleEndian
);
245 switch (Op
.SubOpcode
) {
246 case dwarf::DW_LNE_set_address
:
247 case dwarf::DW_LNE_set_discriminator
:
248 writeVariableSizedInteger(Op
.Data
, DI
.CompileUnits
[0].AddrSize
, OS
,
251 case dwarf::DW_LNE_define_file
:
252 EmitFileEntry(OS
, Op
.FileEntry
);
254 case dwarf::DW_LNE_end_sequence
:
257 for (auto OpByte
: Op
.UnknownOpcodeData
)
258 writeInteger((uint8_t)OpByte
, OS
, DI
.IsLittleEndian
);
260 } else if (Op
.Opcode
< LineTable
.OpcodeBase
) {
262 case dwarf::DW_LNS_copy
:
263 case dwarf::DW_LNS_negate_stmt
:
264 case dwarf::DW_LNS_set_basic_block
:
265 case dwarf::DW_LNS_const_add_pc
:
266 case dwarf::DW_LNS_set_prologue_end
:
267 case dwarf::DW_LNS_set_epilogue_begin
:
270 case dwarf::DW_LNS_advance_pc
:
271 case dwarf::DW_LNS_set_file
:
272 case dwarf::DW_LNS_set_column
:
273 case dwarf::DW_LNS_set_isa
:
274 encodeULEB128(Op
.Data
, OS
);
277 case dwarf::DW_LNS_advance_line
:
278 encodeSLEB128(Op
.SData
, OS
);
281 case dwarf::DW_LNS_fixed_advance_pc
:
282 writeInteger((uint16_t)Op
.Data
, OS
, DI
.IsLittleEndian
);
286 for (auto OpData
: Op
.StandardOpcodeData
) {
287 encodeULEB128(OpData
, OS
);
295 using EmitFuncType
= void (*)(raw_ostream
&, const DWARFYAML::Data
&);
298 EmitDebugSectionImpl(const DWARFYAML::Data
&DI
, EmitFuncType EmitFunc
,
300 StringMap
<std::unique_ptr
<MemoryBuffer
>> &OutputBuffers
) {
302 raw_string_ostream
DebugInfoStream(Data
);
303 EmitFunc(DebugInfoStream
, DI
);
304 DebugInfoStream
.flush();
306 OutputBuffers
[Sec
] = MemoryBuffer::getMemBufferCopy(Data
);
310 class DIEFixupVisitor
: public DWARFYAML::Visitor
{
314 DIEFixupVisitor(DWARFYAML::Data
&DI
) : DWARFYAML::Visitor(DI
){};
317 virtual void onStartCompileUnit(DWARFYAML::Unit
&CU
) { Length
= 7; }
319 virtual void onEndCompileUnit(DWARFYAML::Unit
&CU
) {
320 CU
.Length
.setLength(Length
);
323 virtual void onStartDIE(DWARFYAML::Unit
&CU
, DWARFYAML::Entry
&DIE
) {
324 Length
+= getULEB128Size(DIE
.AbbrCode
);
327 virtual void onValue(const uint8_t U
) { Length
+= 1; }
328 virtual void onValue(const uint16_t U
) { Length
+= 2; }
329 virtual void onValue(const uint32_t U
) { Length
+= 4; }
330 virtual void onValue(const uint64_t U
, const bool LEB
= false) {
332 Length
+= getULEB128Size(U
);
336 virtual void onValue(const int64_t S
, const bool LEB
= false) {
338 Length
+= getSLEB128Size(S
);
342 virtual void onValue(const StringRef String
) { Length
+= String
.size() + 1; }
344 virtual void onValue(const MemoryBufferRef MBR
) {
345 Length
+= MBR
.getBufferSize();
350 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>>
351 DWARFYAML::EmitDebugSections(StringRef YAMLString
, bool ApplyFixups
,
352 bool IsLittleEndian
) {
353 yaml::Input
YIn(YAMLString
);
356 DI
.IsLittleEndian
= IsLittleEndian
;
359 return errorCodeToError(YIn
.error());
362 DIEFixupVisitor
DIFixer(DI
);
363 DIFixer
.traverseDebugInfo();
366 StringMap
<std::unique_ptr
<MemoryBuffer
>> DebugSections
;
367 EmitDebugSectionImpl(DI
, &DWARFYAML::EmitDebugInfo
, "debug_info",
369 EmitDebugSectionImpl(DI
, &DWARFYAML::EmitDebugLine
, "debug_line",
371 EmitDebugSectionImpl(DI
, &DWARFYAML::EmitDebugStr
, "debug_str",
373 EmitDebugSectionImpl(DI
, &DWARFYAML::EmitDebugAbbrev
, "debug_abbrev",
375 EmitDebugSectionImpl(DI
, &DWARFYAML::EmitDebugAranges
, "debug_aranges",
377 return std::move(DebugSections
);