LLVM  10.0.0svn
DWARFEmitter.cpp
Go to the documentation of this file.
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 
15 #include "DWARFVisitor.h"
16 #include "llvm/ADT/StringMap.h"
17 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/Host.h"
21 #include "llvm/Support/LEB128.h"
27 #include <algorithm>
28 #include <cassert>
29 #include <cstddef>
30 #include <cstdint>
31 #include <memory>
32 #include <string>
33 #include <vector>
34 
35 using namespace llvm;
36 
37 template <typename T>
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));
42 }
43 
44 static 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 
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);
62 }
63 
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);
69 }
70 
72  for (auto Str : DI.DebugStrings) {
73  OS.write(Str.data(), Str.size());
74  OS.write('\0');
75  }
76 }
77 
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 
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 
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 
133 namespace {
134 /// An extension of the DWARFYAML::ConstVisitor which writes compile
135 /// units and DIEs to a stream.
136 class DumpVisitor : public DWARFYAML::ConstVisitor {
137  raw_ostream &OS;
138 
139 protected:
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 
193 public:
194  DumpVisitor(const DWARFYAML::Data &DI, raw_ostream &Out)
195  : DWARFYAML::ConstVisitor(DI), OS(Out) {}
196 };
197 } // namespace
198 
200  DumpVisitor Visitor(DI, OS);
201  Visitor.traverseDebugInfo();
202 }
203 
204 static 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 
213  for (const auto &LineTable : DI.DebugLines) {
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);
220  if (LineTable.Version >= 4)
223  writeInteger((uint8_t)LineTable.LineBase, 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 
295 using EmitFuncType = void (*)(raw_ostream &, const DWARFYAML::Data &);
296 
297 static void
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 
309 namespace {
310 class DIEFixupVisitor : public DWARFYAML::Visitor {
311  uint64_t Length;
312 
313 public:
314  DIEFixupVisitor(DWARFYAML::Data &DI) : DWARFYAML::Visitor(DI){};
315 
316 private:
317  virtual void onStartCompileUnit(DWARFYAML::Unit &CU) { Length = 7; }
318 
319  virtual void onEndCompileUnit(DWARFYAML::Unit &CU) {
320  CU.Length.setLength(Length);
321  }
322 
323  virtual void onStartDIE(DWARFYAML::Unit &CU, DWARFYAML::Entry &DIE) {
324  Length += getULEB128Size(DIE.AbbrCode);
325  }
326 
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) {
331  if (LEB)
332  Length += getULEB128Size(U);
333  else
334  Length += 8;
335  }
336  virtual void onValue(const int64_t S, const bool LEB = false) {
337  if (LEB)
338  Length += getSLEB128Size(S);
339  else
340  Length += 8;
341  }
342  virtual void onValue(const StringRef String) { Length += String.size() + 1; }
343 
344  virtual void onValue(const MemoryBufferRef MBR) {
345  Length += MBR.getBufferSize();
346  }
347 };
348 } // namespace
349 
351 DWARFYAML::EmitDebugSections(StringRef YAMLString, bool ApplyFixups,
352  bool IsLittleEndian) {
353  yaml::Input YIn(YAMLString);
354 
355  DWARFYAML::Data DI;
356  DI.IsLittleEndian = IsLittleEndian;
357  YIn >> DI;
358  if (YIn.error())
359  return errorCodeToError(YIn.error());
360 
361  if (ApplyFixups) {
362  DIEFixupVisitor DIFixer(DI);
363  DIFixer.traverseDebugInfo();
364  }
365 
368  DebugSections);
370  DebugSections);
372  DebugSections);
374  DebugSections);
376  DebugSections);
377  return std::move(DebugSections);
378 }
void swapByteOrder(T &Value)
This class represents lattice values for constants.
Definition: AllocatorList.h:23
void EmitDebugInfo(raw_ostream &OS, const Data &DI)
llvm::dwarf::UnitType Type
Definition: DWARFYAML.h:103
void EmitDebugAranges(raw_ostream &OS, const Data &DI)
std::vector< Abbrev > AbbrevDecls
Definition: DWARFYAML.h:145
static void ZeroFillBytes(raw_ostream &OS, size_t Size)
std::vector< uint8_t > StandardOpcodeLengths
Definition: DWARFYAML.h:137
std::vector< PubEntry > Entries
Definition: DWARFYAML.h:86
static void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian)
static void writeInitialLength(const DWARFYAML::InitialLength &Length, raw_ostream &OS, bool IsLittleEndian)
Expected< StringMap< std::unique_ptr< MemoryBuffer > > > EmitDebugSections(StringRef YAMLString, bool ApplyFixups=false, bool IsLittleEndian=sys::IsLittleEndianHost)
Tagged union holding either a T or a Error.
Definition: yaml2obj.h:21
std::vector< ARange > ARanges
Definition: DWARFYAML.h:147
void EmitDebugAbbrev(raw_ostream &OS, const Data &DI)
static const bool IsLittleEndianHost
Definition: Host.h:49
std::vector< Unit > CompileUnits
Definition: DWARFYAML.h:154
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:144
InitialLength Length
Definition: DWARFYAML.h:101
std::vector< File > Files
Definition: DWARFYAML.h:139
size_t getBufferSize() const
Definition: MemoryBuffer.h:278
std::vector< LineTable > DebugLines
Definition: DWARFYAML.h:156
Instrumentation for Order File
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:87
A structured debug information entry.
Definition: DIE.h:700
std::vector< StringRef > IncludeDirs
Definition: DWARFYAML.h:138
static void writeVariableSizedInteger(uint64_t Integer, size_t Size, raw_ostream &OS, bool IsLittleEndian)
unsigned getULEB128Size(uint64_t Value)
Utility function to get the size of the ULEB128-encoded value.
Definition: LEB128.cpp:19
raw_ostream & write(unsigned char C)
void EmitPubSection(raw_ostream &OS, const PubSection &Sect, bool IsLittleEndian)
static void EmitFileEntry(raw_ostream &OS, const DWARFYAML::File &File)
unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a ULEB128 value to an output stream.
Definition: LEB128.h:80
unsigned encodeSLEB128(int64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a SLEB128 value to an output stream.
Definition: LEB128.h:23
void(*)(raw_ostream &, const DWARFYAML::Data &) EmitFuncType
std::vector< StringRef > DebugStrings
Definition: DWARFYAML.h:146
llvm::yaml::Hex32 AbbrCode
Definition: DWARFYAML.h:96
static void EmitDebugSectionImpl(const DWARFYAML::Data &DI, EmitFuncType EmitFunc, StringRef Sec, StringMap< std::unique_ptr< MemoryBuffer >> &OutputBuffers)
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
Definition: StringMap.h:219
static std::unique_ptr< MemoryBuffer > getMemBufferCopy(StringRef InputData, const Twine &BufferName="")
Open the specified memory range as a MemoryBuffer, copying the contents and taking ownership of it...
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:133
This file declares classes for handling the YAML representation of DWARF Debug Info.
std::vector< LineTableOpcode > Opcodes
Definition: DWARFYAML.h:140
uint32_t Size
Definition: Profile.cpp:46
Common declarations for yaml2obj.
void EmitDebugStr(raw_ostream &OS, const Data &DI)
unsigned getSLEB128Size(int64_t Value)
Utility function to get the size of the SLEB128-encoded value.
Definition: LEB128.cpp:29
LLVM_NODISCARD const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:136
void setLength(uint64_t Len)
Definition: DWARFYAML.h:37
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const char * getBufferStart() const
Definition: MemoryBuffer.h:276
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:503
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:111
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:45
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
void EmitDebugLine(raw_ostream &OS, const Data &DI)