Line data Source code
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 : /// The DWARF component of yaml2obj. Provided as library code for tests.
12 : ///
13 : //===----------------------------------------------------------------------===//
14 :
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"
28 : #include <algorithm>
29 : #include <cassert>
30 : #include <cstddef>
31 : #include <cstdint>
32 : #include <memory>
33 : #include <string>
34 : #include <vector>
35 :
36 : using namespace llvm;
37 :
38 : template <typename T>
39 : static void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian) {
40 16 : if (IsLittleEndian != sys::IsLittleEndianHost)
41 : sys::swapByteOrder(Integer);
42 350 : OS.write(reinterpret_cast<char *>(&Integer), sizeof(T));
43 : }
44 :
45 24 : static void writeVariableSizedInteger(uint64_t Integer, size_t Size,
46 : raw_ostream &OS, bool IsLittleEndian) {
47 24 : if (8 == Size)
48 16 : writeInteger((uint64_t)Integer, OS, IsLittleEndian);
49 8 : else if (4 == Size)
50 16 : writeInteger((uint32_t)Integer, OS, IsLittleEndian);
51 0 : else if (2 == Size)
52 0 : writeInteger((uint16_t)Integer, OS, IsLittleEndian);
53 0 : else if (1 == Size)
54 0 : writeInteger((uint8_t)Integer, OS, IsLittleEndian);
55 : else
56 : assert(false && "Invalid integer write size.");
57 24 : }
58 :
59 8 : static void ZeroFillBytes(raw_ostream &OS, size_t Size) {
60 : std::vector<uint8_t> FillData;
61 8 : FillData.insert(FillData.begin(), Size, 0);
62 8 : OS.write(reinterpret_cast<char *>(FillData.data()), Size);
63 8 : }
64 :
65 54 : static void writeInitialLength(const DWARFYAML::InitialLength &Length,
66 : raw_ostream &OS, bool IsLittleEndian) {
67 54 : writeInteger((uint32_t)Length.TotalLength, OS, IsLittleEndian);
68 54 : if (Length.isDWARF64())
69 0 : writeInteger((uint64_t)Length.TotalLength64, OS, IsLittleEndian);
70 54 : }
71 :
72 30 : void DWARFYAML::EmitDebugStr(raw_ostream &OS, const DWARFYAML::Data &DI) {
73 126 : for (auto Str : DI.DebugStrings) {
74 96 : OS.write(Str.data(), Str.size());
75 96 : OS.write('\0');
76 : }
77 30 : }
78 :
79 30 : void DWARFYAML::EmitDebugAbbrev(raw_ostream &OS, const DWARFYAML::Data &DI) {
80 97 : for (auto AbbrevDecl : DI.AbbrevDecls) {
81 67 : encodeULEB128(AbbrevDecl.Code, OS);
82 67 : encodeULEB128(AbbrevDecl.Tag, OS);
83 67 : OS.write(AbbrevDecl.Children);
84 325 : for (auto Attr : AbbrevDecl.Attributes) {
85 258 : encodeULEB128(Attr.Attribute, OS);
86 258 : encodeULEB128(Attr.Form, OS);
87 258 : if (Attr.Form == dwarf::DW_FORM_implicit_const)
88 1 : encodeSLEB128(Attr.Value, OS);
89 : }
90 67 : encodeULEB128(0, OS);
91 67 : encodeULEB128(0, OS);
92 : }
93 30 : }
94 :
95 28 : void DWARFYAML::EmitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) {
96 32 : for (auto Range : DI.ARanges) {
97 : auto HeaderStart = OS.tell();
98 4 : writeInitialLength(Range.Length, OS, DI.IsLittleEndian);
99 4 : writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian);
100 4 : writeInteger((uint32_t)Range.CuOffset, OS, DI.IsLittleEndian);
101 4 : writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian);
102 4 : writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian);
103 :
104 4 : auto HeaderSize = OS.tell() - HeaderStart;
105 4 : auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2);
106 4 : ZeroFillBytes(OS, FirstDescriptor - HeaderSize);
107 :
108 8 : for (auto Descriptor : Range.Descriptors) {
109 4 : writeVariableSizedInteger(Descriptor.Address, Range.AddrSize, OS,
110 4 : DI.IsLittleEndian);
111 4 : writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS,
112 4 : DI.IsLittleEndian);
113 : }
114 4 : ZeroFillBytes(OS, Range.AddrSize * 2);
115 : }
116 28 : }
117 :
118 18 : void DWARFYAML::EmitPubSection(raw_ostream &OS,
119 : const DWARFYAML::PubSection &Sect,
120 : bool IsLittleEndian) {
121 18 : writeInitialLength(Sect.Length, OS, IsLittleEndian);
122 18 : writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian);
123 18 : writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian);
124 18 : writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian);
125 24 : for (auto Entry : Sect.Entries) {
126 6 : writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian);
127 6 : if (Sect.IsGNUStyle)
128 0 : writeInteger((uint32_t)Entry.Descriptor, OS, IsLittleEndian);
129 6 : OS.write(Entry.Name.data(), Entry.Name.size());
130 6 : OS.write('\0');
131 : }
132 18 : }
133 :
134 : namespace {
135 : /// An extension of the DWARFYAML::ConstVisitor which writes compile
136 : /// units and DIEs to a stream.
137 : class DumpVisitor : public DWARFYAML::ConstVisitor {
138 : raw_ostream &OS;
139 :
140 : protected:
141 24 : void onStartCompileUnit(const DWARFYAML::Unit &CU) override {
142 24 : writeInitialLength(CU.Length, OS, DebugInfo.IsLittleEndian);
143 24 : writeInteger((uint16_t)CU.Version, OS, DebugInfo.IsLittleEndian);
144 24 : if(CU.Version >= 5) {
145 1 : writeInteger((uint8_t)CU.Type, OS, DebugInfo.IsLittleEndian);
146 1 : writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian);
147 2 : writeInteger((uint32_t)CU.AbbrOffset, OS, DebugInfo.IsLittleEndian);
148 : }else {
149 23 : writeInteger((uint32_t)CU.AbbrOffset, OS, DebugInfo.IsLittleEndian);
150 23 : writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian);
151 : }
152 24 : }
153 :
154 82 : void onStartDIE(const DWARFYAML::Unit &CU,
155 : const DWARFYAML::Entry &DIE) override {
156 82 : encodeULEB128(DIE.AbbrCode, OS);
157 82 : }
158 :
159 35 : void onValue(const uint8_t U) override {
160 35 : writeInteger(U, OS, DebugInfo.IsLittleEndian);
161 35 : }
162 :
163 6 : void onValue(const uint16_t U) override {
164 6 : writeInteger(U, OS, DebugInfo.IsLittleEndian);
165 6 : }
166 :
167 96 : void onValue(const uint32_t U) override {
168 96 : writeInteger(U, OS, DebugInfo.IsLittleEndian);
169 96 : }
170 :
171 58 : void onValue(const uint64_t U, const bool LEB = false) override {
172 58 : if (LEB)
173 12 : encodeULEB128(U, OS);
174 : else
175 92 : writeInteger(U, OS, DebugInfo.IsLittleEndian);
176 58 : }
177 :
178 1 : void onValue(const int64_t S, const bool LEB = false) override {
179 1 : if (LEB)
180 1 : encodeSLEB128(S, OS);
181 : else
182 0 : writeInteger(S, OS, DebugInfo.IsLittleEndian);
183 1 : }
184 :
185 1 : void onValue(const StringRef String) override {
186 2 : OS.write(String.data(), String.size());
187 1 : OS.write('\0');
188 1 : }
189 :
190 13 : void onValue(const MemoryBufferRef MBR) override {
191 26 : OS.write(MBR.getBufferStart(), MBR.getBufferSize());
192 13 : }
193 :
194 : public:
195 : DumpVisitor(const DWARFYAML::Data &DI, raw_ostream &Out)
196 60 : : DWARFYAML::ConstVisitor(DI), OS(Out) {}
197 : };
198 : } // namespace
199 :
200 30 : void DWARFYAML::EmitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) {
201 : DumpVisitor Visitor(DI, OS);
202 30 : Visitor.traverseDebugInfo();
203 30 : }
204 :
205 9 : static void EmitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) {
206 9 : OS.write(File.Name.data(), File.Name.size());
207 9 : OS.write('\0');
208 9 : encodeULEB128(File.DirIdx, OS);
209 9 : encodeULEB128(File.ModTime, OS);
210 9 : encodeULEB128(File.Length, OS);
211 9 : }
212 :
213 30 : void DWARFYAML::EmitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) {
214 38 : for (const auto &LineTable : DI.DebugLines) {
215 8 : writeInitialLength(LineTable.Length, OS, DI.IsLittleEndian);
216 8 : uint64_t SizeOfPrologueLength = LineTable.Length.isDWARF64() ? 8 : 4;
217 8 : writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian);
218 8 : writeVariableSizedInteger(LineTable.PrologueLength, SizeOfPrologueLength,
219 8 : OS, DI.IsLittleEndian);
220 8 : writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian);
221 8 : if (LineTable.Version >= 4)
222 0 : writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian);
223 8 : writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian);
224 8 : writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian);
225 8 : writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian);
226 8 : writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian);
227 :
228 104 : for (auto OpcodeLength : LineTable.StandardOpcodeLengths)
229 96 : writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian);
230 :
231 13 : for (auto IncludeDir : LineTable.IncludeDirs) {
232 5 : OS.write(IncludeDir.data(), IncludeDir.size());
233 5 : OS.write('\0');
234 : }
235 8 : OS.write('\0');
236 :
237 17 : for (auto File : LineTable.Files)
238 9 : EmitFileEntry(OS, File);
239 8 : OS.write('\0');
240 :
241 118 : for (auto Op : LineTable.Opcodes) {
242 55 : writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian);
243 55 : if (Op.Opcode == 0) {
244 16 : encodeULEB128(Op.ExtLen, OS);
245 16 : writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian);
246 16 : switch (Op.SubOpcode) {
247 8 : case dwarf::DW_LNE_set_address:
248 : case dwarf::DW_LNE_set_discriminator:
249 8 : writeVariableSizedInteger(Op.Data, DI.CompileUnits[0].AddrSize, OS,
250 8 : DI.IsLittleEndian);
251 8 : break;
252 0 : case dwarf::DW_LNE_define_file:
253 0 : EmitFileEntry(OS, Op.FileEntry);
254 0 : break;
255 : case dwarf::DW_LNE_end_sequence:
256 : break;
257 0 : default:
258 0 : for (auto OpByte : Op.UnknownOpcodeData)
259 0 : writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian);
260 : }
261 39 : } else if (Op.Opcode < LineTable.OpcodeBase) {
262 30 : switch (Op.Opcode) {
263 : case dwarf::DW_LNS_copy:
264 : case dwarf::DW_LNS_negate_stmt:
265 : case dwarf::DW_LNS_set_basic_block:
266 : case dwarf::DW_LNS_const_add_pc:
267 : case dwarf::DW_LNS_set_prologue_end:
268 : case dwarf::DW_LNS_set_epilogue_begin:
269 : break;
270 :
271 14 : case dwarf::DW_LNS_advance_pc:
272 : case dwarf::DW_LNS_set_file:
273 : case dwarf::DW_LNS_set_column:
274 : case dwarf::DW_LNS_set_isa:
275 14 : encodeULEB128(Op.Data, OS);
276 14 : break;
277 :
278 5 : case dwarf::DW_LNS_advance_line:
279 5 : encodeSLEB128(Op.SData, OS);
280 5 : break;
281 :
282 0 : case dwarf::DW_LNS_fixed_advance_pc:
283 0 : writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian);
284 0 : break;
285 :
286 0 : default:
287 0 : for (auto OpData : Op.StandardOpcodeData) {
288 0 : encodeULEB128(OpData, OS);
289 : }
290 : }
291 : }
292 : }
293 : }
294 30 : }
295 :
296 : using EmitFuncType = void (*)(raw_ostream &, const DWARFYAML::Data &);
297 :
298 : static void
299 95 : EmitDebugSectionImpl(const DWARFYAML::Data &DI, EmitFuncType EmitFunc,
300 : StringRef Sec,
301 : StringMap<std::unique_ptr<MemoryBuffer>> &OutputBuffers) {
302 : std::string Data;
303 95 : raw_string_ostream DebugInfoStream(Data);
304 95 : EmitFunc(DebugInfoStream, DI);
305 : DebugInfoStream.flush();
306 95 : if (!Data.empty())
307 183 : OutputBuffers[Sec] = MemoryBuffer::getMemBufferCopy(Data);
308 95 : }
309 :
310 : namespace {
311 : class DIEFixupVisitor : public DWARFYAML::Visitor {
312 : uint64_t Length;
313 :
314 : public:
315 1 : DIEFixupVisitor(DWARFYAML::Data &DI) : DWARFYAML::Visitor(DI){};
316 :
317 : private:
318 1 : virtual void onStartCompileUnit(DWARFYAML::Unit &CU) { Length = 7; }
319 :
320 1 : virtual void onEndCompileUnit(DWARFYAML::Unit &CU) {
321 1 : CU.Length.setLength(Length);
322 1 : }
323 :
324 2 : virtual void onStartDIE(DWARFYAML::Unit &CU, DWARFYAML::Entry &DIE) {
325 2 : Length += getULEB128Size(DIE.AbbrCode);
326 2 : }
327 :
328 0 : virtual void onValue(const uint8_t U) { Length += 1; }
329 0 : virtual void onValue(const uint16_t U) { Length += 2; }
330 0 : virtual void onValue(const uint32_t U) { Length += 4; }
331 0 : virtual void onValue(const uint64_t U, const bool LEB = false) {
332 0 : if (LEB)
333 0 : Length += getULEB128Size(U);
334 : else
335 0 : Length += 8;
336 0 : }
337 0 : virtual void onValue(const int64_t S, const bool LEB = false) {
338 0 : if (LEB)
339 0 : Length += getSLEB128Size(S);
340 : else
341 0 : Length += 8;
342 0 : }
343 0 : virtual void onValue(const StringRef String) { Length += String.size() + 1; }
344 :
345 0 : virtual void onValue(const MemoryBufferRef MBR) {
346 0 : Length += MBR.getBufferSize();
347 0 : }
348 : };
349 : } // namespace
350 :
351 : Expected<StringMap<std::unique_ptr<MemoryBuffer>>>
352 19 : DWARFYAML::EmitDebugSections(StringRef YAMLString, bool ApplyFixups,
353 : bool IsLittleEndian) {
354 38 : yaml::Input YIn(YAMLString);
355 :
356 19 : DWARFYAML::Data DI;
357 19 : DI.IsLittleEndian = IsLittleEndian;
358 : YIn >> DI;
359 19 : if (YIn.error())
360 0 : return errorCodeToError(YIn.error());
361 :
362 19 : if (ApplyFixups) {
363 : DIEFixupVisitor DIFixer(DI);
364 1 : DIFixer.traverseDebugInfo();
365 : }
366 :
367 19 : StringMap<std::unique_ptr<MemoryBuffer>> DebugSections;
368 19 : EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugInfo, "debug_info",
369 : DebugSections);
370 19 : EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugLine, "debug_line",
371 : DebugSections);
372 19 : EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugStr, "debug_str",
373 : DebugSections);
374 19 : EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAbbrev, "debug_abbrev",
375 : DebugSections);
376 19 : EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAranges, "debug_aranges",
377 : DebugSections);
378 : return std::move(DebugSections);
379 : }
|