mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
ae65e281f3
to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
379 lines
13 KiB
C++
379 lines
13 KiB
C++
//===- DWARFEmitter - Convert YAML to DWARF binary data -------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// The DWARF component of yaml2obj. Provided as library code for tests.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ObjectYAML/DWARFEmitter.h"
|
|
#include "DWARFVisitor.h"
|
|
#include "llvm/ADT/StringMap.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ObjectYAML/DWARFYAML.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/Host.h"
|
|
#include "llvm/Support/LEB128.h"
|
|
#include "llvm/Support/MathExtras.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/SwapByteOrder.h"
|
|
#include "llvm/Support/YAMLTraits.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace llvm;
|
|
|
|
template <typename T>
|
|
static void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian) {
|
|
if (IsLittleEndian != sys::IsLittleEndianHost)
|
|
sys::swapByteOrder(Integer);
|
|
OS.write(reinterpret_cast<char *>(&Integer), sizeof(T));
|
|
}
|
|
|
|
static void writeVariableSizedInteger(uint64_t Integer, size_t Size,
|
|
raw_ostream &OS, bool IsLittleEndian) {
|
|
if (8 == Size)
|
|
writeInteger((uint64_t)Integer, OS, IsLittleEndian);
|
|
else if (4 == Size)
|
|
writeInteger((uint32_t)Integer, OS, IsLittleEndian);
|
|
else if (2 == Size)
|
|
writeInteger((uint16_t)Integer, OS, IsLittleEndian);
|
|
else if (1 == Size)
|
|
writeInteger((uint8_t)Integer, OS, IsLittleEndian);
|
|
else
|
|
assert(false && "Invalid integer write size.");
|
|
}
|
|
|
|
static void ZeroFillBytes(raw_ostream &OS, size_t Size) {
|
|
std::vector<uint8_t> FillData;
|
|
FillData.insert(FillData.begin(), Size, 0);
|
|
OS.write(reinterpret_cast<char *>(FillData.data()), Size);
|
|
}
|
|
|
|
static void writeInitialLength(const DWARFYAML::InitialLength &Length,
|
|
raw_ostream &OS, bool IsLittleEndian) {
|
|
writeInteger((uint32_t)Length.TotalLength, OS, IsLittleEndian);
|
|
if (Length.isDWARF64())
|
|
writeInteger((uint64_t)Length.TotalLength64, OS, IsLittleEndian);
|
|
}
|
|
|
|
void DWARFYAML::EmitDebugStr(raw_ostream &OS, const DWARFYAML::Data &DI) {
|
|
for (auto Str : DI.DebugStrings) {
|
|
OS.write(Str.data(), Str.size());
|
|
OS.write('\0');
|
|
}
|
|
}
|
|
|
|
void DWARFYAML::EmitDebugAbbrev(raw_ostream &OS, const DWARFYAML::Data &DI) {
|
|
for (auto AbbrevDecl : DI.AbbrevDecls) {
|
|
encodeULEB128(AbbrevDecl.Code, OS);
|
|
encodeULEB128(AbbrevDecl.Tag, OS);
|
|
OS.write(AbbrevDecl.Children);
|
|
for (auto Attr : AbbrevDecl.Attributes) {
|
|
encodeULEB128(Attr.Attribute, OS);
|
|
encodeULEB128(Attr.Form, OS);
|
|
if (Attr.Form == dwarf::DW_FORM_implicit_const)
|
|
encodeSLEB128(Attr.Value, OS);
|
|
}
|
|
encodeULEB128(0, OS);
|
|
encodeULEB128(0, OS);
|
|
}
|
|
}
|
|
|
|
void DWARFYAML::EmitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) {
|
|
for (auto Range : DI.ARanges) {
|
|
auto HeaderStart = OS.tell();
|
|
writeInitialLength(Range.Length, OS, DI.IsLittleEndian);
|
|
writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian);
|
|
writeInteger((uint32_t)Range.CuOffset, OS, DI.IsLittleEndian);
|
|
writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian);
|
|
writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian);
|
|
|
|
auto HeaderSize = OS.tell() - HeaderStart;
|
|
auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2);
|
|
ZeroFillBytes(OS, FirstDescriptor - HeaderSize);
|
|
|
|
for (auto Descriptor : Range.Descriptors) {
|
|
writeVariableSizedInteger(Descriptor.Address, Range.AddrSize, OS,
|
|
DI.IsLittleEndian);
|
|
writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS,
|
|
DI.IsLittleEndian);
|
|
}
|
|
ZeroFillBytes(OS, Range.AddrSize * 2);
|
|
}
|
|
}
|
|
|
|
void DWARFYAML::EmitPubSection(raw_ostream &OS,
|
|
const DWARFYAML::PubSection &Sect,
|
|
bool IsLittleEndian) {
|
|
writeInitialLength(Sect.Length, OS, IsLittleEndian);
|
|
writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian);
|
|
writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian);
|
|
writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian);
|
|
for (auto Entry : Sect.Entries) {
|
|
writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian);
|
|
if (Sect.IsGNUStyle)
|
|
writeInteger((uint32_t)Entry.Descriptor, OS, IsLittleEndian);
|
|
OS.write(Entry.Name.data(), Entry.Name.size());
|
|
OS.write('\0');
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
/// An extension of the DWARFYAML::ConstVisitor which writes compile
|
|
/// units and DIEs to a stream.
|
|
class DumpVisitor : public DWARFYAML::ConstVisitor {
|
|
raw_ostream &OS;
|
|
|
|
protected:
|
|
void onStartCompileUnit(const DWARFYAML::Unit &CU) override {
|
|
writeInitialLength(CU.Length, OS, DebugInfo.IsLittleEndian);
|
|
writeInteger((uint16_t)CU.Version, OS, DebugInfo.IsLittleEndian);
|
|
if(CU.Version >= 5) {
|
|
writeInteger((uint8_t)CU.Type, OS, DebugInfo.IsLittleEndian);
|
|
writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian);
|
|
writeInteger((uint32_t)CU.AbbrOffset, OS, DebugInfo.IsLittleEndian);
|
|
}else {
|
|
writeInteger((uint32_t)CU.AbbrOffset, OS, DebugInfo.IsLittleEndian);
|
|
writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian);
|
|
}
|
|
}
|
|
|
|
void onStartDIE(const DWARFYAML::Unit &CU,
|
|
const DWARFYAML::Entry &DIE) override {
|
|
encodeULEB128(DIE.AbbrCode, OS);
|
|
}
|
|
|
|
void onValue(const uint8_t U) override {
|
|
writeInteger(U, OS, DebugInfo.IsLittleEndian);
|
|
}
|
|
|
|
void onValue(const uint16_t U) override {
|
|
writeInteger(U, OS, DebugInfo.IsLittleEndian);
|
|
}
|
|
|
|
void onValue(const uint32_t U) override {
|
|
writeInteger(U, OS, DebugInfo.IsLittleEndian);
|
|
}
|
|
|
|
void onValue(const uint64_t U, const bool LEB = false) override {
|
|
if (LEB)
|
|
encodeULEB128(U, OS);
|
|
else
|
|
writeInteger(U, OS, DebugInfo.IsLittleEndian);
|
|
}
|
|
|
|
void onValue(const int64_t S, const bool LEB = false) override {
|
|
if (LEB)
|
|
encodeSLEB128(S, OS);
|
|
else
|
|
writeInteger(S, OS, DebugInfo.IsLittleEndian);
|
|
}
|
|
|
|
void onValue(const StringRef String) override {
|
|
OS.write(String.data(), String.size());
|
|
OS.write('\0');
|
|
}
|
|
|
|
void onValue(const MemoryBufferRef MBR) override {
|
|
OS.write(MBR.getBufferStart(), MBR.getBufferSize());
|
|
}
|
|
|
|
public:
|
|
DumpVisitor(const DWARFYAML::Data &DI, raw_ostream &Out)
|
|
: DWARFYAML::ConstVisitor(DI), OS(Out) {}
|
|
};
|
|
} // namespace
|
|
|
|
void DWARFYAML::EmitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) {
|
|
DumpVisitor Visitor(DI, OS);
|
|
Visitor.traverseDebugInfo();
|
|
}
|
|
|
|
static void EmitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) {
|
|
OS.write(File.Name.data(), File.Name.size());
|
|
OS.write('\0');
|
|
encodeULEB128(File.DirIdx, OS);
|
|
encodeULEB128(File.ModTime, OS);
|
|
encodeULEB128(File.Length, OS);
|
|
}
|
|
|
|
void DWARFYAML::EmitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) {
|
|
for (const auto &LineTable : DI.DebugLines) {
|
|
writeInitialLength(LineTable.Length, OS, DI.IsLittleEndian);
|
|
uint64_t SizeOfPrologueLength = LineTable.Length.isDWARF64() ? 8 : 4;
|
|
writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian);
|
|
writeVariableSizedInteger(LineTable.PrologueLength, SizeOfPrologueLength,
|
|
OS, DI.IsLittleEndian);
|
|
writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian);
|
|
if (LineTable.Version >= 4)
|
|
writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian);
|
|
writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian);
|
|
writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian);
|
|
writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian);
|
|
writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian);
|
|
|
|
for (auto OpcodeLength : LineTable.StandardOpcodeLengths)
|
|
writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian);
|
|
|
|
for (auto IncludeDir : LineTable.IncludeDirs) {
|
|
OS.write(IncludeDir.data(), IncludeDir.size());
|
|
OS.write('\0');
|
|
}
|
|
OS.write('\0');
|
|
|
|
for (auto File : LineTable.Files)
|
|
EmitFileEntry(OS, File);
|
|
OS.write('\0');
|
|
|
|
for (auto Op : LineTable.Opcodes) {
|
|
writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian);
|
|
if (Op.Opcode == 0) {
|
|
encodeULEB128(Op.ExtLen, OS);
|
|
writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian);
|
|
switch (Op.SubOpcode) {
|
|
case dwarf::DW_LNE_set_address:
|
|
case dwarf::DW_LNE_set_discriminator:
|
|
writeVariableSizedInteger(Op.Data, DI.CompileUnits[0].AddrSize, OS,
|
|
DI.IsLittleEndian);
|
|
break;
|
|
case dwarf::DW_LNE_define_file:
|
|
EmitFileEntry(OS, Op.FileEntry);
|
|
break;
|
|
case dwarf::DW_LNE_end_sequence:
|
|
break;
|
|
default:
|
|
for (auto OpByte : Op.UnknownOpcodeData)
|
|
writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian);
|
|
}
|
|
} else if (Op.Opcode < LineTable.OpcodeBase) {
|
|
switch (Op.Opcode) {
|
|
case dwarf::DW_LNS_copy:
|
|
case dwarf::DW_LNS_negate_stmt:
|
|
case dwarf::DW_LNS_set_basic_block:
|
|
case dwarf::DW_LNS_const_add_pc:
|
|
case dwarf::DW_LNS_set_prologue_end:
|
|
case dwarf::DW_LNS_set_epilogue_begin:
|
|
break;
|
|
|
|
case dwarf::DW_LNS_advance_pc:
|
|
case dwarf::DW_LNS_set_file:
|
|
case dwarf::DW_LNS_set_column:
|
|
case dwarf::DW_LNS_set_isa:
|
|
encodeULEB128(Op.Data, OS);
|
|
break;
|
|
|
|
case dwarf::DW_LNS_advance_line:
|
|
encodeSLEB128(Op.SData, OS);
|
|
break;
|
|
|
|
case dwarf::DW_LNS_fixed_advance_pc:
|
|
writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian);
|
|
break;
|
|
|
|
default:
|
|
for (auto OpData : Op.StandardOpcodeData) {
|
|
encodeULEB128(OpData, OS);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
using EmitFuncType = void (*)(raw_ostream &, const DWARFYAML::Data &);
|
|
|
|
static void
|
|
EmitDebugSectionImpl(const DWARFYAML::Data &DI, EmitFuncType EmitFunc,
|
|
StringRef Sec,
|
|
StringMap<std::unique_ptr<MemoryBuffer>> &OutputBuffers) {
|
|
std::string Data;
|
|
raw_string_ostream DebugInfoStream(Data);
|
|
EmitFunc(DebugInfoStream, DI);
|
|
DebugInfoStream.flush();
|
|
if (!Data.empty())
|
|
OutputBuffers[Sec] = MemoryBuffer::getMemBufferCopy(Data);
|
|
}
|
|
|
|
namespace {
|
|
class DIEFixupVisitor : public DWARFYAML::Visitor {
|
|
uint64_t Length;
|
|
|
|
public:
|
|
DIEFixupVisitor(DWARFYAML::Data &DI) : DWARFYAML::Visitor(DI){};
|
|
|
|
private:
|
|
virtual void onStartCompileUnit(DWARFYAML::Unit &CU) { Length = 7; }
|
|
|
|
virtual void onEndCompileUnit(DWARFYAML::Unit &CU) {
|
|
CU.Length.setLength(Length);
|
|
}
|
|
|
|
virtual void onStartDIE(DWARFYAML::Unit &CU, DWARFYAML::Entry &DIE) {
|
|
Length += getULEB128Size(DIE.AbbrCode);
|
|
}
|
|
|
|
virtual void onValue(const uint8_t U) { Length += 1; }
|
|
virtual void onValue(const uint16_t U) { Length += 2; }
|
|
virtual void onValue(const uint32_t U) { Length += 4; }
|
|
virtual void onValue(const uint64_t U, const bool LEB = false) {
|
|
if (LEB)
|
|
Length += getULEB128Size(U);
|
|
else
|
|
Length += 8;
|
|
}
|
|
virtual void onValue(const int64_t S, const bool LEB = false) {
|
|
if (LEB)
|
|
Length += getSLEB128Size(S);
|
|
else
|
|
Length += 8;
|
|
}
|
|
virtual void onValue(const StringRef String) { Length += String.size() + 1; }
|
|
|
|
virtual void onValue(const MemoryBufferRef MBR) {
|
|
Length += MBR.getBufferSize();
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
Expected<StringMap<std::unique_ptr<MemoryBuffer>>>
|
|
DWARFYAML::EmitDebugSections(StringRef YAMLString, bool ApplyFixups,
|
|
bool IsLittleEndian) {
|
|
yaml::Input YIn(YAMLString);
|
|
|
|
DWARFYAML::Data DI;
|
|
DI.IsLittleEndian = IsLittleEndian;
|
|
YIn >> DI;
|
|
if (YIn.error())
|
|
return errorCodeToError(YIn.error());
|
|
|
|
if (ApplyFixups) {
|
|
DIEFixupVisitor DIFixer(DI);
|
|
DIFixer.traverseDebugInfo();
|
|
}
|
|
|
|
StringMap<std::unique_ptr<MemoryBuffer>> DebugSections;
|
|
EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugInfo, "debug_info",
|
|
DebugSections);
|
|
EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugLine, "debug_line",
|
|
DebugSections);
|
|
EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugStr, "debug_str",
|
|
DebugSections);
|
|
EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAbbrev, "debug_abbrev",
|
|
DebugSections);
|
|
EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAranges, "debug_aranges",
|
|
DebugSections);
|
|
return std::move(DebugSections);
|
|
}
|