1297 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// The DWARF component of yaml2obj. Provided as library code for tests.11///12//===----------------------------------------------------------------------===//13 14#include "llvm/ObjectYAML/DWARFEmitter.h"15#include "llvm/ADT/ArrayRef.h"16#include "llvm/ADT/StringMap.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/ADT/StringSwitch.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/LEB128.h"24#include "llvm/Support/MathExtras.h"25#include "llvm/Support/MemoryBuffer.h"26#include "llvm/Support/SourceMgr.h"27#include "llvm/Support/SwapByteOrder.h"28#include "llvm/Support/YAMLTraits.h"29#include "llvm/Support/raw_ostream.h"30#include "llvm/TargetParser/Host.h"31#include <cassert>32#include <cstddef>33#include <cstdint>34#include <memory>35#include <optional>36#include <string>37#include <vector>38 39using namespace llvm;40 41template <typename T>42static 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 48static 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 else59 return createStringError(errc::not_supported,60 "invalid integer write size: %zu", Size);61 62 return Error::success();63}64 65static void ZeroFillBytes(raw_ostream &OS, size_t Size) {66 std::vector<uint8_t> FillData(Size, 0);67 OS.write(reinterpret_cast<char *>(FillData.data()), Size);68}69 70static void writeInitialLength(const dwarf::DwarfFormat Format,71 const uint64_t Length, raw_ostream &OS,72 bool IsLittleEndian) {73 bool IsDWARF64 = Format == dwarf::DWARF64;74 if (IsDWARF64)75 cantFail(writeVariableSizedInteger(dwarf::DW_LENGTH_DWARF64, 4, OS,76 IsLittleEndian));77 cantFail(78 writeVariableSizedInteger(Length, IsDWARF64 ? 8 : 4, OS, IsLittleEndian));79}80 81static void writeDWARFOffset(uint64_t Offset, dwarf::DwarfFormat Format,82 raw_ostream &OS, bool IsLittleEndian) {83 cantFail(writeVariableSizedInteger(Offset, Format == dwarf::DWARF64 ? 8 : 4,84 OS, IsLittleEndian));85}86 87Error DWARFYAML::emitDebugStr(raw_ostream &OS, const DWARFYAML::Data &DI) {88 for (StringRef Str : *DI.DebugStrings) {89 OS.write(Str.data(), Str.size());90 OS.write('\0');91 }92 93 return Error::success();94}95 96StringRef DWARFYAML::Data::getAbbrevTableContentByIndex(uint64_t Index) const {97 assert(Index < DebugAbbrev.size() &&98 "Index should be less than the size of DebugAbbrev array");99 auto [It, Inserted] = AbbrevTableContents.try_emplace(Index);100 if (!Inserted)101 return It->second;102 103 raw_string_ostream OS(It->second);104 105 uint64_t AbbrevCode = 0;106 for (const DWARFYAML::Abbrev &AbbrevDecl : DebugAbbrev[Index].Table) {107 AbbrevCode = AbbrevDecl.Code ? (uint64_t)*AbbrevDecl.Code : AbbrevCode + 1;108 encodeULEB128(AbbrevCode, OS);109 encodeULEB128(AbbrevDecl.Tag, OS);110 OS.write(AbbrevDecl.Children);111 for (const auto &Attr : AbbrevDecl.Attributes) {112 encodeULEB128(Attr.Attribute, OS);113 encodeULEB128(Attr.Form, OS);114 if (Attr.Form == dwarf::DW_FORM_implicit_const)115 encodeSLEB128(Attr.Value, OS);116 }117 encodeULEB128(0, OS);118 encodeULEB128(0, OS);119 }120 121 // The abbreviations for a given compilation unit end with an entry122 // consisting of a 0 byte for the abbreviation code.123 OS.write_zeros(1);124 125 return It->second;126}127 128Error DWARFYAML::emitDebugAbbrev(raw_ostream &OS, const DWARFYAML::Data &DI) {129 for (uint64_t I = 0; I < DI.DebugAbbrev.size(); ++I) {130 StringRef AbbrevTableContent = DI.getAbbrevTableContentByIndex(I);131 OS.write(AbbrevTableContent.data(), AbbrevTableContent.size());132 }133 134 return Error::success();135}136 137Error DWARFYAML::emitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) {138 assert(DI.DebugAranges && "unexpected emitDebugAranges() call");139 for (const auto &Range : *DI.DebugAranges) {140 uint8_t AddrSize;141 if (Range.AddrSize)142 AddrSize = *Range.AddrSize;143 else144 AddrSize = DI.Is64BitAddrSize ? 8 : 4;145 146 uint64_t Length = 4; // sizeof(version) 2 + sizeof(address_size) 1 +147 // sizeof(segment_selector_size) 1148 Length +=149 Range.Format == dwarf::DWARF64 ? 8 : 4; // sizeof(debug_info_offset)150 151 const uint64_t HeaderLength =152 Length + (Range.Format == dwarf::DWARF64153 ? 12154 : 4); // sizeof(unit_header) = 12 (DWARF64) or 4 (DWARF32)155 const uint64_t PaddedHeaderLength = alignTo(HeaderLength, AddrSize * 2);156 157 if (Range.Length) {158 Length = *Range.Length;159 } else {160 Length += PaddedHeaderLength - HeaderLength;161 Length += AddrSize * 2 * (Range.Descriptors.size() + 1);162 }163 164 writeInitialLength(Range.Format, Length, OS, DI.IsLittleEndian);165 writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian);166 writeDWARFOffset(Range.CuOffset, Range.Format, OS, DI.IsLittleEndian);167 writeInteger((uint8_t)AddrSize, OS, DI.IsLittleEndian);168 writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian);169 ZeroFillBytes(OS, PaddedHeaderLength - HeaderLength);170 171 for (const auto &Descriptor : Range.Descriptors) {172 if (Error Err = writeVariableSizedInteger(Descriptor.Address, AddrSize,173 OS, DI.IsLittleEndian))174 return createStringError(errc::not_supported,175 "unable to write debug_aranges address: %s",176 toString(std::move(Err)).c_str());177 cantFail(writeVariableSizedInteger(Descriptor.Length, AddrSize, OS,178 DI.IsLittleEndian));179 }180 ZeroFillBytes(OS, AddrSize * 2);181 }182 183 return Error::success();184}185 186Error DWARFYAML::emitDebugRanges(raw_ostream &OS, const DWARFYAML::Data &DI) {187 const size_t RangesOffset = OS.tell();188 uint64_t EntryIndex = 0;189 for (const auto &DebugRanges : *DI.DebugRanges) {190 const size_t CurrOffset = OS.tell() - RangesOffset;191 if (DebugRanges.Offset && (uint64_t)*DebugRanges.Offset < CurrOffset)192 return createStringError(errc::invalid_argument,193 "'Offset' for 'debug_ranges' with index " +194 Twine(EntryIndex) +195 " must be greater than or equal to the "196 "number of bytes written already (0x" +197 Twine::utohexstr(CurrOffset) + ")");198 if (DebugRanges.Offset)199 ZeroFillBytes(OS, *DebugRanges.Offset - CurrOffset);200 201 uint8_t AddrSize;202 if (DebugRanges.AddrSize)203 AddrSize = *DebugRanges.AddrSize;204 else205 AddrSize = DI.Is64BitAddrSize ? 8 : 4;206 for (const auto &Entry : DebugRanges.Entries) {207 if (Error Err = writeVariableSizedInteger(Entry.LowOffset, AddrSize, OS,208 DI.IsLittleEndian))209 return createStringError(210 errc::not_supported,211 "unable to write debug_ranges address offset: %s",212 toString(std::move(Err)).c_str());213 cantFail(writeVariableSizedInteger(Entry.HighOffset, AddrSize, OS,214 DI.IsLittleEndian));215 }216 ZeroFillBytes(OS, AddrSize * 2);217 ++EntryIndex;218 }219 220 return Error::success();221}222 223static Error emitPubSection(raw_ostream &OS, const DWARFYAML::PubSection &Sect,224 bool IsLittleEndian, bool IsGNUPubSec = false) {225 writeInitialLength(Sect.Format, Sect.Length, OS, IsLittleEndian);226 writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian);227 writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian);228 writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian);229 for (const auto &Entry : Sect.Entries) {230 writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian);231 if (IsGNUPubSec)232 writeInteger((uint8_t)Entry.Descriptor, OS, IsLittleEndian);233 OS.write(Entry.Name.data(), Entry.Name.size());234 OS.write('\0');235 }236 return Error::success();237}238 239Error DWARFYAML::emitDebugPubnames(raw_ostream &OS, const Data &DI) {240 assert(DI.PubNames && "unexpected emitDebugPubnames() call");241 return emitPubSection(OS, *DI.PubNames, DI.IsLittleEndian);242}243 244Error DWARFYAML::emitDebugPubtypes(raw_ostream &OS, const Data &DI) {245 assert(DI.PubTypes && "unexpected emitDebugPubtypes() call");246 return emitPubSection(OS, *DI.PubTypes, DI.IsLittleEndian);247}248 249Error DWARFYAML::emitDebugGNUPubnames(raw_ostream &OS, const Data &DI) {250 assert(DI.GNUPubNames && "unexpected emitDebugGNUPubnames() call");251 return emitPubSection(OS, *DI.GNUPubNames, DI.IsLittleEndian,252 /*IsGNUStyle=*/true);253}254 255Error DWARFYAML::emitDebugGNUPubtypes(raw_ostream &OS, const Data &DI) {256 assert(DI.GNUPubTypes && "unexpected emitDebugGNUPubtypes() call");257 return emitPubSection(OS, *DI.GNUPubTypes, DI.IsLittleEndian,258 /*IsGNUStyle=*/true);259}260 261static Expected<uint64_t> writeDIE(const DWARFYAML::Data &DI, uint64_t CUIndex,262 uint64_t AbbrevTableID,263 const dwarf::FormParams &Params,264 const DWARFYAML::Entry &Entry,265 raw_ostream &OS, bool IsLittleEndian) {266 uint64_t EntryBegin = OS.tell();267 encodeULEB128(Entry.AbbrCode, OS);268 uint32_t AbbrCode = Entry.AbbrCode;269 if (AbbrCode == 0 || Entry.Values.empty())270 return OS.tell() - EntryBegin;271 272 Expected<DWARFYAML::Data::AbbrevTableInfo> AbbrevTableInfoOrErr =273 DI.getAbbrevTableInfoByID(AbbrevTableID);274 if (!AbbrevTableInfoOrErr)275 return createStringError(errc::invalid_argument,276 toString(AbbrevTableInfoOrErr.takeError()) +277 " for compilation unit with index " +278 utostr(CUIndex));279 280 ArrayRef<DWARFYAML::Abbrev> AbbrevDecls(281 DI.DebugAbbrev[AbbrevTableInfoOrErr->Index].Table);282 283 if (AbbrCode > AbbrevDecls.size())284 return createStringError(285 errc::invalid_argument,286 "abbrev code must be less than or equal to the number of "287 "entries in abbreviation table");288 const DWARFYAML::Abbrev &Abbrev = AbbrevDecls[AbbrCode - 1];289 auto FormVal = Entry.Values.begin();290 auto AbbrForm = Abbrev.Attributes.begin();291 for (; FormVal != Entry.Values.end() && AbbrForm != Abbrev.Attributes.end();292 ++FormVal, ++AbbrForm) {293 dwarf::Form Form = AbbrForm->Form;294 bool Indirect;295 do {296 Indirect = false;297 switch (Form) {298 case dwarf::DW_FORM_addr:299 // TODO: Test this error.300 if (Error Err = writeVariableSizedInteger(301 FormVal->Value, Params.AddrSize, OS, IsLittleEndian))302 return std::move(Err);303 break;304 case dwarf::DW_FORM_ref_addr:305 // TODO: Test this error.306 if (Error Err = writeVariableSizedInteger(FormVal->Value,307 Params.getRefAddrByteSize(),308 OS, IsLittleEndian))309 return std::move(Err);310 break;311 case dwarf::DW_FORM_exprloc:312 case dwarf::DW_FORM_block:313 encodeULEB128(FormVal->BlockData.size(), OS);314 OS.write((const char *)FormVal->BlockData.data(),315 FormVal->BlockData.size());316 break;317 case dwarf::DW_FORM_block1: {318 writeInteger((uint8_t)FormVal->BlockData.size(), OS, IsLittleEndian);319 OS.write((const char *)FormVal->BlockData.data(),320 FormVal->BlockData.size());321 break;322 }323 case dwarf::DW_FORM_block2: {324 writeInteger((uint16_t)FormVal->BlockData.size(), OS, IsLittleEndian);325 OS.write((const char *)FormVal->BlockData.data(),326 FormVal->BlockData.size());327 break;328 }329 case dwarf::DW_FORM_block4: {330 writeInteger((uint32_t)FormVal->BlockData.size(), OS, IsLittleEndian);331 OS.write((const char *)FormVal->BlockData.data(),332 FormVal->BlockData.size());333 break;334 }335 case dwarf::DW_FORM_strx:336 case dwarf::DW_FORM_addrx:337 case dwarf::DW_FORM_rnglistx:338 case dwarf::DW_FORM_loclistx:339 case dwarf::DW_FORM_udata:340 case dwarf::DW_FORM_ref_udata:341 case dwarf::DW_FORM_GNU_addr_index:342 case dwarf::DW_FORM_GNU_str_index:343 encodeULEB128(FormVal->Value, OS);344 break;345 case dwarf::DW_FORM_data1:346 case dwarf::DW_FORM_ref1:347 case dwarf::DW_FORM_flag:348 case dwarf::DW_FORM_strx1:349 case dwarf::DW_FORM_addrx1:350 writeInteger((uint8_t)FormVal->Value, OS, IsLittleEndian);351 break;352 case dwarf::DW_FORM_data2:353 case dwarf::DW_FORM_ref2:354 case dwarf::DW_FORM_strx2:355 case dwarf::DW_FORM_addrx2:356 writeInteger((uint16_t)FormVal->Value, OS, IsLittleEndian);357 break;358 case dwarf::DW_FORM_data4:359 case dwarf::DW_FORM_ref4:360 case dwarf::DW_FORM_ref_sup4:361 case dwarf::DW_FORM_strx4:362 case dwarf::DW_FORM_addrx4:363 writeInteger((uint32_t)FormVal->Value, OS, IsLittleEndian);364 break;365 case dwarf::DW_FORM_data8:366 case dwarf::DW_FORM_ref8:367 case dwarf::DW_FORM_ref_sup8:368 case dwarf::DW_FORM_ref_sig8:369 writeInteger((uint64_t)FormVal->Value, OS, IsLittleEndian);370 break;371 case dwarf::DW_FORM_sdata:372 encodeSLEB128(FormVal->Value, OS);373 break;374 case dwarf::DW_FORM_string:375 OS.write(FormVal->CStr.data(), FormVal->CStr.size());376 OS.write('\0');377 break;378 case dwarf::DW_FORM_indirect:379 encodeULEB128(FormVal->Value, OS);380 Indirect = true;381 Form = static_cast<dwarf::Form>((uint64_t)FormVal->Value);382 ++FormVal;383 break;384 case dwarf::DW_FORM_strp:385 case dwarf::DW_FORM_sec_offset:386 case dwarf::DW_FORM_GNU_ref_alt:387 case dwarf::DW_FORM_GNU_strp_alt:388 case dwarf::DW_FORM_line_strp:389 case dwarf::DW_FORM_strp_sup:390 cantFail(writeVariableSizedInteger(FormVal->Value,391 Params.getDwarfOffsetByteSize(), OS,392 IsLittleEndian));393 break;394 default:395 break;396 }397 } while (Indirect);398 }399 400 return OS.tell() - EntryBegin;401}402 403Error DWARFYAML::emitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) {404 for (uint64_t I = 0; I < DI.Units.size(); ++I) {405 const DWARFYAML::Unit &Unit = DI.Units[I];406 uint8_t AddrSize;407 if (Unit.AddrSize)408 AddrSize = *Unit.AddrSize;409 else410 AddrSize = DI.Is64BitAddrSize ? 8 : 4;411 dwarf::FormParams Params = {Unit.Version, AddrSize, Unit.Format};412 uint64_t Length = 3; // sizeof(version) + sizeof(address_size)413 Length += Params.getDwarfOffsetByteSize(); // sizeof(debug_abbrev_offset)414 if (Unit.Version >= 5) {415 ++Length; // sizeof(unit_type)416 switch (Unit.Type) {417 case dwarf::DW_UT_compile:418 case dwarf::DW_UT_partial:419 default:420 break;421 case dwarf::DW_UT_type:422 case dwarf::DW_UT_split_type:423 // sizeof(type_signature) + sizeof(type_offset)424 Length += 8 + Params.getDwarfOffsetByteSize();425 break;426 case dwarf::DW_UT_skeleton:427 case dwarf::DW_UT_split_compile:428 Length += 8; // sizeof(dwo_id)429 }430 }431 432 // Since the length of the current compilation unit is undetermined yet, we433 // firstly write the content of the compilation unit to a buffer to434 // calculate it and then serialize the buffer content to the actual output435 // stream.436 std::string EntryBuffer;437 raw_string_ostream EntryBufferOS(EntryBuffer);438 439 uint64_t AbbrevTableID = Unit.AbbrevTableID.value_or(I);440 for (const DWARFYAML::Entry &Entry : Unit.Entries) {441 if (Expected<uint64_t> EntryLength =442 writeDIE(DI, I, AbbrevTableID, Params, Entry, EntryBufferOS,443 DI.IsLittleEndian))444 Length += *EntryLength;445 else446 return EntryLength.takeError();447 }448 449 // If the length is specified in the YAML description, we use it instead of450 // the actual length.451 if (Unit.Length)452 Length = *Unit.Length;453 454 writeInitialLength(Unit.Format, Length, OS, DI.IsLittleEndian);455 writeInteger((uint16_t)Unit.Version, OS, DI.IsLittleEndian);456 457 uint64_t AbbrevTableOffset = 0;458 if (Unit.AbbrOffset) {459 AbbrevTableOffset = *Unit.AbbrOffset;460 } else {461 if (Expected<DWARFYAML::Data::AbbrevTableInfo> AbbrevTableInfoOrErr =462 DI.getAbbrevTableInfoByID(AbbrevTableID)) {463 AbbrevTableOffset = AbbrevTableInfoOrErr->Offset;464 } else {465 // The current compilation unit may not have DIEs and it will not be466 // able to find the associated abbrev table. We consume the error and467 // assign 0 to the debug_abbrev_offset in such circumstances.468 consumeError(AbbrevTableInfoOrErr.takeError());469 }470 }471 472 if (Unit.Version >= 5) {473 writeInteger((uint8_t)Unit.Type, OS, DI.IsLittleEndian);474 writeInteger((uint8_t)AddrSize, OS, DI.IsLittleEndian);475 writeDWARFOffset(AbbrevTableOffset, Unit.Format, OS, DI.IsLittleEndian);476 switch (Unit.Type) {477 case dwarf::DW_UT_compile:478 case dwarf::DW_UT_partial:479 default:480 break;481 case dwarf::DW_UT_type:482 case dwarf::DW_UT_split_type:483 writeInteger(Unit.TypeSignatureOrDwoID, OS, DI.IsLittleEndian);484 writeDWARFOffset(Unit.TypeOffset, Unit.Format, OS, DI.IsLittleEndian);485 break;486 case dwarf::DW_UT_skeleton:487 case dwarf::DW_UT_split_compile:488 writeInteger(Unit.TypeSignatureOrDwoID, OS, DI.IsLittleEndian);489 break;490 }491 } else {492 writeDWARFOffset(AbbrevTableOffset, Unit.Format, OS, DI.IsLittleEndian);493 writeInteger((uint8_t)AddrSize, OS, DI.IsLittleEndian);494 }495 496 OS.write(EntryBuffer.data(), EntryBuffer.size());497 }498 499 return Error::success();500}501 502static void emitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) {503 OS.write(File.Name.data(), File.Name.size());504 OS.write('\0');505 encodeULEB128(File.DirIdx, OS);506 encodeULEB128(File.ModTime, OS);507 encodeULEB128(File.Length, OS);508}509 510static void writeExtendedOpcode(const DWARFYAML::LineTableOpcode &Op,511 uint8_t AddrSize, bool IsLittleEndian,512 raw_ostream &OS) {513 // The first byte of extended opcodes is a zero byte. The next bytes are an514 // ULEB128 integer giving the number of bytes in the instruction itself (does515 // not include the first zero byte or the size). We serialize the instruction516 // itself into the OpBuffer and then write the size of the buffer and the517 // buffer to the real output stream.518 std::string OpBuffer;519 raw_string_ostream OpBufferOS(OpBuffer);520 writeInteger((uint8_t)Op.SubOpcode, OpBufferOS, IsLittleEndian);521 switch (Op.SubOpcode) {522 case dwarf::DW_LNE_set_address:523 cantFail(writeVariableSizedInteger(Op.Data, AddrSize, OpBufferOS,524 IsLittleEndian));525 break;526 case dwarf::DW_LNE_define_file:527 emitFileEntry(OpBufferOS, Op.FileEntry);528 break;529 case dwarf::DW_LNE_set_discriminator:530 encodeULEB128(Op.Data, OpBufferOS);531 break;532 case dwarf::DW_LNE_end_sequence:533 break;534 default:535 for (auto OpByte : Op.UnknownOpcodeData)536 writeInteger((uint8_t)OpByte, OpBufferOS, IsLittleEndian);537 }538 uint64_t ExtLen = Op.ExtLen.value_or(OpBuffer.size());539 encodeULEB128(ExtLen, OS);540 OS.write(OpBuffer.data(), OpBuffer.size());541}542 543static void writeLineTableOpcode(const DWARFYAML::LineTableOpcode &Op,544 uint8_t OpcodeBase, uint8_t AddrSize,545 raw_ostream &OS, bool IsLittleEndian) {546 writeInteger((uint8_t)Op.Opcode, OS, IsLittleEndian);547 if (Op.Opcode == 0) {548 writeExtendedOpcode(Op, AddrSize, IsLittleEndian, OS);549 } else if (Op.Opcode < OpcodeBase) {550 switch (Op.Opcode) {551 case dwarf::DW_LNS_copy:552 case dwarf::DW_LNS_negate_stmt:553 case dwarf::DW_LNS_set_basic_block:554 case dwarf::DW_LNS_const_add_pc:555 case dwarf::DW_LNS_set_prologue_end:556 case dwarf::DW_LNS_set_epilogue_begin:557 break;558 559 case dwarf::DW_LNS_advance_pc:560 case dwarf::DW_LNS_set_file:561 case dwarf::DW_LNS_set_column:562 case dwarf::DW_LNS_set_isa:563 encodeULEB128(Op.Data, OS);564 break;565 566 case dwarf::DW_LNS_advance_line:567 encodeSLEB128(Op.SData, OS);568 break;569 570 case dwarf::DW_LNS_fixed_advance_pc:571 writeInteger((uint16_t)Op.Data, OS, IsLittleEndian);572 break;573 574 default:575 for (auto OpData : Op.StandardOpcodeData) {576 encodeULEB128(OpData, OS);577 }578 }579 }580}581 582static std::vector<uint8_t>583getStandardOpcodeLengths(uint16_t Version, std::optional<uint8_t> OpcodeBase) {584 // If the opcode_base field isn't specified, we returns the585 // standard_opcode_lengths array according to the version by default.586 std::vector<uint8_t> StandardOpcodeLengths{0, 1, 1, 1, 1, 0,587 0, 0, 1, 0, 0, 1};588 if (Version == 2) {589 // DWARF v2 uses the same first 9 standard opcodes as v3-5.590 StandardOpcodeLengths.resize(9);591 } else if (OpcodeBase) {592 StandardOpcodeLengths.resize(*OpcodeBase > 0 ? *OpcodeBase - 1 : 0, 0);593 }594 return StandardOpcodeLengths;595}596 597Error DWARFYAML::emitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) {598 for (const DWARFYAML::LineTable &LineTable : DI.DebugLines) {599 // Buffer holds the bytes following the header_length (or prologue_length in600 // DWARFv2) field to the end of the line number program itself.601 std::string Buffer;602 raw_string_ostream BufferOS(Buffer);603 604 writeInteger(LineTable.MinInstLength, BufferOS, DI.IsLittleEndian);605 // TODO: Add support for emitting DWARFv5 line table.606 if (LineTable.Version >= 4)607 writeInteger(LineTable.MaxOpsPerInst, BufferOS, DI.IsLittleEndian);608 writeInteger(LineTable.DefaultIsStmt, BufferOS, DI.IsLittleEndian);609 writeInteger(LineTable.LineBase, BufferOS, DI.IsLittleEndian);610 writeInteger(LineTable.LineRange, BufferOS, DI.IsLittleEndian);611 612 std::vector<uint8_t> StandardOpcodeLengths =613 LineTable.StandardOpcodeLengths.value_or(614 getStandardOpcodeLengths(LineTable.Version, LineTable.OpcodeBase));615 uint8_t OpcodeBase = LineTable.OpcodeBase616 ? *LineTable.OpcodeBase617 : StandardOpcodeLengths.size() + 1;618 writeInteger(OpcodeBase, BufferOS, DI.IsLittleEndian);619 for (uint8_t OpcodeLength : StandardOpcodeLengths)620 writeInteger(OpcodeLength, BufferOS, DI.IsLittleEndian);621 622 for (StringRef IncludeDir : LineTable.IncludeDirs) {623 BufferOS.write(IncludeDir.data(), IncludeDir.size());624 BufferOS.write('\0');625 }626 BufferOS.write('\0');627 628 for (const DWARFYAML::File &File : LineTable.Files)629 emitFileEntry(BufferOS, File);630 BufferOS.write('\0');631 632 uint64_t HeaderLength =633 LineTable.PrologueLength ? *LineTable.PrologueLength : Buffer.size();634 635 for (const DWARFYAML::LineTableOpcode &Op : LineTable.Opcodes)636 writeLineTableOpcode(Op, OpcodeBase, DI.Is64BitAddrSize ? 8 : 4, BufferOS,637 DI.IsLittleEndian);638 639 uint64_t Length;640 if (LineTable.Length) {641 Length = *LineTable.Length;642 } else {643 Length = 2; // sizeof(version)644 Length +=645 (LineTable.Format == dwarf::DWARF64 ? 8 : 4); // sizeof(header_length)646 Length += Buffer.size();647 }648 649 writeInitialLength(LineTable.Format, Length, OS, DI.IsLittleEndian);650 writeInteger(LineTable.Version, OS, DI.IsLittleEndian);651 writeDWARFOffset(HeaderLength, LineTable.Format, OS, DI.IsLittleEndian);652 OS.write(Buffer.data(), Buffer.size());653 }654 655 return Error::success();656}657 658Error DWARFYAML::emitDebugAddr(raw_ostream &OS, const Data &DI) {659 for (const AddrTableEntry &TableEntry : *DI.DebugAddr) {660 uint8_t AddrSize;661 if (TableEntry.AddrSize)662 AddrSize = *TableEntry.AddrSize;663 else664 AddrSize = DI.Is64BitAddrSize ? 8 : 4;665 666 uint64_t Length;667 if (TableEntry.Length)668 Length = (uint64_t)*TableEntry.Length;669 else670 // 2 (version) + 1 (address_size) + 1 (segment_selector_size) = 4671 Length = 4 + (AddrSize + TableEntry.SegSelectorSize) *672 TableEntry.SegAddrPairs.size();673 674 writeInitialLength(TableEntry.Format, Length, OS, DI.IsLittleEndian);675 writeInteger((uint16_t)TableEntry.Version, OS, DI.IsLittleEndian);676 writeInteger((uint8_t)AddrSize, OS, DI.IsLittleEndian);677 writeInteger((uint8_t)TableEntry.SegSelectorSize, OS, DI.IsLittleEndian);678 679 for (const SegAddrPair &Pair : TableEntry.SegAddrPairs) {680 if (TableEntry.SegSelectorSize != yaml::Hex8{0})681 if (Error Err = writeVariableSizedInteger(Pair.Segment,682 TableEntry.SegSelectorSize,683 OS, DI.IsLittleEndian))684 return createStringError(errc::not_supported,685 "unable to write debug_addr segment: %s",686 toString(std::move(Err)).c_str());687 if (AddrSize != 0)688 if (Error Err = writeVariableSizedInteger(Pair.Address, AddrSize, OS,689 DI.IsLittleEndian))690 return createStringError(errc::not_supported,691 "unable to write debug_addr address: %s",692 toString(std::move(Err)).c_str());693 }694 }695 696 return Error::success();697}698 699Error DWARFYAML::emitDebugStrOffsets(raw_ostream &OS, const Data &DI) {700 assert(DI.DebugStrOffsets && "unexpected emitDebugStrOffsets() call");701 for (const DWARFYAML::StringOffsetsTable &Table : *DI.DebugStrOffsets) {702 uint64_t Length;703 if (Table.Length)704 Length = *Table.Length;705 else706 // sizeof(version) + sizeof(padding) = 4707 Length =708 4 + Table.Offsets.size() * (Table.Format == dwarf::DWARF64 ? 8 : 4);709 710 writeInitialLength(Table.Format, Length, OS, DI.IsLittleEndian);711 writeInteger((uint16_t)Table.Version, OS, DI.IsLittleEndian);712 writeInteger((uint16_t)Table.Padding, OS, DI.IsLittleEndian);713 714 for (uint64_t Offset : Table.Offsets)715 writeDWARFOffset(Offset, Table.Format, OS, DI.IsLittleEndian);716 }717 718 return Error::success();719}720 721namespace {722/// Emits the header for a DebugNames section.723void emitDebugNamesHeader(raw_ostream &OS, bool IsLittleEndian,724 uint32_t NameCount, uint32_t AbbrevSize,725 uint32_t CombinedSizeOtherParts) {726 // Use the same AugmentationString as AsmPrinter.727 StringRef AugmentationString = "LLVM0700";728 size_t TotalSize = CombinedSizeOtherParts + 5 * sizeof(uint32_t) +729 2 * sizeof(uint16_t) + sizeof(NameCount) +730 sizeof(AbbrevSize) + AugmentationString.size();731 writeInteger(uint32_t(TotalSize), OS, IsLittleEndian); // Unit length732 733 // Everything below is included in total size.734 writeInteger(uint16_t(5), OS, IsLittleEndian); // Version735 writeInteger(uint16_t(0), OS, IsLittleEndian); // Padding736 writeInteger(uint32_t(1), OS, IsLittleEndian); // Compilation Unit count737 writeInteger(uint32_t(0), OS, IsLittleEndian); // Local Type Unit count738 writeInteger(uint32_t(0), OS, IsLittleEndian); // Foreign Type Unit count739 writeInteger(uint32_t(0), OS, IsLittleEndian); // Bucket count740 writeInteger(NameCount, OS, IsLittleEndian);741 writeInteger(AbbrevSize, OS, IsLittleEndian);742 writeInteger(uint32_t(AugmentationString.size()), OS, IsLittleEndian);743 OS.write(AugmentationString.data(), AugmentationString.size());744}745 746/// Emits the abbreviations for a DebugNames section.747std::string748emitDebugNamesAbbrev(ArrayRef<DWARFYAML::DebugNameAbbreviation> Abbrevs) {749 std::string Data;750 raw_string_ostream OS(Data);751 for (const DWARFYAML::DebugNameAbbreviation &Abbrev : Abbrevs) {752 encodeULEB128(Abbrev.Code, OS);753 encodeULEB128(Abbrev.Tag, OS);754 for (auto [Idx, Form] : Abbrev.Indices) {755 encodeULEB128(Idx, OS);756 encodeULEB128(Form, OS);757 }758 encodeULEB128(0, OS);759 encodeULEB128(0, OS);760 }761 encodeULEB128(0, OS);762 return Data;763}764 765/// Emits a simple CU offsets list for a DebugNames section containing a single766/// CU at offset 0.767std::string emitDebugNamesCUOffsets(bool IsLittleEndian) {768 std::string Data;769 raw_string_ostream OS(Data);770 writeInteger(uint32_t(0), OS, IsLittleEndian);771 return Data;772}773 774/// Emits the "NameTable" for a DebugNames section; according to the spec, it775/// consists of two arrays: an array of string offsets, followed immediately by776/// an array of entry offsets. The string offsets are emitted in the order777/// provided in `Entries`.778std::string emitDebugNamesNameTable(779 bool IsLittleEndian,780 const DenseMap<uint32_t, std::vector<DWARFYAML::DebugNameEntry>> &Entries,781 ArrayRef<uint32_t> EntryPoolOffsets) {782 assert(Entries.size() == EntryPoolOffsets.size());783 784 std::string Data;785 raw_string_ostream OS(Data);786 787 for (uint32_t Strp : make_first_range(Entries))788 writeInteger(Strp, OS, IsLittleEndian);789 for (uint32_t PoolOffset : EntryPoolOffsets)790 writeInteger(PoolOffset, OS, IsLittleEndian);791 return Data;792}793 794/// Groups entries based on their name (strp) code and returns a map.795DenseMap<uint32_t, std::vector<DWARFYAML::DebugNameEntry>>796groupEntries(ArrayRef<DWARFYAML::DebugNameEntry> Entries) {797 DenseMap<uint32_t, std::vector<DWARFYAML::DebugNameEntry>> StrpToEntries;798 for (const DWARFYAML::DebugNameEntry &Entry : Entries)799 StrpToEntries[Entry.NameStrp].push_back(Entry);800 return StrpToEntries;801}802 803/// Finds the abbreviation whose code is AbbrevCode and returns a list804/// containing the expected size of all non-zero-length forms.805Expected<SmallVector<uint8_t>>806getNonZeroDataSizesFor(uint32_t AbbrevCode,807 ArrayRef<DWARFYAML::DebugNameAbbreviation> Abbrevs) {808 const auto *AbbrevIt = find_if(Abbrevs, [&](const auto &Abbrev) {809 return Abbrev.Code.value == AbbrevCode;810 });811 if (AbbrevIt == Abbrevs.end())812 return createStringError(inconvertibleErrorCode(),813 "did not find an Abbreviation for this code");814 815 SmallVector<uint8_t> DataSizes;816 dwarf::FormParams Params{/*Version=*/5, /*AddrSize=*/4, dwarf::DWARF32};817 for (auto [Idx, Form] : AbbrevIt->Indices) {818 std::optional<uint8_t> FormSize = dwarf::getFixedFormByteSize(Form, Params);819 if (!FormSize)820 return createStringError(inconvertibleErrorCode(),821 "unsupported Form for YAML debug_names emitter");822 if (FormSize == 0)823 continue;824 DataSizes.push_back(*FormSize);825 }826 return DataSizes;827}828 829struct PoolOffsetsAndData {830 std::string PoolData;831 std::vector<uint32_t> PoolOffsets;832};833 834/// Emits the entry pool and returns an array of offsets containing the start835/// offset for the entries of each unique name.836/// Verifies that the provided number of data values match those expected by837/// the abbreviation table.838Expected<PoolOffsetsAndData> emitDebugNamesEntryPool(839 bool IsLittleEndian,840 const DenseMap<uint32_t, std::vector<DWARFYAML::DebugNameEntry>>841 &StrpToEntries,842 ArrayRef<DWARFYAML::DebugNameAbbreviation> Abbrevs) {843 PoolOffsetsAndData Result;844 raw_string_ostream OS(Result.PoolData);845 846 for (ArrayRef<DWARFYAML::DebugNameEntry> EntriesWithSameName :847 make_second_range(StrpToEntries)) {848 Result.PoolOffsets.push_back(Result.PoolData.size());849 850 for (const DWARFYAML::DebugNameEntry &Entry : EntriesWithSameName) {851 encodeULEB128(Entry.Code, OS);852 853 Expected<SmallVector<uint8_t>> DataSizes =854 getNonZeroDataSizesFor(Entry.Code, Abbrevs);855 if (!DataSizes)856 return DataSizes.takeError();857 if (DataSizes->size() != Entry.Values.size())858 return createStringError(859 inconvertibleErrorCode(),860 "mismatch between provided and required number of values");861 862 for (auto [Value, ValueSize] : zip_equal(Entry.Values, *DataSizes))863 if (Error E =864 writeVariableSizedInteger(Value, ValueSize, OS, IsLittleEndian))865 return std::move(E);866 }867 encodeULEB128(0, OS);868 }869 870 return Result;871}872} // namespace873 874Error DWARFYAML::emitDebugNames(raw_ostream &OS, const Data &DI) {875 assert(DI.DebugNames && "unexpected emitDebugNames() call");876 const DebugNamesSection DebugNames = DI.DebugNames.value();877 878 DenseMap<uint32_t, std::vector<DebugNameEntry>> StrpToEntries =879 groupEntries(DebugNames.Entries);880 881 // Emit all sub-sections into individual strings so that we may compute882 // relative offsets and sizes.883 Expected<PoolOffsetsAndData> PoolInfo = emitDebugNamesEntryPool(884 DI.IsLittleEndian, StrpToEntries, DebugNames.Abbrevs);885 if (!PoolInfo)886 return PoolInfo.takeError();887 std::string NamesTableData = emitDebugNamesNameTable(888 DI.IsLittleEndian, StrpToEntries, PoolInfo->PoolOffsets);889 890 std::string AbbrevData = emitDebugNamesAbbrev(DebugNames.Abbrevs);891 std::string CUOffsetsData = emitDebugNamesCUOffsets(DI.IsLittleEndian);892 893 size_t TotalSize = PoolInfo->PoolData.size() + NamesTableData.size() +894 AbbrevData.size() + CUOffsetsData.size();895 896 // Start real emission by combining all individual strings.897 emitDebugNamesHeader(OS, DI.IsLittleEndian, StrpToEntries.size(),898 AbbrevData.size(), TotalSize);899 OS.write(CUOffsetsData.data(), CUOffsetsData.size());900 // No local TUs, no foreign TUs, no hash lookups table.901 OS.write(NamesTableData.data(), NamesTableData.size());902 OS.write(AbbrevData.data(), AbbrevData.size());903 OS.write(PoolInfo->PoolData.data(), PoolInfo->PoolData.size());904 905 return Error::success();906}907 908static Error checkOperandCount(StringRef EncodingString,909 ArrayRef<yaml::Hex64> Values,910 uint64_t ExpectedOperands) {911 if (Values.size() != ExpectedOperands)912 return createStringError(913 errc::invalid_argument,914 "invalid number (%zu) of operands for the operator: %s, %" PRIu64915 " expected",916 Values.size(), EncodingString.str().c_str(), ExpectedOperands);917 918 return Error::success();919}920 921static Error writeListEntryAddress(StringRef EncodingName, raw_ostream &OS,922 uint64_t Addr, uint8_t AddrSize,923 bool IsLittleEndian) {924 if (Error Err = writeVariableSizedInteger(Addr, AddrSize, OS, IsLittleEndian))925 return createStringError(errc::invalid_argument,926 "unable to write address for the operator %s: %s",927 EncodingName.str().c_str(),928 toString(std::move(Err)).c_str());929 930 return Error::success();931}932 933static Expected<uint64_t>934writeDWARFExpression(raw_ostream &OS,935 const DWARFYAML::DWARFOperation &Operation,936 uint8_t AddrSize, bool IsLittleEndian) {937 auto CheckOperands = [&](uint64_t ExpectedOperands) -> Error {938 return checkOperandCount(dwarf::OperationEncodingString(Operation.Operator),939 Operation.Values, ExpectedOperands);940 };941 942 uint64_t ExpressionBegin = OS.tell();943 writeInteger((uint8_t)Operation.Operator, OS, IsLittleEndian);944 switch (Operation.Operator) {945 case dwarf::DW_OP_consts:946 if (Error Err = CheckOperands(1))947 return std::move(Err);948 encodeSLEB128(Operation.Values[0], OS);949 break;950 case dwarf::DW_OP_stack_value:951 if (Error Err = CheckOperands(0))952 return std::move(Err);953 break;954 default:955 StringRef EncodingStr = dwarf::OperationEncodingString(Operation.Operator);956 return createStringError(errc::not_supported,957 "DWARF expression: " +958 (EncodingStr.empty()959 ? "0x" + utohexstr(Operation.Operator)960 : EncodingStr) +961 " is not supported");962 }963 return OS.tell() - ExpressionBegin;964}965 966static Expected<uint64_t> writeListEntry(raw_ostream &OS,967 const DWARFYAML::RnglistEntry &Entry,968 uint8_t AddrSize,969 bool IsLittleEndian) {970 uint64_t BeginOffset = OS.tell();971 writeInteger((uint8_t)Entry.Operator, OS, IsLittleEndian);972 973 StringRef EncodingName = dwarf::RangeListEncodingString(Entry.Operator);974 975 auto CheckOperands = [&](uint64_t ExpectedOperands) -> Error {976 return checkOperandCount(EncodingName, Entry.Values, ExpectedOperands);977 };978 979 auto WriteAddress = [&](uint64_t Addr) -> Error {980 return writeListEntryAddress(EncodingName, OS, Addr, AddrSize,981 IsLittleEndian);982 };983 984 switch (Entry.Operator) {985 case dwarf::DW_RLE_end_of_list:986 if (Error Err = CheckOperands(0))987 return std::move(Err);988 break;989 case dwarf::DW_RLE_base_addressx:990 if (Error Err = CheckOperands(1))991 return std::move(Err);992 encodeULEB128(Entry.Values[0], OS);993 break;994 case dwarf::DW_RLE_startx_endx:995 case dwarf::DW_RLE_startx_length:996 case dwarf::DW_RLE_offset_pair:997 if (Error Err = CheckOperands(2))998 return std::move(Err);999 encodeULEB128(Entry.Values[0], OS);1000 encodeULEB128(Entry.Values[1], OS);1001 break;1002 case dwarf::DW_RLE_base_address:1003 if (Error Err = CheckOperands(1))1004 return std::move(Err);1005 if (Error Err = WriteAddress(Entry.Values[0]))1006 return std::move(Err);1007 break;1008 case dwarf::DW_RLE_start_end:1009 if (Error Err = CheckOperands(2))1010 return std::move(Err);1011 if (Error Err = WriteAddress(Entry.Values[0]))1012 return std::move(Err);1013 cantFail(WriteAddress(Entry.Values[1]));1014 break;1015 case dwarf::DW_RLE_start_length:1016 if (Error Err = CheckOperands(2))1017 return std::move(Err);1018 if (Error Err = WriteAddress(Entry.Values[0]))1019 return std::move(Err);1020 encodeULEB128(Entry.Values[1], OS);1021 break;1022 }1023 1024 return OS.tell() - BeginOffset;1025}1026 1027static Expected<uint64_t> writeListEntry(raw_ostream &OS,1028 const DWARFYAML::LoclistEntry &Entry,1029 uint8_t AddrSize,1030 bool IsLittleEndian) {1031 uint64_t BeginOffset = OS.tell();1032 writeInteger((uint8_t)Entry.Operator, OS, IsLittleEndian);1033 1034 StringRef EncodingName = dwarf::LocListEncodingString(Entry.Operator);1035 1036 auto CheckOperands = [&](uint64_t ExpectedOperands) -> Error {1037 return checkOperandCount(EncodingName, Entry.Values, ExpectedOperands);1038 };1039 1040 auto WriteAddress = [&](uint64_t Addr) -> Error {1041 return writeListEntryAddress(EncodingName, OS, Addr, AddrSize,1042 IsLittleEndian);1043 };1044 1045 auto WriteDWARFOperations = [&]() -> Error {1046 std::string OpBuffer;1047 raw_string_ostream OpBufferOS(OpBuffer);1048 uint64_t DescriptionsLength = 0;1049 1050 for (const DWARFYAML::DWARFOperation &Op : Entry.Descriptions) {1051 if (Expected<uint64_t> OpSize =1052 writeDWARFExpression(OpBufferOS, Op, AddrSize, IsLittleEndian))1053 DescriptionsLength += *OpSize;1054 else1055 return OpSize.takeError();1056 }1057 1058 if (Entry.DescriptionsLength)1059 DescriptionsLength = *Entry.DescriptionsLength;1060 else1061 DescriptionsLength = OpBuffer.size();1062 1063 encodeULEB128(DescriptionsLength, OS);1064 OS.write(OpBuffer.data(), OpBuffer.size());1065 1066 return Error::success();1067 };1068 1069 switch (Entry.Operator) {1070 case dwarf::DW_LLE_end_of_list:1071 if (Error Err = CheckOperands(0))1072 return std::move(Err);1073 break;1074 case dwarf::DW_LLE_base_addressx:1075 if (Error Err = CheckOperands(1))1076 return std::move(Err);1077 encodeULEB128(Entry.Values[0], OS);1078 break;1079 case dwarf::DW_LLE_startx_endx:1080 case dwarf::DW_LLE_startx_length:1081 case dwarf::DW_LLE_offset_pair:1082 if (Error Err = CheckOperands(2))1083 return std::move(Err);1084 encodeULEB128(Entry.Values[0], OS);1085 encodeULEB128(Entry.Values[1], OS);1086 if (Error Err = WriteDWARFOperations())1087 return std::move(Err);1088 break;1089 case dwarf::DW_LLE_default_location:1090 if (Error Err = CheckOperands(0))1091 return std::move(Err);1092 if (Error Err = WriteDWARFOperations())1093 return std::move(Err);1094 break;1095 case dwarf::DW_LLE_base_address:1096 if (Error Err = CheckOperands(1))1097 return std::move(Err);1098 if (Error Err = WriteAddress(Entry.Values[0]))1099 return std::move(Err);1100 break;1101 case dwarf::DW_LLE_start_end:1102 if (Error Err = CheckOperands(2))1103 return std::move(Err);1104 if (Error Err = WriteAddress(Entry.Values[0]))1105 return std::move(Err);1106 cantFail(WriteAddress(Entry.Values[1]));1107 if (Error Err = WriteDWARFOperations())1108 return std::move(Err);1109 break;1110 case dwarf::DW_LLE_start_length:1111 if (Error Err = CheckOperands(2))1112 return std::move(Err);1113 if (Error Err = WriteAddress(Entry.Values[0]))1114 return std::move(Err);1115 encodeULEB128(Entry.Values[1], OS);1116 if (Error Err = WriteDWARFOperations())1117 return std::move(Err);1118 break;1119 }1120 1121 return OS.tell() - BeginOffset;1122}1123 1124template <typename EntryType>1125static Error writeDWARFLists(raw_ostream &OS,1126 ArrayRef<DWARFYAML::ListTable<EntryType>> Tables,1127 bool IsLittleEndian, bool Is64BitAddrSize) {1128 for (const DWARFYAML::ListTable<EntryType> &Table : Tables) {1129 // sizeof(version) + sizeof(address_size) + sizeof(segment_selector_size) +1130 // sizeof(offset_entry_count) = 81131 uint64_t Length = 8;1132 1133 uint8_t AddrSize;1134 if (Table.AddrSize)1135 AddrSize = *Table.AddrSize;1136 else1137 AddrSize = Is64BitAddrSize ? 8 : 4;1138 1139 // Since the length of the current range/location lists entry is1140 // undetermined yet, we firstly write the content of the range/location1141 // lists to a buffer to calculate the length and then serialize the buffer1142 // content to the actual output stream.1143 std::string ListBuffer;1144 raw_string_ostream ListBufferOS(ListBuffer);1145 1146 // Offsets holds offsets for each range/location list. The i-th element is1147 // the offset from the beginning of the first range/location list to the1148 // location of the i-th range list.1149 std::vector<uint64_t> Offsets;1150 1151 for (const DWARFYAML::ListEntries<EntryType> &List : Table.Lists) {1152 Offsets.push_back(ListBufferOS.tell());1153 if (List.Content) {1154 List.Content->writeAsBinary(ListBufferOS, UINT64_MAX);1155 Length += List.Content->binary_size();1156 } else if (List.Entries) {1157 for (const EntryType &Entry : *List.Entries) {1158 Expected<uint64_t> EntrySize =1159 writeListEntry(ListBufferOS, Entry, AddrSize, IsLittleEndian);1160 if (!EntrySize)1161 return EntrySize.takeError();1162 Length += *EntrySize;1163 }1164 }1165 }1166 1167 // If the offset_entry_count field isn't specified, yaml2obj will infer it1168 // from the 'Offsets' field in the YAML description. If the 'Offsets' field1169 // isn't specified either, yaml2obj will infer it from the auto-generated1170 // offsets.1171 uint32_t OffsetEntryCount;1172 if (Table.OffsetEntryCount)1173 OffsetEntryCount = *Table.OffsetEntryCount;1174 else1175 OffsetEntryCount = Table.Offsets ? Table.Offsets->size() : Offsets.size();1176 uint64_t OffsetsSize =1177 OffsetEntryCount * (Table.Format == dwarf::DWARF64 ? 8 : 4);1178 Length += OffsetsSize;1179 1180 // If the length is specified in the YAML description, we use it instead of1181 // the actual length.1182 if (Table.Length)1183 Length = *Table.Length;1184 1185 writeInitialLength(Table.Format, Length, OS, IsLittleEndian);1186 writeInteger((uint16_t)Table.Version, OS, IsLittleEndian);1187 writeInteger((uint8_t)AddrSize, OS, IsLittleEndian);1188 writeInteger((uint8_t)Table.SegSelectorSize, OS, IsLittleEndian);1189 writeInteger((uint32_t)OffsetEntryCount, OS, IsLittleEndian);1190 1191 auto EmitOffsets = [&](ArrayRef<uint64_t> Offsets, uint64_t OffsetsSize) {1192 for (uint64_t Offset : Offsets)1193 writeDWARFOffset(OffsetsSize + Offset, Table.Format, OS,1194 IsLittleEndian);1195 };1196 1197 if (Table.Offsets)1198 EmitOffsets(ArrayRef<uint64_t>((const uint64_t *)Table.Offsets->data(),1199 Table.Offsets->size()),1200 0);1201 else if (OffsetEntryCount != 0)1202 EmitOffsets(Offsets, OffsetsSize);1203 1204 OS.write(ListBuffer.data(), ListBuffer.size());1205 }1206 1207 return Error::success();1208}1209 1210Error DWARFYAML::emitDebugRnglists(raw_ostream &OS, const Data &DI) {1211 assert(DI.DebugRnglists && "unexpected emitDebugRnglists() call");1212 return writeDWARFLists<DWARFYAML::RnglistEntry>(1213 OS, *DI.DebugRnglists, DI.IsLittleEndian, DI.Is64BitAddrSize);1214}1215 1216Error DWARFYAML::emitDebugLoclists(raw_ostream &OS, const Data &DI) {1217 assert(DI.DebugLoclists && "unexpected emitDebugRnglists() call");1218 return writeDWARFLists<DWARFYAML::LoclistEntry>(1219 OS, *DI.DebugLoclists, DI.IsLittleEndian, DI.Is64BitAddrSize);1220}1221 1222std::function<Error(raw_ostream &, const DWARFYAML::Data &)>1223DWARFYAML::getDWARFEmitterByName(StringRef SecName) {1224 auto EmitFunc =1225 StringSwitch<1226 std::function<Error(raw_ostream &, const DWARFYAML::Data &)>>(SecName)1227 .Case("debug_abbrev", DWARFYAML::emitDebugAbbrev)1228 .Case("debug_addr", DWARFYAML::emitDebugAddr)1229 .Case("debug_aranges", DWARFYAML::emitDebugAranges)1230 .Case("debug_gnu_pubnames", DWARFYAML::emitDebugGNUPubnames)1231 .Case("debug_gnu_pubtypes", DWARFYAML::emitDebugGNUPubtypes)1232 .Case("debug_info", DWARFYAML::emitDebugInfo)1233 .Case("debug_line", DWARFYAML::emitDebugLine)1234 .Case("debug_loclists", DWARFYAML::emitDebugLoclists)1235 .Case("debug_pubnames", DWARFYAML::emitDebugPubnames)1236 .Case("debug_pubtypes", DWARFYAML::emitDebugPubtypes)1237 .Case("debug_ranges", DWARFYAML::emitDebugRanges)1238 .Case("debug_rnglists", DWARFYAML::emitDebugRnglists)1239 .Case("debug_str", DWARFYAML::emitDebugStr)1240 .Case("debug_str_offsets", DWARFYAML::emitDebugStrOffsets)1241 .Case("debug_names", DWARFYAML::emitDebugNames)1242 .Default([&](raw_ostream &, const DWARFYAML::Data &) {1243 return createStringError(errc::not_supported,1244 SecName + " is not supported");1245 });1246 1247 return EmitFunc;1248}1249 1250static Error1251emitDebugSectionImpl(const DWARFYAML::Data &DI, StringRef Sec,1252 StringMap<std::unique_ptr<MemoryBuffer>> &OutputBuffers) {1253 std::string Data;1254 raw_string_ostream DebugInfoStream(Data);1255 1256 auto EmitFunc = DWARFYAML::getDWARFEmitterByName(Sec);1257 1258 if (Error Err = EmitFunc(DebugInfoStream, DI))1259 return Err;1260 DebugInfoStream.flush();1261 if (!Data.empty())1262 OutputBuffers[Sec] = MemoryBuffer::getMemBufferCopy(Data);1263 1264 return Error::success();1265}1266 1267Expected<StringMap<std::unique_ptr<MemoryBuffer>>>1268DWARFYAML::emitDebugSections(StringRef YAMLString, bool IsLittleEndian,1269 bool Is64BitAddrSize) {1270 auto CollectDiagnostic = [](const SMDiagnostic &Diag, void *DiagContext) {1271 *static_cast<SMDiagnostic *>(DiagContext) = Diag;1272 };1273 1274 SMDiagnostic GeneratedDiag;1275 yaml::Input YIn(YAMLString, /*Ctxt=*/nullptr, CollectDiagnostic,1276 &GeneratedDiag);1277 1278 DWARFYAML::Data DI;1279 DI.IsLittleEndian = IsLittleEndian;1280 DI.Is64BitAddrSize = Is64BitAddrSize;1281 1282 YIn >> DI;1283 if (YIn.error())1284 return createStringError(YIn.error(), GeneratedDiag.getMessage());1285 1286 StringMap<std::unique_ptr<MemoryBuffer>> DebugSections;1287 Error Err = Error::success();1288 1289 for (StringRef SecName : DI.getNonEmptySectionNames())1290 Err = joinErrors(std::move(Err),1291 emitDebugSectionImpl(DI, SecName, DebugSections));1292 1293 if (Err)1294 return std::move(Err);1295 return std::move(DebugSections);1296}1297