1 //===- DWARFEmitter - Convert YAML to DWARF binary data -------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief The DWARF component of yaml2obj. Provided as library code for tests.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "llvm/ObjectYAML/DWARFEmitter.h"
16 #include "llvm/ObjectYAML/DWARFYAML.h"
17 #include "llvm/Support/Error.h"
18 #include "llvm/Support/LEB128.h"
19 #include "llvm/Support/raw_ostream.h"
20 #include "llvm/Support/SwapByteOrder.h"
21 
22 #include <algorithm>
23 
24 using namespace llvm;
25 
26 template <typename T>
27 void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian) {
28   if (IsLittleEndian != sys::IsLittleEndianHost)
29     sys::swapByteOrder(Integer);
30   OS.write(reinterpret_cast<char *>(&Integer), sizeof(T));
31 }
32 
33 void writeVariableSizedInteger(uint64_t Integer, size_t Size, raw_ostream &OS,
34                                bool IsLittleEndian) {
35   if (8 == Size)
36     writeInteger((uint64_t)Integer, OS, IsLittleEndian);
37   else if (4 == Size)
38     writeInteger((uint32_t)Integer, OS, IsLittleEndian);
39   else if (2 == Size)
40     writeInteger((uint16_t)Integer, OS, IsLittleEndian);
41   else if (1 == Size)
42     writeInteger((uint8_t)Integer, OS, IsLittleEndian);
43   else
44     assert(false && "Invalid integer write size.");
45 }
46 
47 void ZeroFillBytes(raw_ostream &OS, size_t Size) {
48   std::vector<uint8_t> FillData;
49   FillData.insert(FillData.begin(), Size, 0);
50   OS.write(reinterpret_cast<char *>(FillData.data()), Size);
51 }
52 
53 void DWARFYAML::EmitDebugStr(raw_ostream &OS, const DWARFYAML::Data &DI) {
54   for (auto Str : DI.DebugStrings) {
55     OS.write(Str.data(), Str.size());
56     OS.write('\0');
57   }
58 }
59 
60 void DWARFYAML::EmitDebugAbbrev(raw_ostream &OS, const DWARFYAML::Data &DI) {
61   for (auto AbbrevDecl : DI.AbbrevDecls) {
62     encodeULEB128(AbbrevDecl.Code, OS);
63     encodeULEB128(AbbrevDecl.Tag, OS);
64     OS.write(AbbrevDecl.Children);
65     for (auto Attr : AbbrevDecl.Attributes) {
66       encodeULEB128(Attr.Attribute, OS);
67       encodeULEB128(Attr.Form, OS);
68     }
69     encodeULEB128(0, OS);
70     encodeULEB128(0, OS);
71   }
72 }
73 
74 void DWARFYAML::EmitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) {
75   for (auto Range : DI.ARanges) {
76     auto HeaderStart = OS.tell();
77     writeInteger((uint32_t)Range.Length, OS, DI.IsLittleEndian);
78     writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian);
79     writeInteger((uint32_t)Range.CuOffset, OS, DI.IsLittleEndian);
80     writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian);
81     writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian);
82 
83     auto HeaderSize = OS.tell() - HeaderStart;
84     auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2);
85     ZeroFillBytes(OS, FirstDescriptor - HeaderSize);
86 
87     for (auto Descriptor : Range.Descriptors) {
88       writeVariableSizedInteger(Descriptor.Address, Range.AddrSize, OS,
89                                 DI.IsLittleEndian);
90       writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS,
91                                 DI.IsLittleEndian);
92     }
93     ZeroFillBytes(OS, Range.AddrSize * 2);
94   }
95 }
96 
97 void DWARFYAML::EmitPubSection(raw_ostream &OS,
98                                const DWARFYAML::PubSection &Sect,
99                                bool IsLittleEndian) {
100   writeInteger((uint32_t)Sect.Length, OS, IsLittleEndian);
101   writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian);
102   writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian);
103   writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian);
104   for (auto Entry : Sect.Entries) {
105     writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian);
106     if (Sect.IsGNUStyle)
107       writeInteger((uint32_t)Entry.Descriptor, OS, IsLittleEndian);
108     OS.write(Entry.Name.data(), Entry.Name.size());
109     OS.write('\0');
110   }
111 }
112 
113 void DWARFYAML::EmitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) {
114 
115   for (auto CU : DI.CompileUnits) {
116     writeInteger((uint32_t)CU.Length, OS, DI.IsLittleEndian);
117     writeInteger((uint16_t)CU.Version, OS, DI.IsLittleEndian);
118     writeInteger((uint32_t)CU.AbbrOffset, OS, DI.IsLittleEndian);
119     writeInteger((uint8_t)CU.AddrSize, OS, DI.IsLittleEndian);
120 
121     auto FirstAbbrevCode = CU.Entries[0].AbbrCode;
122 
123     for (auto Entry : CU.Entries) {
124       encodeULEB128(Entry.AbbrCode, OS);
125       if (Entry.AbbrCode == 0u)
126         continue;
127       bool Indirect = false;
128       assert(Entry.AbbrCode - FirstAbbrevCode < DI.AbbrevDecls.size() &&
129              "Out of range AbbCode");
130       auto &Abbrev = DI.AbbrevDecls[Entry.AbbrCode - FirstAbbrevCode];
131 
132       auto FormVal = Entry.Values.begin();
133       auto AbbrForm = Abbrev.Attributes.begin();
134       for (;
135            FormVal != Entry.Values.end() && AbbrForm != Abbrev.Attributes.end();
136            ++FormVal, ++AbbrForm) {
137         dwarf::Form Form = AbbrForm->Form;
138         do {
139           Indirect = false;
140           switch (Form) {
141           case dwarf::DW_FORM_addr:
142             writeVariableSizedInteger(FormVal->Value, CU.AddrSize, OS,
143                                       DI.IsLittleEndian);
144             break;
145           case dwarf::DW_FORM_ref_addr: {
146             // TODO: Handle DWARF32/DWARF64 after Line Table data is done
147             auto writeSize = CU.Version == 2 ? CU.AddrSize : 4;
148             writeVariableSizedInteger(FormVal->Value, writeSize, OS,
149                                       DI.IsLittleEndian);
150             break;
151           }
152           case dwarf::DW_FORM_exprloc:
153           case dwarf::DW_FORM_block:
154             encodeULEB128(FormVal->BlockData.size(), OS);
155             OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]),
156                      FormVal->BlockData.size());
157             break;
158           case dwarf::DW_FORM_block1: {
159             auto writeSize = FormVal->BlockData.size();
160             writeInteger((uint8_t)writeSize, OS, DI.IsLittleEndian);
161             OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]),
162                      FormVal->BlockData.size());
163             break;
164           }
165           case dwarf::DW_FORM_block2: {
166             auto writeSize = FormVal->BlockData.size();
167             writeInteger((uint16_t)writeSize, OS, DI.IsLittleEndian);
168             OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]),
169                      FormVal->BlockData.size());
170             break;
171           }
172           case dwarf::DW_FORM_block4: {
173             auto writeSize = FormVal->BlockData.size();
174             writeInteger((uint32_t)writeSize, OS, DI.IsLittleEndian);
175             OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]),
176                      FormVal->BlockData.size());
177             break;
178           }
179           case dwarf::DW_FORM_data1:
180           case dwarf::DW_FORM_ref1:
181           case dwarf::DW_FORM_flag:
182             writeInteger((uint8_t)FormVal->Value, OS, DI.IsLittleEndian);
183             break;
184           case dwarf::DW_FORM_data2:
185           case dwarf::DW_FORM_ref2:
186             writeInteger((uint16_t)FormVal->Value, OS, DI.IsLittleEndian);
187             break;
188           case dwarf::DW_FORM_data4:
189           case dwarf::DW_FORM_ref4:
190             writeInteger((uint32_t)FormVal->Value, OS, DI.IsLittleEndian);
191             break;
192           case dwarf::DW_FORM_data8:
193           case dwarf::DW_FORM_ref8:
194             writeInteger((uint64_t)FormVal->Value, OS, DI.IsLittleEndian);
195             break;
196           case dwarf::DW_FORM_sdata:
197             encodeSLEB128(FormVal->Value, OS);
198             break;
199           case dwarf::DW_FORM_udata:
200           case dwarf::DW_FORM_ref_udata:
201             encodeULEB128(FormVal->Value, OS);
202             break;
203           case dwarf::DW_FORM_string:
204             OS.write(FormVal->CStr.data(), FormVal->CStr.size());
205             OS.write('\0');
206             break;
207           case dwarf::DW_FORM_indirect:
208             encodeULEB128(FormVal->Value, OS);
209             Indirect = true;
210             Form = static_cast<dwarf::Form>((uint64_t)FormVal->Value);
211             ++FormVal;
212             break;
213           case dwarf::DW_FORM_strp:
214           case dwarf::DW_FORM_sec_offset:
215           case dwarf::DW_FORM_GNU_ref_alt:
216           case dwarf::DW_FORM_GNU_strp_alt:
217           case dwarf::DW_FORM_line_strp:
218           case dwarf::DW_FORM_strp_sup:
219           case dwarf::DW_FORM_ref_sup:
220             // TODO: Handle DWARF32/64
221             writeInteger((uint32_t)FormVal->Value, OS, DI.IsLittleEndian);
222             break;
223           case dwarf::DW_FORM_ref_sig8:
224             writeInteger((uint64_t)FormVal->Value, OS, DI.IsLittleEndian);
225             break;
226           case dwarf::DW_FORM_GNU_addr_index:
227           case dwarf::DW_FORM_GNU_str_index:
228             encodeULEB128(FormVal->Value, OS);
229             break;
230           default:
231             break;
232           }
233         } while (Indirect);
234       }
235     }
236   }
237 }
238 
239 void EmitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) {
240   OS.write(File.Name.data(), File.Name.size());
241   OS.write('\0');
242   encodeULEB128(File.DirIdx, OS);
243   encodeULEB128(File.ModTime, OS);
244   encodeULEB128(File.Length, OS);
245 }
246 
247 void DWARFYAML::EmitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) {
248   for (const auto LineTable : DI.DebugLines) {
249     writeInteger((uint32_t)LineTable.TotalLength, OS, DI.IsLittleEndian);
250     uint64_t SizeOfPrologueLength = 4;
251     if (LineTable.TotalLength == UINT32_MAX) {
252       writeInteger((uint64_t)LineTable.TotalLength64, OS, DI.IsLittleEndian);
253       SizeOfPrologueLength = 8;
254     }
255     writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian);
256     writeVariableSizedInteger(LineTable.PrologueLength, SizeOfPrologueLength,
257                               OS, DI.IsLittleEndian);
258     writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian);
259     if (LineTable.Version >= 4)
260       writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian);
261     writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian);
262     writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian);
263     writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian);
264     writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian);
265 
266     for (auto OpcodeLength : LineTable.StandardOpcodeLengths)
267       writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian);
268 
269     for (auto IncludeDir : LineTable.IncludeDirs) {
270       OS.write(IncludeDir.data(), IncludeDir.size());
271       OS.write('\0');
272     }
273     OS.write('\0');
274 
275     for (auto File : LineTable.Files)
276       EmitFileEntry(OS, File);
277     OS.write('\0');
278 
279     for (auto Op : LineTable.Opcodes) {
280       writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian);
281       if (Op.Opcode == 0) {
282         encodeULEB128(Op.ExtLen, OS);
283         writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian);
284         switch (Op.SubOpcode) {
285         case dwarf::DW_LNE_set_address:
286         case dwarf::DW_LNE_set_discriminator:
287           writeVariableSizedInteger(Op.Data, DI.CompileUnits[0].AddrSize, OS,
288                                     DI.IsLittleEndian);
289           break;
290         case dwarf::DW_LNE_define_file:
291           EmitFileEntry(OS, Op.FileEntry);
292           break;
293         case dwarf::DW_LNE_end_sequence:
294           break;
295         default:
296           for (auto OpByte : Op.UnknownOpcodeData)
297             writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian);
298         }
299       } else if (Op.Opcode < LineTable.OpcodeBase) {
300         switch (Op.Opcode) {
301         case dwarf::DW_LNS_copy:
302         case dwarf::DW_LNS_negate_stmt:
303         case dwarf::DW_LNS_set_basic_block:
304         case dwarf::DW_LNS_const_add_pc:
305         case dwarf::DW_LNS_set_prologue_end:
306         case dwarf::DW_LNS_set_epilogue_begin:
307           break;
308 
309         case dwarf::DW_LNS_advance_pc:
310         case dwarf::DW_LNS_set_file:
311         case dwarf::DW_LNS_set_column:
312         case dwarf::DW_LNS_set_isa:
313           encodeULEB128(Op.Data, OS);
314           break;
315 
316         case dwarf::DW_LNS_advance_line:
317           encodeSLEB128(Op.SData, OS);
318           break;
319 
320         case dwarf::DW_LNS_fixed_advance_pc:
321           writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian);
322           break;
323 
324         default:
325           for (auto OpData : Op.StandardOpcodeData) {
326             encodeULEB128(OpData, OS);
327           }
328         }
329       }
330     }
331   }
332 }
333 
334 typedef void (*EmitFuncType)(raw_ostream &, const DWARFYAML::Data &);
335 
336 void EmitDebugSectionImpl(
337     const DWARFYAML::Data &DI, EmitFuncType EmitFunc, StringRef Sec,
338     StringMap<std::unique_ptr<MemoryBuffer>> &OutputBuffers) {
339   std::string Data;
340   raw_string_ostream DebugInfoStream(Data);
341   EmitFunc(DebugInfoStream, DI);
342   DebugInfoStream.flush();
343   if (!Data.empty())
344     OutputBuffers[Sec] = MemoryBuffer::getMemBufferCopy(Data);
345 }
346 
347 Expected<StringMap<std::unique_ptr<MemoryBuffer>>>
348 DWARFYAML::EmitDebugSections(StringRef YAMLString,
349                              bool IsLittleEndian) {
350   StringMap<std::unique_ptr<MemoryBuffer>> DebugSections;
351 
352   yaml::Input YIn(YAMLString);
353 
354   DWARFYAML::Data DI;
355   DI.IsLittleEndian = IsLittleEndian;
356   YIn >> DI;
357   if (YIn.error())
358     return errorCodeToError(YIn.error());
359 
360   EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugInfo, "debug_info",
361                        DebugSections);
362   EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugLine, "debug_line",
363                        DebugSections);
364   EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugStr, "debug_str",
365                        DebugSections);
366   EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAbbrev, "debug_abbrev",
367                        DebugSections);
368   EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAranges, "debug_aranges",
369                        DebugSections);
370   return std::move(DebugSections);
371 }
372