DWARFEmitter.cpp revision 360784
1//===- DWARFEmitter - Convert YAML to DWARF binary data -------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// The DWARF component of yaml2obj. Provided as library code for tests.
11///
12//===----------------------------------------------------------------------===//
13
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"
27#include <algorithm>
28#include <cassert>
29#include <cstddef>
30#include <cstdint>
31#include <memory>
32#include <string>
33#include <vector>
34
35using namespace llvm;
36
37template <typename T>
38static 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));
42}
43
44static void writeVariableSizedInteger(uint64_t Integer, size_t Size,
45                                      raw_ostream &OS, bool IsLittleEndian) {
46  if (8 == Size)
47    writeInteger((uint64_t)Integer, OS, IsLittleEndian);
48  else if (4 == Size)
49    writeInteger((uint32_t)Integer, OS, IsLittleEndian);
50  else if (2 == Size)
51    writeInteger((uint16_t)Integer, OS, IsLittleEndian);
52  else if (1 == Size)
53    writeInteger((uint8_t)Integer, OS, IsLittleEndian);
54  else
55    assert(false && "Invalid integer write size.");
56}
57
58static 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);
62}
63
64static 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);
69}
70
71void DWARFYAML::EmitDebugStr(raw_ostream &OS, const DWARFYAML::Data &DI) {
72  for (auto Str : DI.DebugStrings) {
73    OS.write(Str.data(), Str.size());
74    OS.write('\0');
75  }
76}
77
78void 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);
88    }
89    encodeULEB128(0, OS);
90    encodeULEB128(0, OS);
91  }
92}
93
94void 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);
102
103    auto HeaderSize = OS.tell() - HeaderStart;
104    auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2);
105    ZeroFillBytes(OS, FirstDescriptor - HeaderSize);
106
107    for (auto Descriptor : Range.Descriptors) {
108      writeVariableSizedInteger(Descriptor.Address, Range.AddrSize, OS,
109                                DI.IsLittleEndian);
110      writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS,
111                                DI.IsLittleEndian);
112    }
113    ZeroFillBytes(OS, Range.AddrSize * 2);
114  }
115}
116
117void 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);
126    if (Sect.IsGNUStyle)
127      writeInteger((uint32_t)Entry.Descriptor, OS, IsLittleEndian);
128    OS.write(Entry.Name.data(), Entry.Name.size());
129    OS.write('\0');
130  }
131}
132
133namespace {
134/// An extension of the DWARFYAML::ConstVisitor which writes compile
135/// units and DIEs to a stream.
136class DumpVisitor : public DWARFYAML::ConstVisitor {
137  raw_ostream &OS;
138
139protected:
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);
147    }else {
148      writeInteger((uint32_t)CU.AbbrOffset, OS, DebugInfo.IsLittleEndian);
149      writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian);
150    }
151  }
152
153  void onStartDIE(const DWARFYAML::Unit &CU,
154                  const DWARFYAML::Entry &DIE) override {
155    encodeULEB128(DIE.AbbrCode, OS);
156  }
157
158  void onValue(const uint8_t U) override {
159    writeInteger(U, OS, DebugInfo.IsLittleEndian);
160  }
161
162  void onValue(const uint16_t U) override {
163    writeInteger(U, OS, DebugInfo.IsLittleEndian);
164  }
165
166  void onValue(const uint32_t U) override {
167    writeInteger(U, OS, DebugInfo.IsLittleEndian);
168  }
169
170  void onValue(const uint64_t U, const bool LEB = false) override {
171    if (LEB)
172      encodeULEB128(U, OS);
173    else
174      writeInteger(U, OS, DebugInfo.IsLittleEndian);
175  }
176
177  void onValue(const int64_t S, const bool LEB = false) override {
178    if (LEB)
179      encodeSLEB128(S, OS);
180    else
181      writeInteger(S, OS, DebugInfo.IsLittleEndian);
182  }
183
184  void onValue(const StringRef String) override {
185    OS.write(String.data(), String.size());
186    OS.write('\0');
187  }
188
189  void onValue(const MemoryBufferRef MBR) override {
190    OS.write(MBR.getBufferStart(), MBR.getBufferSize());
191  }
192
193public:
194  DumpVisitor(const DWARFYAML::Data &DI, raw_ostream &Out)
195      : DWARFYAML::ConstVisitor(DI), OS(Out) {}
196};
197} // namespace
198
199void DWARFYAML::EmitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) {
200  DumpVisitor Visitor(DI, OS);
201  Visitor.traverseDebugInfo();
202}
203
204static void EmitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) {
205  OS.write(File.Name.data(), File.Name.size());
206  OS.write('\0');
207  encodeULEB128(File.DirIdx, OS);
208  encodeULEB128(File.ModTime, OS);
209  encodeULEB128(File.Length, OS);
210}
211
212void 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);
226
227    for (auto OpcodeLength : LineTable.StandardOpcodeLengths)
228      writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian);
229
230    for (auto IncludeDir : LineTable.IncludeDirs) {
231      OS.write(IncludeDir.data(), IncludeDir.size());
232      OS.write('\0');
233    }
234    OS.write('\0');
235
236    for (auto File : LineTable.Files)
237      EmitFileEntry(OS, File);
238    OS.write('\0');
239
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,
249                                    DI.IsLittleEndian);
250          break;
251        case dwarf::DW_LNE_define_file:
252          EmitFileEntry(OS, Op.FileEntry);
253          break;
254        case dwarf::DW_LNE_end_sequence:
255          break;
256        default:
257          for (auto OpByte : Op.UnknownOpcodeData)
258            writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian);
259        }
260      } else if (Op.Opcode < LineTable.OpcodeBase) {
261        switch (Op.Opcode) {
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:
268          break;
269
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);
275          break;
276
277        case dwarf::DW_LNS_advance_line:
278          encodeSLEB128(Op.SData, OS);
279          break;
280
281        case dwarf::DW_LNS_fixed_advance_pc:
282          writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian);
283          break;
284
285        default:
286          for (auto OpData : Op.StandardOpcodeData) {
287            encodeULEB128(OpData, OS);
288          }
289        }
290      }
291    }
292  }
293}
294
295using EmitFuncType = void (*)(raw_ostream &, const DWARFYAML::Data &);
296
297static void
298EmitDebugSectionImpl(const DWARFYAML::Data &DI, EmitFuncType EmitFunc,
299                     StringRef Sec,
300                     StringMap<std::unique_ptr<MemoryBuffer>> &OutputBuffers) {
301  std::string Data;
302  raw_string_ostream DebugInfoStream(Data);
303  EmitFunc(DebugInfoStream, DI);
304  DebugInfoStream.flush();
305  if (!Data.empty())
306    OutputBuffers[Sec] = MemoryBuffer::getMemBufferCopy(Data);
307}
308
309namespace {
310class DIEFixupVisitor : public DWARFYAML::Visitor {
311  uint64_t Length;
312
313public:
314  DIEFixupVisitor(DWARFYAML::Data &DI) : DWARFYAML::Visitor(DI){};
315
316private:
317  virtual void onStartCompileUnit(DWARFYAML::Unit &CU) {
318    // Size of the unit header, excluding the length field itself.
319    Length = CU.Version >= 5 ? 8 : 7;
320  }
321
322  virtual void onEndCompileUnit(DWARFYAML::Unit &CU) {
323    CU.Length.setLength(Length);
324  }
325
326  virtual void onStartDIE(DWARFYAML::Unit &CU, DWARFYAML::Entry &DIE) {
327    Length += getULEB128Size(DIE.AbbrCode);
328  }
329
330  virtual void onValue(const uint8_t U) { Length += 1; }
331  virtual void onValue(const uint16_t U) { Length += 2; }
332  virtual void onValue(const uint32_t U) { Length += 4; }
333  virtual void onValue(const uint64_t U, const bool LEB = false) {
334    if (LEB)
335      Length += getULEB128Size(U);
336    else
337      Length += 8;
338  }
339  virtual void onValue(const int64_t S, const bool LEB = false) {
340    if (LEB)
341      Length += getSLEB128Size(S);
342    else
343      Length += 8;
344  }
345  virtual void onValue(const StringRef String) { Length += String.size() + 1; }
346
347  virtual void onValue(const MemoryBufferRef MBR) {
348    Length += MBR.getBufferSize();
349  }
350};
351} // namespace
352
353Expected<StringMap<std::unique_ptr<MemoryBuffer>>>
354DWARFYAML::EmitDebugSections(StringRef YAMLString, bool ApplyFixups,
355                             bool IsLittleEndian) {
356  yaml::Input YIn(YAMLString);
357
358  DWARFYAML::Data DI;
359  DI.IsLittleEndian = IsLittleEndian;
360  YIn >> DI;
361  if (YIn.error())
362    return errorCodeToError(YIn.error());
363
364  if (ApplyFixups) {
365    DIEFixupVisitor DIFixer(DI);
366    DIFixer.traverseDebugInfo();
367  }
368
369  StringMap<std::unique_ptr<MemoryBuffer>> DebugSections;
370  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugInfo, "debug_info",
371                       DebugSections);
372  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugLine, "debug_line",
373                       DebugSections);
374  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugStr, "debug_str",
375                       DebugSections);
376  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAbbrev, "debug_abbrev",
377                       DebugSections);
378  EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAranges, "debug_aranges",
379                       DebugSections);
380  return std::move(DebugSections);
381}
382