1 //===- DWARFEmitter - Convert YAML to DWARF binary data -------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief The DWARF component of yaml2obj. Provided as library code for tests.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/ObjectYAML/DWARFEmitter.h"
16 #include "DWARFVisitor.h"
17 #include "llvm/ADT/StringMap.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ObjectYAML/DWARFYAML.h"
20 #include "llvm/Support/Error.h"
21 #include "llvm/Support/Host.h"
22 #include "llvm/Support/LEB128.h"
23 #include "llvm/Support/MathExtras.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 #include "llvm/Support/SwapByteOrder.h"
26 #include "llvm/Support/YAMLTraits.h"
27 #include "llvm/Support/raw_ostream.h"
39 static void writeInteger(T Integer
, raw_ostream
&OS
, bool IsLittleEndian
) {
40 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
41 sys::swapByteOrder(Integer
);
42 OS
.write(reinterpret_cast<char *>(&Integer
), sizeof(T
));
45 static void writeVariableSizedInteger(uint64_t Integer
, size_t Size
,
46 raw_ostream
&OS
, bool IsLittleEndian
) {
48 writeInteger((uint64_t)Integer
, OS
, IsLittleEndian
);
50 writeInteger((uint32_t)Integer
, OS
, IsLittleEndian
);
52 writeInteger((uint16_t)Integer
, OS
, IsLittleEndian
);
54 writeInteger((uint8_t)Integer
, OS
, IsLittleEndian
);
56 assert(false && "Invalid integer write size.");
59 static void ZeroFillBytes(raw_ostream
&OS
, size_t Size
) {
60 std::vector
<uint8_t> FillData
;
61 FillData
.insert(FillData
.begin(), Size
, 0);
62 OS
.write(reinterpret_cast<char *>(FillData
.data()), Size
);
65 static void writeInitialLength(const DWARFYAML::InitialLength
&Length
,
66 raw_ostream
&OS
, bool IsLittleEndian
) {
67 writeInteger((uint32_t)Length
.TotalLength
, OS
, IsLittleEndian
);
68 if (Length
.isDWARF64())
69 writeInteger((uint64_t)Length
.TotalLength64
, OS
, IsLittleEndian
);
72 void DWARFYAML::EmitDebugStr(raw_ostream
&OS
, const DWARFYAML::Data
&DI
) {
73 for (auto Str
: DI
.DebugStrings
) {
74 OS
.write(Str
.data(), Str
.size());
79 void DWARFYAML::EmitDebugAbbrev(raw_ostream
&OS
, const DWARFYAML::Data
&DI
) {
80 for (auto AbbrevDecl
: DI
.AbbrevDecls
) {
81 encodeULEB128(AbbrevDecl
.Code
, OS
);
82 encodeULEB128(AbbrevDecl
.Tag
, OS
);
83 OS
.write(AbbrevDecl
.Children
);
84 for (auto Attr
: AbbrevDecl
.Attributes
) {
85 encodeULEB128(Attr
.Attribute
, OS
);
86 encodeULEB128(Attr
.Form
, OS
);
87 if (Attr
.Form
== dwarf::DW_FORM_implicit_const
)
88 encodeSLEB128(Attr
.Value
, OS
);
95 void DWARFYAML::EmitDebugAranges(raw_ostream
&OS
, const DWARFYAML::Data
&DI
) {
96 for (auto Range
: DI
.ARanges
) {
97 auto HeaderStart
= OS
.tell();
98 writeInitialLength(Range
.Length
, OS
, DI
.IsLittleEndian
);
99 writeInteger((uint16_t)Range
.Version
, OS
, DI
.IsLittleEndian
);
100 writeInteger((uint32_t)Range
.CuOffset
, OS
, DI
.IsLittleEndian
);
101 writeInteger((uint8_t)Range
.AddrSize
, OS
, DI
.IsLittleEndian
);
102 writeInteger((uint8_t)Range
.SegSize
, OS
, DI
.IsLittleEndian
);
104 auto HeaderSize
= OS
.tell() - HeaderStart
;
105 auto FirstDescriptor
= alignTo(HeaderSize
, Range
.AddrSize
* 2);
106 ZeroFillBytes(OS
, FirstDescriptor
- HeaderSize
);
108 for (auto Descriptor
: Range
.Descriptors
) {
109 writeVariableSizedInteger(Descriptor
.Address
, Range
.AddrSize
, OS
,
111 writeVariableSizedInteger(Descriptor
.Length
, Range
.AddrSize
, OS
,
114 ZeroFillBytes(OS
, Range
.AddrSize
* 2);
118 void DWARFYAML::EmitPubSection(raw_ostream
&OS
,
119 const DWARFYAML::PubSection
&Sect
,
120 bool IsLittleEndian
) {
121 writeInitialLength(Sect
.Length
, OS
, IsLittleEndian
);
122 writeInteger((uint16_t)Sect
.Version
, OS
, IsLittleEndian
);
123 writeInteger((uint32_t)Sect
.UnitOffset
, OS
, IsLittleEndian
);
124 writeInteger((uint32_t)Sect
.UnitSize
, OS
, IsLittleEndian
);
125 for (auto Entry
: Sect
.Entries
) {
126 writeInteger((uint32_t)Entry
.DieOffset
, OS
, IsLittleEndian
);
128 writeInteger((uint32_t)Entry
.Descriptor
, OS
, IsLittleEndian
);
129 OS
.write(Entry
.Name
.data(), Entry
.Name
.size());
135 /// \brief An extension of the DWARFYAML::ConstVisitor which writes compile
136 /// units and DIEs to a stream.
137 class DumpVisitor
: public DWARFYAML::ConstVisitor
{
141 void onStartCompileUnit(const DWARFYAML::Unit
&CU
) override
{
142 writeInitialLength(CU
.Length
, OS
, DebugInfo
.IsLittleEndian
);
143 writeInteger((uint16_t)CU
.Version
, OS
, DebugInfo
.IsLittleEndian
);
144 if(CU
.Version
>= 5) {
145 writeInteger((uint8_t)CU
.Type
, OS
, DebugInfo
.IsLittleEndian
);
146 writeInteger((uint8_t)CU
.AddrSize
, OS
, DebugInfo
.IsLittleEndian
);
147 writeInteger((uint32_t)CU
.AbbrOffset
, OS
, DebugInfo
.IsLittleEndian
);
149 writeInteger((uint32_t)CU
.AbbrOffset
, OS
, DebugInfo
.IsLittleEndian
);
150 writeInteger((uint8_t)CU
.AddrSize
, OS
, DebugInfo
.IsLittleEndian
);
155 void onStartDIE(const DWARFYAML::Unit
&CU
,
156 const DWARFYAML::Entry
&DIE
) override
{
157 encodeULEB128(DIE
.AbbrCode
, OS
);
160 void onValue(const uint8_t U
) override
{
161 writeInteger(U
, OS
, DebugInfo
.IsLittleEndian
);
164 void onValue(const uint16_t U
) override
{
165 writeInteger(U
, OS
, DebugInfo
.IsLittleEndian
);
168 void onValue(const uint32_t U
) override
{
169 writeInteger(U
, OS
, DebugInfo
.IsLittleEndian
);
172 void onValue(const uint64_t U
, const bool LEB
= false) override
{
174 encodeULEB128(U
, OS
);
176 writeInteger(U
, OS
, DebugInfo
.IsLittleEndian
);
179 void onValue(const int64_t S
, const bool LEB
= false) override
{
181 encodeSLEB128(S
, OS
);
183 writeInteger(S
, OS
, DebugInfo
.IsLittleEndian
);
186 void onValue(const StringRef String
) override
{
187 OS
.write(String
.data(), String
.size());
191 void onValue(const MemoryBufferRef MBR
) override
{
192 OS
.write(MBR
.getBufferStart(), MBR
.getBufferSize());
196 DumpVisitor(const DWARFYAML::Data
&DI
, raw_ostream
&Out
)
197 : DWARFYAML::ConstVisitor(DI
), OS(Out
) {}
201 void DWARFYAML::EmitDebugInfo(raw_ostream
&OS
, const DWARFYAML::Data
&DI
) {
202 DumpVisitor
Visitor(DI
, OS
);
203 Visitor
.traverseDebugInfo();
206 static void EmitFileEntry(raw_ostream
&OS
, const DWARFYAML::File
&File
) {
207 OS
.write(File
.Name
.data(), File
.Name
.size());
209 encodeULEB128(File
.DirIdx
, OS
);
210 encodeULEB128(File
.ModTime
, OS
);
211 encodeULEB128(File
.Length
, OS
);
214 void DWARFYAML::EmitDebugLine(raw_ostream
&OS
, const DWARFYAML::Data
&DI
) {
215 for (const auto &LineTable
: DI
.DebugLines
) {
216 writeInitialLength(LineTable
.Length
, OS
, DI
.IsLittleEndian
);
217 uint64_t SizeOfPrologueLength
= LineTable
.Length
.isDWARF64() ? 8 : 4;
218 writeInteger((uint16_t)LineTable
.Version
, OS
, DI
.IsLittleEndian
);
219 writeVariableSizedInteger(LineTable
.PrologueLength
, SizeOfPrologueLength
,
220 OS
, DI
.IsLittleEndian
);
221 writeInteger((uint8_t)LineTable
.MinInstLength
, OS
, DI
.IsLittleEndian
);
222 if (LineTable
.Version
>= 4)
223 writeInteger((uint8_t)LineTable
.MaxOpsPerInst
, OS
, DI
.IsLittleEndian
);
224 writeInteger((uint8_t)LineTable
.DefaultIsStmt
, OS
, DI
.IsLittleEndian
);
225 writeInteger((uint8_t)LineTable
.LineBase
, OS
, DI
.IsLittleEndian
);
226 writeInteger((uint8_t)LineTable
.LineRange
, OS
, DI
.IsLittleEndian
);
227 writeInteger((uint8_t)LineTable
.OpcodeBase
, OS
, DI
.IsLittleEndian
);
229 for (auto OpcodeLength
: LineTable
.StandardOpcodeLengths
)
230 writeInteger((uint8_t)OpcodeLength
, OS
, DI
.IsLittleEndian
);
232 for (auto IncludeDir
: LineTable
.IncludeDirs
) {
233 OS
.write(IncludeDir
.data(), IncludeDir
.size());
238 for (auto File
: LineTable
.Files
)
239 EmitFileEntry(OS
, File
);
242 for (auto Op
: LineTable
.Opcodes
) {
243 writeInteger((uint8_t)Op
.Opcode
, OS
, DI
.IsLittleEndian
);
244 if (Op
.Opcode
== 0) {
245 encodeULEB128(Op
.ExtLen
, OS
);
246 writeInteger((uint8_t)Op
.SubOpcode
, OS
, DI
.IsLittleEndian
);
247 switch (Op
.SubOpcode
) {
248 case dwarf::DW_LNE_set_address
:
249 case dwarf::DW_LNE_set_discriminator
:
250 writeVariableSizedInteger(Op
.Data
, DI
.CompileUnits
[0].AddrSize
, OS
,
253 case dwarf::DW_LNE_define_file
:
254 EmitFileEntry(OS
, Op
.FileEntry
);
256 case dwarf::DW_LNE_end_sequence
:
259 for (auto OpByte
: Op
.UnknownOpcodeData
)
260 writeInteger((uint8_t)OpByte
, OS
, DI
.IsLittleEndian
);
262 } else if (Op
.Opcode
< LineTable
.OpcodeBase
) {
264 case dwarf::DW_LNS_copy
:
265 case dwarf::DW_LNS_negate_stmt
:
266 case dwarf::DW_LNS_set_basic_block
:
267 case dwarf::DW_LNS_const_add_pc
:
268 case dwarf::DW_LNS_set_prologue_end
:
269 case dwarf::DW_LNS_set_epilogue_begin
:
272 case dwarf::DW_LNS_advance_pc
:
273 case dwarf::DW_LNS_set_file
:
274 case dwarf::DW_LNS_set_column
:
275 case dwarf::DW_LNS_set_isa
:
276 encodeULEB128(Op
.Data
, OS
);
279 case dwarf::DW_LNS_advance_line
:
280 encodeSLEB128(Op
.SData
, OS
);
283 case dwarf::DW_LNS_fixed_advance_pc
:
284 writeInteger((uint16_t)Op
.Data
, OS
, DI
.IsLittleEndian
);
288 for (auto OpData
: Op
.StandardOpcodeData
) {
289 encodeULEB128(OpData
, OS
);
297 using EmitFuncType
= void (*)(raw_ostream
&, const DWARFYAML::Data
&);
300 EmitDebugSectionImpl(const DWARFYAML::Data
&DI
, EmitFuncType EmitFunc
,
302 StringMap
<std::unique_ptr
<MemoryBuffer
>> &OutputBuffers
) {
304 raw_string_ostream
DebugInfoStream(Data
);
305 EmitFunc(DebugInfoStream
, DI
);
306 DebugInfoStream
.flush();
308 OutputBuffers
[Sec
] = MemoryBuffer::getMemBufferCopy(Data
);
311 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>>
312 DWARFYAML::EmitDebugSections(StringRef YAMLString
,
313 bool IsLittleEndian
) {
314 StringMap
<std::unique_ptr
<MemoryBuffer
>> DebugSections
;
316 yaml::Input
YIn(YAMLString
);
319 DI
.IsLittleEndian
= IsLittleEndian
;
322 return errorCodeToError(YIn
.error());
324 EmitDebugSectionImpl(DI
, &DWARFYAML::EmitDebugInfo
, "debug_info",
326 EmitDebugSectionImpl(DI
, &DWARFYAML::EmitDebugLine
, "debug_line",
328 EmitDebugSectionImpl(DI
, &DWARFYAML::EmitDebugStr
, "debug_str",
330 EmitDebugSectionImpl(DI
, &DWARFYAML::EmitDebugAbbrev
, "debug_abbrev",
332 EmitDebugSectionImpl(DI
, &DWARFYAML::EmitDebugAranges
, "debug_aranges",
334 return std::move(DebugSections
);