1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[DebugInfo] Add interface for pre-calculating the size of emitted DWARF

Summary:
DWARF's DW_OP_entry_value operation has two operands; the first is a
ULEB128 operand that specifies the size of the second operand, which is
a DWARF block. This means that we need to be able to pre-calculate and
emit the size of DWARF expressions before emitting them. There is
currently no interface for doing this in DwarfExpression, so this patch
introduces that.

When implementing this I initially thought about running through
DwarfExpression's emission two times; first with a temporary buffer to
emit the expression, in order to being able to calculate the size of
that emitted data. However, DwarfExpression is a quite complex state
machine, so I decided against that, as it seemed like the two runs could
get out of sync, resulting in incorrect size operands. Therefore I have
implemented this in a way that we only have to run DwarfExpression once.
The idea is to emit DWARF to a temporary buffer, for which it is
possible to query the size. The data in the temporary buffer can then be
emitted to DwarfExpression's main output.

In the case of DIEDwarfExpression, a temporary DIE is used. The values
are all allocated using the same BumpPtrAllocator as for all other DIEs,
and the values are then transferred to the real value list. In the case
of DebugLocDwarfExpression, the temporary buffer is implemented using a
BufferByteStreamer which emits to a buffer in the DwarfExpression
object.

Reviewers: aprantl, vsk, NikolaPrica, djtodoro

Reviewed By: aprantl

Subscribers: hiraditya, llvm-commits

Tags: #debug-info, #llvm

Differential Revision: https://reviews.llvm.org/D67768

llvm-svn: 374879
This commit is contained in:
David Stenberg 2019-10-15 11:14:35 +00:00
parent aa3c21eb76
commit dd39b25648
5 changed files with 130 additions and 27 deletions

View File

@ -550,6 +550,14 @@ public:
return *static_cast<T *>(Last ? Last->Next.getPointer() : nullptr);
}
void takeNodes(IntrusiveBackList<T> &Other) {
for (auto &N : Other) {
N.Next.setPointerAndInt(&N, true);
push_back(N);
}
Other.Last = nullptr;
}
class const_iterator;
class iterator
: public iterator_facade_base<iterator, std::forward_iterator_tag, T> {
@ -685,6 +693,10 @@ public:
return addValue(Alloc, DIEValue(Attribute, Form, std::forward<T>(Value)));
}
/// Take ownership of the nodes in \p Other, and append them to the back of
/// the list.
void takeValues(DIEValueList &Other) { List.takeNodes(Other.List); }
value_range values() {
return make_range(value_iterator(List.begin()), value_iterator(List.end()));
}

View File

