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/ArrayRef.h" 17 #include "llvm/ADT/StringMap.h" 18 #include "llvm/ADT/StringRef.h" 19 #include "llvm/BinaryFormat/Dwarf.h" 20 #include "llvm/ObjectYAML/DWARFYAML.h" 21 #include "llvm/Support/Errc.h" 22 #include "llvm/Support/Error.h" 23 #include "llvm/Support/Host.h" 24 #include "llvm/Support/LEB128.h" 25 #include "llvm/Support/MathExtras.h" 26 #include "llvm/Support/MemoryBuffer.h" 27 #include "llvm/Support/SourceMgr.h" 28 #include "llvm/Support/SwapByteOrder.h" 29 #include "llvm/Support/YAMLTraits.h" 30 #include "llvm/Support/raw_ostream.h" 31 #include <algorithm> 32 #include <cassert> 33 #include <cstddef> 34 #include <cstdint> 35 #include <memory> 36 #include <string> 37 #include <vector> 38 39 using namespace llvm; 40 41 template <typename T> 42 static void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian) { 43 if (IsLittleEndian != sys::IsLittleEndianHost) 44 sys::swapByteOrder(Integer); 45 OS.write(reinterpret_cast<char *>(&Integer), sizeof(T)); 46 } 47 48 static Error writeVariableSizedInteger(uint64_t Integer, size_t Size, 49 raw_ostream &OS, bool IsLittleEndian) { 50 if (8 == Size) 51 writeInteger((uint64_t)Integer, OS, IsLittleEndian); 52 else if (4 == Size) 53 writeInteger((uint32_t)Integer, OS, IsLittleEndian); 54 else if (2 == Size) 55 writeInteger((uint16_t)Integer, OS, IsLittleEndian); 56 else if (1 == Size) 57 writeInteger((uint8_t)Integer, OS, IsLittleEndian); 58 else 59 return createStringError(errc::not_supported, 60 "invalid integer write size: %zu", Size); 61 62 return Error::success(); 63 } 64 65 static void ZeroFillBytes(raw_ostream &OS, size_t Size) { 66 std::vector<uint8_t> FillData; 67 FillData.insert(FillData.begin(), Size, 0); 68 OS.write(reinterpret_cast<char *>(FillData.data()), Size); 69 } 70 71 static void writeInitialLength(const DWARFYAML::InitialLength &Length, 72 raw_ostream &OS, bool IsLittleEndian) { 73 writeInteger((uint32_t)Length.TotalLength, OS, IsLittleEndian); 74 if (Length.isDWARF64()) 75 writeInteger((uint64_t)Length.TotalLength64, OS, IsLittleEndian); 76 } 77 78 static void writeInitialLength(const dwarf::DwarfFormat Format, 79 const uint64_t Length, raw_ostream &OS, 80 bool IsLittleEndian) { 81 bool IsDWARF64 = Format == dwarf::DWARF64; 82 if (IsDWARF64) 83 cantFail(writeVariableSizedInteger(dwarf::DW_LENGTH_DWARF64, 4, OS, 84 IsLittleEndian)); 85 cantFail( 86 writeVariableSizedInteger(Length, IsDWARF64 ? 8 : 4, OS, IsLittleEndian)); 87 } 88 89 Error DWARFYAML::emitDebugStr(raw_ostream &OS, const DWARFYAML::Data &DI) { 90 for (auto Str : DI.DebugStrings) { 91 OS.write(Str.data(), Str.size()); 92 OS.write('\0'); 93 } 94 95 return Error::success(); 96 } 97 98 Error DWARFYAML::emitDebugAbbrev(raw_ostream &OS, const DWARFYAML::Data &DI) { 99 uint64_t AbbrevCode = 0; 100 for (auto AbbrevDecl : DI.AbbrevDecls) { 101 AbbrevCode = AbbrevDecl.Code ? (uint64_t)*AbbrevDecl.Code : AbbrevCode + 1; 102 encodeULEB128(AbbrevCode, OS); 103 encodeULEB128(AbbrevDecl.Tag, OS); 104 OS.write(AbbrevDecl.Children); 105 for (auto Attr : AbbrevDecl.Attributes) { 106 encodeULEB128(Attr.Attribute, OS); 107 encodeULEB128(Attr.Form, OS); 108 if (Attr.Form == dwarf::DW_FORM_implicit_const) 109 encodeSLEB128(Attr.Value, OS); 110 } 111 encodeULEB128(0, OS); 112 encodeULEB128(0, OS); 113 } 114 115 // The abbreviations for a given compilation unit end with an entry consisting 116 // of a 0 byte for the abbreviation code. 117 OS.write_zeros(1); 118 119 return Error::success(); 120 } 121 122 Error DWARFYAML::emitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) { 123 for (auto Range : DI.ARanges) { 124 auto HeaderStart = OS.tell(); 125 writeInitialLength(Range.Format, Range.Length, OS, DI.IsLittleEndian); 126 writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian); 127 if (Range.Format == dwarf::DWARF64) 128 writeInteger((uint64_t)Range.CuOffset, OS, DI.IsLittleEndian); 129 else 130 writeInteger((uint32_t)Range.CuOffset, OS, DI.IsLittleEndian); 131 writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian); 132 writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian); 133 134 auto HeaderSize = OS.tell() - HeaderStart; 135 auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2); 136 ZeroFillBytes(OS, FirstDescriptor - HeaderSize); 137 138 for (auto Descriptor : Range.Descriptors) { 139 if (Error Err = writeVariableSizedInteger( 140 Descriptor.Address, Range.AddrSize, OS, DI.IsLittleEndian)) 141 return createStringError(errc::not_supported, 142 "unable to write debug_aranges address: %s", 143 toString(std::move(Err)).c_str()); 144 cantFail(writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS, 145 DI.IsLittleEndian)); 146 } 147 ZeroFillBytes(OS, Range.AddrSize * 2); 148 } 149 150 return Error::success(); 151 } 152 153 Error DWARFYAML::emitDebugRanges(raw_ostream &OS, const DWARFYAML::Data &DI) { 154 const size_t RangesOffset = OS.tell(); 155 uint64_t EntryIndex = 0; 156 for (auto DebugRanges : DI.DebugRanges) { 157 const size_t CurrOffset = OS.tell() - RangesOffset; 158 if (DebugRanges.Offset && (uint64_t)*DebugRanges.Offset < CurrOffset) 159 return createStringError(errc::invalid_argument, 160 "'Offset' for 'debug_ranges' with index " + 161 Twine(EntryIndex) + 162 " must be greater than or equal to the " 163 "number of bytes written already (0x" + 164 Twine::utohexstr(CurrOffset) + ")"); 165 if (DebugRanges.Offset) 166 ZeroFillBytes(OS, *DebugRanges.Offset - CurrOffset); 167 168 uint8_t AddrSize; 169 if (DebugRanges.AddrSize) 170 AddrSize = *DebugRanges.AddrSize; 171 else 172 AddrSize = DI.Is64BitAddrSize ? 8 : 4; 173 for (auto Entry : DebugRanges.Entries) { 174 if (Error Err = writeVariableSizedInteger(Entry.LowOffset, AddrSize, OS, 175 DI.IsLittleEndian)) 176 return createStringError( 177 errc::not_supported, 178 "unable to write debug_ranges address offset: %s", 179 toString(std::move(Err)).c_str()); 180 cantFail(writeVariableSizedInteger(Entry.HighOffset, AddrSize, OS, 181 DI.IsLittleEndian)); 182 } 183 ZeroFillBytes(OS, AddrSize * 2); 184 ++EntryIndex; 185 } 186 187 return Error::success(); 188 } 189 190 Error DWARFYAML::emitPubSection(raw_ostream &OS, 191 const DWARFYAML::PubSection &Sect, 192 bool IsLittleEndian, bool IsGNUPubSec) { 193 writeInitialLength(Sect.Length, OS, IsLittleEndian); 194 writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian); 195 writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian); 196 writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian); 197 for (auto Entry : Sect.Entries) { 198 writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian); 199 if (IsGNUPubSec) 200 writeInteger((uint8_t)Entry.Descriptor, OS, IsLittleEndian); 201 OS.write(Entry.Name.data(), Entry.Name.size()); 202 OS.write('\0'); 203 } 204 205 return Error::success(); 206 } 207 208 namespace { 209 /// An extension of the DWARFYAML::ConstVisitor which writes compile 210 /// units and DIEs to a stream. 211 class DumpVisitor : public DWARFYAML::ConstVisitor { 212 raw_ostream &OS; 213 214 protected: 215 void onStartCompileUnit(const DWARFYAML::Unit &CU) override { 216 writeInitialLength(CU.Format, CU.Length, OS, DebugInfo.IsLittleEndian); 217 writeInteger((uint16_t)CU.Version, OS, DebugInfo.IsLittleEndian); 218 if (CU.Version >= 5) { 219 writeInteger((uint8_t)CU.Type, OS, DebugInfo.IsLittleEndian); 220 writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian); 221 cantFail(writeVariableSizedInteger(CU.AbbrOffset, 222 CU.Format == dwarf::DWARF64 ? 8 : 4, 223 OS, DebugInfo.IsLittleEndian)); 224 } else { 225 cantFail(writeVariableSizedInteger(CU.AbbrOffset, 226 CU.Format == dwarf::DWARF64 ? 8 : 4, 227 OS, DebugInfo.IsLittleEndian)); 228 writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian); 229 } 230 } 231 232 void onStartDIE(const DWARFYAML::Unit &CU, 233 const DWARFYAML::Entry &DIE) override { 234 encodeULEB128(DIE.AbbrCode, OS); 235 } 236 237 void onValue(const uint8_t U) override { 238 writeInteger(U, OS, DebugInfo.IsLittleEndian); 239 } 240 241 void onValue(const uint16_t U) override { 242 writeInteger(U, OS, DebugInfo.IsLittleEndian); 243 } 244 245 void onValue(const uint32_t U) override { 246 writeInteger(U, OS, DebugInfo.IsLittleEndian); 247 } 248 249 void onValue(const uint64_t U, const bool LEB = false) override { 250 if (LEB) 251 encodeULEB128(U, OS); 252 else 253 writeInteger(U, OS, DebugInfo.IsLittleEndian); 254 } 255 256 void onValue(const int64_t S, const bool LEB = false) override { 257 if (LEB) 258 encodeSLEB128(S, OS); 259 else 260 writeInteger(S, OS, DebugInfo.IsLittleEndian); 261 } 262 263 void onValue(const StringRef String) override { 264 OS.write(String.data(), String.size()); 265 OS.write('\0'); 266 } 267 268 void onValue(const MemoryBufferRef MBR) override { 269 OS.write(MBR.getBufferStart(), MBR.getBufferSize()); 270 } 271 272 public: 273 DumpVisitor(const DWARFYAML::Data &DI, raw_ostream &Out) 274 : DWARFYAML::ConstVisitor(DI), OS(Out) {} 275 }; 276 } // namespace 277 278 Error DWARFYAML::emitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) { 279 DumpVisitor Visitor(DI, OS); 280 return Visitor.traverseDebugInfo(); 281 } 282 283 static void emitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) { 284 OS.write(File.Name.data(), File.Name.size()); 285 OS.write('\0'); 286 encodeULEB128(File.DirIdx, OS); 287 encodeULEB128(File.ModTime, OS); 288 encodeULEB128(File.Length, OS); 289 } 290 291 Error DWARFYAML::emitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) { 292 for (const auto &LineTable : DI.DebugLines) { 293 writeInitialLength(LineTable.Format, LineTable.Length, OS, 294 DI.IsLittleEndian); 295 uint64_t SizeOfPrologueLength = LineTable.Format == dwarf::DWARF64 ? 8 : 4; 296 writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian); 297 cantFail(writeVariableSizedInteger( 298 LineTable.PrologueLength, SizeOfPrologueLength, OS, DI.IsLittleEndian)); 299 writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian); 300 if (LineTable.Version >= 4) 301 writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian); 302 writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian); 303 writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian); 304 writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian); 305 writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian); 306 307 for (auto OpcodeLength : LineTable.StandardOpcodeLengths) 308 writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian); 309 310 for (auto IncludeDir : LineTable.IncludeDirs) { 311 OS.write(IncludeDir.data(), IncludeDir.size()); 312 OS.write('\0'); 313 } 314 OS.write('\0'); 315 316 for (auto File : LineTable.Files) 317 emitFileEntry(OS, File); 318 OS.write('\0'); 319 320 for (auto Op : LineTable.Opcodes) { 321 writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian); 322 if (Op.Opcode == 0) { 323 encodeULEB128(Op.ExtLen, OS); 324 writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian); 325 switch (Op.SubOpcode) { 326 case dwarf::DW_LNE_set_address: 327 case dwarf::DW_LNE_set_discriminator: 328 // TODO: Test this error. 329 if (Error Err = writeVariableSizedInteger( 330 Op.Data, DI.CompileUnits[0].AddrSize, OS, DI.IsLittleEndian)) 331 return Err; 332 break; 333 case dwarf::DW_LNE_define_file: 334 emitFileEntry(OS, Op.FileEntry); 335 break; 336 case dwarf::DW_LNE_end_sequence: 337 break; 338 default: 339 for (auto OpByte : Op.UnknownOpcodeData) 340 writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian); 341 } 342 } else if (Op.Opcode < LineTable.OpcodeBase) { 343 switch (Op.Opcode) { 344 case dwarf::DW_LNS_copy: 345 case dwarf::DW_LNS_negate_stmt: 346 case dwarf::DW_LNS_set_basic_block: 347 case dwarf::DW_LNS_const_add_pc: 348 case dwarf::DW_LNS_set_prologue_end: 349 case dwarf::DW_LNS_set_epilogue_begin: 350 break; 351 352 case dwarf::DW_LNS_advance_pc: 353 case dwarf::DW_LNS_set_file: 354 case dwarf::DW_LNS_set_column: 355 case dwarf::DW_LNS_set_isa: 356 encodeULEB128(Op.Data, OS); 357 break; 358 359 case dwarf::DW_LNS_advance_line: 360 encodeSLEB128(Op.SData, OS); 361 break; 362 363 case dwarf::DW_LNS_fixed_advance_pc: 364 writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian); 365 break; 366 367 default: 368 for (auto OpData : Op.StandardOpcodeData) { 369 encodeULEB128(OpData, OS); 370 } 371 } 372 } 373 } 374 } 375 376 return Error::success(); 377 } 378 379 Error DWARFYAML::emitDebugAddr(raw_ostream &OS, const Data &DI) { 380 for (const AddrTableEntry &TableEntry : DI.DebugAddr) { 381 uint8_t AddrSize; 382 if (TableEntry.AddrSize) 383 AddrSize = *TableEntry.AddrSize; 384 else 385 AddrSize = DI.Is64BitAddrSize ? 8 : 4; 386 387 uint64_t Length; 388 if (TableEntry.Length) 389 Length = (uint64_t)*TableEntry.Length; 390 else 391 // 2 (version) + 1 (address_size) + 1 (segment_selector_size) = 4 392 Length = 4 + (AddrSize + TableEntry.SegSelectorSize) * 393 TableEntry.SegAddrPairs.size(); 394 395 writeInitialLength(TableEntry.Format, Length, OS, DI.IsLittleEndian); 396 writeInteger((uint16_t)TableEntry.Version, OS, DI.IsLittleEndian); 397 writeInteger((uint8_t)AddrSize, OS, DI.IsLittleEndian); 398 writeInteger((uint8_t)TableEntry.SegSelectorSize, OS, DI.IsLittleEndian); 399 400 for (const SegAddrPair &Pair : TableEntry.SegAddrPairs) { 401 if (TableEntry.SegSelectorSize != 0) 402 if (Error Err = writeVariableSizedInteger(Pair.Segment, 403 TableEntry.SegSelectorSize, 404 OS, DI.IsLittleEndian)) 405 return createStringError(errc::not_supported, 406 "unable to write debug_addr segment: %s", 407 toString(std::move(Err)).c_str()); 408 if (AddrSize != 0) 409 if (Error Err = writeVariableSizedInteger(Pair.Address, AddrSize, OS, 410 DI.IsLittleEndian)) 411 return createStringError(errc::not_supported, 412 "unable to write debug_addr address: %s", 413 toString(std::move(Err)).c_str()); 414 } 415 } 416 417 return Error::success(); 418 } 419 420 Error DWARFYAML::emitDebugStrOffsets(raw_ostream &OS, const Data &DI) { 421 assert(DI.DebugStrOffsets && "unexpected emitDebugStrOffsets() call"); 422 for (const DWARFYAML::StringOffsetsTable &Table : *DI.DebugStrOffsets) { 423 uint64_t Length; 424 if (Table.Length) 425 Length = *Table.Length; 426 else 427 // sizeof(version) + sizeof(padding) = 4 428 Length = 429 4 + Table.Offsets.size() * (Table.Format == dwarf::DWARF64 ? 8 : 4); 430 431 writeInitialLength(Table.Format, Length, OS, DI.IsLittleEndian); 432 writeInteger((uint16_t)Table.Version, OS, DI.IsLittleEndian); 433 writeInteger((uint16_t)Table.Padding, OS, DI.IsLittleEndian); 434 435 for (uint64_t Offset : Table.Offsets) { 436 cantFail(writeVariableSizedInteger(Offset, 437 Table.Format == dwarf::DWARF64 ? 8 : 4, 438 OS, DI.IsLittleEndian)); 439 } 440 } 441 442 return Error::success(); 443 } 444 445 static Expected<uint64_t> writeListEntry(raw_ostream &OS, 446 const DWARFYAML::RnglistEntry &Entry, 447 uint8_t AddrSize, 448 bool IsLittleEndian) { 449 uint64_t BeginOffset = OS.tell(); 450 writeInteger((uint8_t)Entry.Operator, OS, IsLittleEndian); 451 452 auto CheckOperands = [&](uint64_t ExpectedOperands) -> Error { 453 if (Entry.Values.size() != ExpectedOperands) { 454 return createStringError( 455 errc::invalid_argument, 456 "invalid number (%zu) of operands for the operator: %s, %" PRIu64 457 " expected", 458 Entry.Values.size(), 459 dwarf::RangeListEncodingString(Entry.Operator).str().c_str(), 460 ExpectedOperands); 461 } 462 463 return Error::success(); 464 }; 465 466 auto WriteAddress = [&](uint64_t Addr) -> Error { 467 if (Error Err = 468 writeVariableSizedInteger(Addr, AddrSize, OS, IsLittleEndian)) 469 return createStringError( 470 errc::not_supported, 471 "unable to write address for the operator %s: %s", 472 dwarf::RangeListEncodingString(Entry.Operator).str().c_str(), 473 toString(std::move(Err)).c_str()); 474 return Error::success(); 475 }; 476 477 switch (Entry.Operator) { 478 case dwarf::DW_RLE_end_of_list: 479 if (Error Err = CheckOperands(0)) 480 return std::move(Err); 481 break; 482 case dwarf::DW_RLE_base_addressx: 483 if (Error Err = CheckOperands(1)) 484 return std::move(Err); 485 encodeULEB128(Entry.Values[0], OS); 486 break; 487 case dwarf::DW_RLE_startx_endx: 488 case dwarf::DW_RLE_startx_length: 489 case dwarf::DW_RLE_offset_pair: 490 if (Error Err = CheckOperands(2)) 491 return std::move(Err); 492 encodeULEB128(Entry.Values[0], OS); 493 encodeULEB128(Entry.Values[1], OS); 494 break; 495 case dwarf::DW_RLE_base_address: 496 if (Error Err = CheckOperands(1)) 497 return std::move(Err); 498 if (Error Err = WriteAddress(Entry.Values[0])) 499 return std::move(Err); 500 break; 501 case dwarf::DW_RLE_start_end: 502 if (Error Err = CheckOperands(2)) 503 return std::move(Err); 504 if (Error Err = WriteAddress(Entry.Values[0])) 505 return std::move(Err); 506 cantFail(WriteAddress(Entry.Values[1])); 507 break; 508 case dwarf::DW_RLE_start_length: 509 if (Error Err = CheckOperands(2)) 510 return std::move(Err); 511 if (Error Err = WriteAddress(Entry.Values[0])) 512 return std::move(Err); 513 encodeULEB128(Entry.Values[1], OS); 514 break; 515 } 516 517 return OS.tell() - BeginOffset; 518 } 519 520 template <typename EntryType> 521 Error writeDWARFLists(raw_ostream &OS, 522 ArrayRef<DWARFYAML::ListTable<EntryType>> Tables, 523 bool IsLittleEndian, bool Is64BitAddrSize) { 524 for (const DWARFYAML::ListTable<EntryType> &Table : Tables) { 525 // sizeof(version) + sizeof(address_size) + sizeof(segment_selector_size) + 526 // sizeof(offset_entry_count) = 8 527 uint64_t Length = 8; 528 529 uint8_t AddrSize; 530 if (Table.AddrSize) 531 AddrSize = *Table.AddrSize; 532 else 533 AddrSize = Is64BitAddrSize ? 8 : 4; 534 535 // Since the length of the current range/location lists entry is 536 // undetermined yet, we firstly write the content of the range/location 537 // lists to a buffer to calculate the length and then serialize the buffer 538 // content to the actual output stream. 539 std::string ListBuffer; 540 raw_string_ostream ListBufferOS(ListBuffer); 541 542 // Offsets holds offsets for each range/location list. The i-th element is 543 // the offset from the beginning of the first range/location list to the 544 // location of the i-th range list. 545 std::vector<uint64_t> Offsets; 546 547 for (const DWARFYAML::ListEntries<EntryType> &List : Table.Lists) { 548 Offsets.push_back(ListBufferOS.tell()); 549 for (const EntryType &Entry : List.Entries) { 550 Expected<uint64_t> EntrySize = 551 writeListEntry(ListBufferOS, Entry, AddrSize, IsLittleEndian); 552 if (!EntrySize) 553 return EntrySize.takeError(); 554 Length += *EntrySize; 555 } 556 } 557 558 // If the offset_entry_count field isn't specified, yaml2obj will infer it 559 // from the 'Offsets' field in the YAML description. If the 'Offsets' field 560 // isn't specified either, yaml2obj will infer it from the auto-generated 561 // offsets. 562 uint32_t OffsetEntryCount; 563 if (Table.OffsetEntryCount) 564 OffsetEntryCount = *Table.OffsetEntryCount; 565 else 566 OffsetEntryCount = Table.Offsets ? Table.Offsets->size() : Offsets.size(); 567 uint64_t OffsetsSize = 568 OffsetEntryCount * (Table.Format == dwarf::DWARF64 ? 8 : 4); 569 Length += OffsetsSize; 570 571 // If the length is specified in the YAML description, we use it instead of 572 // the actual length. 573 if (Table.Length) 574 Length = *Table.Length; 575 576 writeInitialLength(Table.Format, Length, OS, IsLittleEndian); 577 writeInteger((uint16_t)Table.Version, OS, IsLittleEndian); 578 writeInteger((uint8_t)AddrSize, OS, IsLittleEndian); 579 writeInteger((uint8_t)Table.SegSelectorSize, OS, IsLittleEndian); 580 writeInteger((uint32_t)OffsetEntryCount, OS, IsLittleEndian); 581 582 auto EmitOffsets = [&](ArrayRef<uint64_t> Offsets, uint64_t OffsetsSize) { 583 for (uint64_t Offset : Offsets) { 584 cantFail(writeVariableSizedInteger( 585 OffsetsSize + Offset, Table.Format == dwarf::DWARF64 ? 8 : 4, OS, 586 IsLittleEndian)); 587 } 588 }; 589 590 if (Table.Offsets) 591 EmitOffsets(ArrayRef<uint64_t>((const uint64_t *)Table.Offsets->data(), 592 Table.Offsets->size()), 593 0); 594 else 595 EmitOffsets(Offsets, OffsetsSize); 596 597 OS.write(ListBuffer.data(), ListBuffer.size()); 598 } 599 600 return Error::success(); 601 } 602 603 Error DWARFYAML::emitDebugRnglists(raw_ostream &OS, const Data &DI) { 604 assert(DI.DebugRnglists && "unexpected emitDebugRnglists() call"); 605 return writeDWARFLists<DWARFYAML::RnglistEntry>( 606 OS, *DI.DebugRnglists, DI.IsLittleEndian, DI.Is64BitAddrSize); 607 } 608 609 using EmitFuncType = Error (*)(raw_ostream &, const DWARFYAML::Data &); 610 611 static Error 612 emitDebugSectionImpl(const DWARFYAML::Data &DI, EmitFuncType EmitFunc, 613 StringRef Sec, 614 StringMap<std::unique_ptr<MemoryBuffer>> &OutputBuffers) { 615 std::string Data; 616 raw_string_ostream DebugInfoStream(Data); 617 if (Error Err = EmitFunc(DebugInfoStream, DI)) 618 return Err; 619 DebugInfoStream.flush(); 620 if (!Data.empty()) 621 OutputBuffers[Sec] = MemoryBuffer::getMemBufferCopy(Data); 622 623 return Error::success(); 624 } 625 626 namespace { 627 class DIEFixupVisitor : public DWARFYAML::Visitor { 628 uint64_t Length; 629 630 public: 631 DIEFixupVisitor(DWARFYAML::Data &DI) : DWARFYAML::Visitor(DI){}; 632 633 protected: 634 void onStartCompileUnit(DWARFYAML::Unit &CU) override { 635 // Size of the unit header, excluding the length field itself. 636 Length = CU.Version >= 5 ? 8 : 7; 637 } 638 639 void onEndCompileUnit(DWARFYAML::Unit &CU) override { CU.Length = Length; } 640 641 void onStartDIE(DWARFYAML::Unit &CU, DWARFYAML::Entry &DIE) override { 642 Length += getULEB128Size(DIE.AbbrCode); 643 } 644 645 void onValue(const uint8_t U) override { Length += 1; } 646 void onValue(const uint16_t U) override { Length += 2; } 647 void onValue(const uint32_t U) override { Length += 4; } 648 void onValue(const uint64_t U, const bool LEB = false) override { 649 if (LEB) 650 Length += getULEB128Size(U); 651 else 652 Length += 8; 653 } 654 void onValue(const int64_t S, const bool LEB = false) override { 655 if (LEB) 656 Length += getSLEB128Size(S); 657 else 658 Length += 8; 659 } 660 void onValue(const StringRef String) override { Length += String.size() + 1; } 661 662 void onValue(const MemoryBufferRef MBR) override { 663 Length += MBR.getBufferSize(); 664 } 665 }; 666 } // namespace 667 668 Expected<StringMap<std::unique_ptr<MemoryBuffer>>> 669 DWARFYAML::emitDebugSections(StringRef YAMLString, bool ApplyFixups, 670 bool IsLittleEndian) { 671 auto CollectDiagnostic = [](const SMDiagnostic &Diag, void *DiagContext) { 672 *static_cast<SMDiagnostic *>(DiagContext) = Diag; 673 }; 674 675 SMDiagnostic GeneratedDiag; 676 yaml::Input YIn(YAMLString, /*Ctxt=*/nullptr, CollectDiagnostic, 677 &GeneratedDiag); 678 679 DWARFYAML::Data DI; 680 DI.IsLittleEndian = IsLittleEndian; 681 YIn >> DI; 682 if (YIn.error()) 683 return createStringError(YIn.error(), GeneratedDiag.getMessage()); 684 685 if (ApplyFixups) { 686 DIEFixupVisitor DIFixer(DI); 687 if (Error Err = DIFixer.traverseDebugInfo()) 688 return std::move(Err); 689 } 690 691 StringMap<std::unique_ptr<MemoryBuffer>> DebugSections; 692 Error Err = emitDebugSectionImpl(DI, &DWARFYAML::emitDebugInfo, "debug_info", 693 DebugSections); 694 Err = joinErrors(std::move(Err), 695 emitDebugSectionImpl(DI, &DWARFYAML::emitDebugLine, 696 "debug_line", DebugSections)); 697 Err = joinErrors(std::move(Err), 698 emitDebugSectionImpl(DI, &DWARFYAML::emitDebugStr, 699 "debug_str", DebugSections)); 700 Err = joinErrors(std::move(Err), 701 emitDebugSectionImpl(DI, &DWARFYAML::emitDebugAbbrev, 702 "debug_abbrev", DebugSections)); 703 Err = joinErrors(std::move(Err), 704 emitDebugSectionImpl(DI, &DWARFYAML::emitDebugAranges, 705 "debug_aranges", DebugSections)); 706 Err = joinErrors(std::move(Err), 707 emitDebugSectionImpl(DI, &DWARFYAML::emitDebugRanges, 708 "debug_ranges", DebugSections)); 709 710 if (Err) 711 return std::move(Err); 712 return std::move(DebugSections); 713 } 714