@ -75,16 +75,16 @@ private:
SmallVectorImpl<char> &Buffer;
std::vector<std::string> &Comments;
public:
/// Only verbose textual output needs comments. This will be set to
/// true for that case, and false otherwise. If false, comments passed in to
/// the emit methods will be ignored.
bool GenerateComments;
const bool GenerateComments;
public:
BufferByteStreamer(SmallVectorImpl<char> &Buffer,
std::vector<std::string> &Comments,
bool GenerateComments)
: Buffer(Buffer), Comments(Comments), GenerateComments(GenerateComments) {}
std::vector<std::string> &Comments, bool GenerateComments)
: Buffer(Buffer), Comments(Comments), GenerateComments(GenerateComments) {
}
void EmitInt8(uint8_t Byte, const Twine &Comment) override {
Buffer.push_back(Byte);
if (GenerateComments)

View File

@ -170,26 +170,26 @@ static const char *const DbgTimerDescription = "DWARF Debug Writer";
static constexpr unsigned ULEB128PadSize = 4;
void DebugLocDwarfExpression::emitOp(uint8_t Op, const char *Comment) {
BS.EmitInt8(
getActiveStreamer().EmitInt8(
Op, Comment ? Twine(Comment) + " " + dwarf::OperationEncodingString(Op)
: dwarf::OperationEncodingString(Op));
}
void DebugLocDwarfExpression::emitSigned(int64_t Value) {
BS.EmitSLEB128(Value, Twine(Value));
getActiveStreamer().EmitSLEB128(Value, Twine(Value));
}
void DebugLocDwarfExpression::emitUnsigned(uint64_t Value) {
BS.EmitULEB128(Value, Twine(Value));
getActiveStreamer().EmitULEB128(Value, Twine(Value));
}
void DebugLocDwarfExpression::emitData1(uint8_t Value) {
BS.EmitInt8(Value, Twine(Value));
getActiveStreamer().EmitInt8(Value, Twine(Value));
}
void DebugLocDwarfExpression::emitBaseTypeRef(uint64_t Idx) {
assert(Idx < (1ULL << (ULEB128PadSize * 7)) && "Idx wont fit");
BS.EmitULEB128(Idx, Twine(Idx), ULEB128PadSize);
getActiveStreamer().EmitULEB128(Idx, Twine(Idx), ULEB128PadSize);
}
bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI,
@ -198,6 +198,32 @@ bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI,
return false;
}
void DebugLocDwarfExpression::enableTemporaryBuffer() {
assert(!IsBuffering && "Already buffering?");
if (!TmpBuf)
TmpBuf = std::make_unique<TempBuffer>(OutBS.GenerateComments);
IsBuffering = true;
}
void DebugLocDwarfExpression::disableTemporaryBuffer() { IsBuffering = false; }
unsigned DebugLocDwarfExpression::getTemporaryBufferSize() {
return TmpBuf ? TmpBuf->Bytes.size() : 0;
}
void DebugLocDwarfExpression::commitTemporaryBuffer() {
if (!TmpBuf)
return;
for (auto Byte : enumerate(TmpBuf->Bytes)) {
const char *Comment = (Byte.index() < TmpBuf->Comments.size())
? TmpBuf->Comments[Byte.index()].c_str()
: "";
OutBS.EmitInt8(Byte.value(), Comment);
}
TmpBuf->Bytes.clear();
TmpBuf->Comments.clear();
}
const DIType *DbgVariable::getType() const {
return getVariable()->getType();
}

View File

@ -13,6 +13,7 @@
#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFEXPRESSION_H
#define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFEXPRESSION_H
#include "ByteStreamer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
@ -26,7 +27,6 @@ namespace llvm {
class AsmPrinter;
class APInt;
class ByteStreamer;
class DwarfCompileUnit;
class DIELoc;
class TargetRegisterInfo;
@ -95,6 +95,13 @@ public:
/// Base class containing the logic for constructing DWARF expressions
/// independently of whether they are emitted into a DIE or into a .debug_loc
/// entry.
///
/// Some DWARF operations, e.g. DW_OP_entry_value, need to calculate the size
/// of a succeeding DWARF block before the latter is emitted to the output.
/// To handle such cases, data can conditionally be emitted to a temporary
/// buffer, which can later on be committed to the main output. The size of the
/// temporary buffer is queryable, allowing for the size of the data to be
/// emitted before the data is committed.
class DwarfExpression {
protected:
/// Holds information about all subregisters comprising a register location.
@ -178,6 +185,22 @@ protected:
virtual void emitBaseTypeRef(uint64_t Idx) = 0;
/// Start emitting data to the temporary buffer. The data stored in the
/// temporary buffer can be committed to the main output using
/// commitTemporaryBuffer().
virtual void enableTemporaryBuffer() = 0;
/// Disable emission to the temporary buffer. This does not commit data
/// in the temporary buffer to the main output.
virtual void disableTemporaryBuffer() = 0;
/// Return the emitted size, in number of bytes, for the data stored in the
/// temporary buffer.
virtual unsigned getTemporaryBufferSize() = 0;
/// Commit the data stored in the temporary buffer to the main output.
virtual void commitTemporaryBuffer() = 0;
/// Emit a normalized unsigned constant.
void emitConstu(uint64_t Value);
@ -308,31 +331,62 @@ public:
/// DwarfExpression implementation for .debug_loc entries.
class DebugLocDwarfExpression final : public DwarfExpression {
ByteStreamer &BS;
struct TempBuffer {
SmallString<32> Bytes;
std::vector<std::string> Comments;
BufferByteStreamer BS;
TempBuffer(bool GenerateComments) : BS(Bytes, Comments, GenerateComments) {}
};
std::unique_ptr<TempBuffer> TmpBuf;
BufferByteStreamer &OutBS;
bool IsBuffering = false;
/// Return the byte streamer that currently is being emitted to.
ByteStreamer &getActiveStreamer() { return IsBuffering ? TmpBuf->BS : OutBS; }
void emitOp(uint8_t Op, const char *Comment = nullptr) override;
void emitSigned(int64_t Value) override;
void emitUnsigned(uint64_t Value) override;
void emitData1(uint8_t Value) override;
void emitBaseTypeRef(uint64_t Idx) override;
void enableTemporaryBuffer() override;
void disableTemporaryBuffer() override;
unsigned getTemporaryBufferSize() override;
void commitTemporaryBuffer() override;
bool isFrameRegister(const TargetRegisterInfo &TRI,
unsigned MachineReg) override;
public:
DebugLocDwarfExpression(unsigned DwarfVersion, ByteStreamer &BS, DwarfCompileUnit &CU)
: DwarfExpression(DwarfVersion, CU), BS(BS) {}
DebugLocDwarfExpression(unsigned DwarfVersion, BufferByteStreamer &BS,
DwarfCompileUnit &CU)
: DwarfExpression(DwarfVersion, CU), OutBS(BS) {}
};
/// DwarfExpression implementation for singular DW_AT_location.
class DIEDwarfExpression final : public DwarfExpression {
const AsmPrinter &AP;
DIELoc &DIE;
const AsmPrinter &AP;
DIELoc &OutDIE;
DIELoc TmpDIE;
bool IsBuffering = false;
/// Return the DIE that currently is being emitted to.
DIELoc &getActiveDIE() { return IsBuffering ? TmpDIE : OutDIE; }
void emitOp(uint8_t Op, const char *Comment = nullptr) override;
void emitSigned(int64_t Value) override;
void emitUnsigned(uint64_t Value) override;
void emitData1(uint8_t Value) override;
void emitBaseTypeRef(uint64_t Idx) override;
void enableTemporaryBuffer() override;
void disableTemporaryBuffer() override;
unsigned getTemporaryBufferSize() override;
void commitTemporaryBuffer() override;
bool isFrameRegister(const TargetRegisterInfo &TRI,
unsigned MachineReg) override;
public:
@ -340,7 +394,7 @@ public:
DIELoc *finalize() {
DwarfExpression::finalize();
return &DIE;
return &OutDIE;
}
};

View File

@ -47,31 +47,42 @@ using namespace llvm;
#define DEBUG_TYPE "dwarfdebug"
DIEDwarfExpression::DIEDwarfExpression(const AsmPrinter &AP,
DwarfCompileUnit &CU,
DIELoc &DIE)
: DwarfExpression(AP.getDwarfVersion(), CU), AP(AP),
DIE(DIE) {}
DwarfCompileUnit &CU, DIELoc &DIE)
: DwarfExpression(AP.getDwarfVersion(), CU), AP(AP), OutDIE(DIE) {}
void DIEDwarfExpression::emitOp(uint8_t Op, const char* Comment) {
CU.addUInt(DIE, dwarf::DW_FORM_data1, Op);
CU.addUInt(getActiveDIE(), dwarf::DW_FORM_data1, Op);
}
void DIEDwarfExpression::emitSigned(int64_t Value) {
CU.addSInt(DIE, dwarf::DW_FORM_sdata, Value);
CU.addSInt(getActiveDIE(), dwarf::DW_FORM_sdata, Value);
}
void DIEDwarfExpression::emitUnsigned(uint64_t Value) {
CU.addUInt(DIE, dwarf::DW_FORM_udata, Value);
CU.addUInt(getActiveDIE(), dwarf::DW_FORM_udata, Value);
}
void DIEDwarfExpression::emitData1(uint8_t Value) {
CU.addUInt(DIE, dwarf::DW_FORM_data1, Value);
CU.addUInt(getActiveDIE(), dwarf::DW_FORM_data1, Value);
}
void DIEDwarfExpression::emitBaseTypeRef(uint64_t Idx) {
CU.addBaseTypeRef(DIE, Idx);
CU.addBaseTypeRef(getActiveDIE(), Idx);
}
void DIEDwarfExpression::enableTemporaryBuffer() {
assert(!IsBuffering && "Already buffering?");
IsBuffering = true;
}
void DIEDwarfExpression::disableTemporaryBuffer() { IsBuffering = false; }
unsigned DIEDwarfExpression::getTemporaryBufferSize() {
return TmpDIE.ComputeSize(&AP);
}
void DIEDwarfExpression::commitTemporaryBuffer() { OutDIE.takeValues(TmpDIE); }
bool DIEDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI,
unsigned MachineReg) {
return MachineReg == TRI.getFrameRegister(*AP.MF);