#include "DwarfExpression.h"
#include "DwarfCompileUnit.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/Register.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
using namespace llvm;
#define DEBUG_TYPE "dwarfdebug"
void DwarfExpression::emitConstu(uint64_t Value) {
if (Value < 32)
emitOp(dwarf::DW_OP_lit0 + Value);
else if (Value == std::numeric_limits<uint64_t>::max()) {
emitOp(dwarf::DW_OP_lit0);
emitOp(dwarf::DW_OP_not);
} else {
emitOp(dwarf::DW_OP_constu);
emitUnsigned(Value);
}
}
void DwarfExpression::addReg(int DwarfReg, const char *Comment) {
assert(DwarfReg >= 0 && "invalid negative dwarf register number");
assert((isUnknownLocation() || isRegisterLocation()) &&
"location description already locked down");
LocationKind = Register;
if (DwarfReg < 32) {
emitOp(dwarf::DW_OP_reg0 + DwarfReg, Comment);
} else {
emitOp(dwarf::DW_OP_regx, Comment);
emitUnsigned(DwarfReg);
}
}
void DwarfExpression::addBReg(int DwarfReg, int Offset) {
assert(DwarfReg >= 0 && "invalid negative dwarf register number");
assert(!isRegisterLocation() && "location description already locked down");
if (DwarfReg < 32) {
emitOp(dwarf::DW_OP_breg0 + DwarfReg);
} else {
emitOp(dwarf::DW_OP_bregx);
emitUnsigned(DwarfReg);
}
emitSigned(Offset);
}
void DwarfExpression::addFBReg(int Offset) {
emitOp(dwarf::DW_OP_fbreg);
emitSigned(Offset);
}
void DwarfExpression::addOpPiece(unsigned SizeInBits, unsigned OffsetInBits) {
if (!SizeInBits)
return;
const unsigned SizeOfByte = 8;
if (OffsetInBits > 0 || SizeInBits % SizeOfByte) {
emitOp(dwarf::DW_OP_bit_piece);
emitUnsigned(SizeInBits);
emitUnsigned(OffsetInBits);
} else {
emitOp(dwarf::DW_OP_piece);
unsigned ByteSize = SizeInBits / SizeOfByte;
emitUnsigned(ByteSize);
}
this->OffsetInBits += SizeInBits;
}
void DwarfExpression::addShr(unsigned ShiftBy) {
emitConstu(ShiftBy);
emitOp(dwarf::DW_OP_shr);
}
void DwarfExpression::addAnd(unsigned Mask) {
emitConstu(Mask);
emitOp(dwarf::DW_OP_and);
}
bool DwarfExpression::addMachineReg(const TargetRegisterInfo &TRI,
llvm::Register MachineReg,
unsigned MaxSize) {
if (!llvm::Register::isPhysicalRegister(MachineReg)) {
if (isFrameRegister(TRI, MachineReg)) {
DwarfRegs.push_back(Register::createRegister(-1, nullptr));
return true;
}
return false;
}
int Reg = TRI.getDwarfRegNum(MachineReg, false);
if (Reg >= 0) {
DwarfRegs.push_back(Register::createRegister(Reg, nullptr));
return true;
}
for (MCSuperRegIterator SR(MachineReg, &TRI); SR.isValid(); ++SR) {
Reg = TRI.getDwarfRegNum(*SR, false);
if (Reg >= 0) {
unsigned Idx = TRI.getSubRegIndex(*SR, MachineReg);
unsigned Size = TRI.getSubRegIdxSize(Idx);
unsigned RegOffset = TRI.getSubRegIdxOffset(Idx);
DwarfRegs.push_back(Register::createRegister(Reg, "super-register"));
setSubRegisterPiece(Size, RegOffset);
return true;
}
}
unsigned CurPos = 0;
const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(MachineReg);
unsigned RegSize = TRI.getRegSizeInBits(*RC);
SmallBitVector Coverage(RegSize, false);
for (MCSubRegIterator SR(MachineReg, &TRI); SR.isValid(); ++SR) {
unsigned Idx = TRI.getSubRegIndex(MachineReg, *SR);
unsigned Size = TRI.getSubRegIdxSize(Idx);
unsigned Offset = TRI.getSubRegIdxOffset(Idx);
Reg = TRI.getDwarfRegNum(*SR, false);
if (Reg < 0)
continue;
SmallBitVector CurSubReg(RegSize, false);
CurSubReg.set(Offset, Offset + Size);
if (Offset < MaxSize && CurSubReg.test(Coverage)) {
if (Offset > CurPos)
DwarfRegs.push_back(Register::createSubRegister(
-1, Offset - CurPos, "no DWARF register encoding"));
if (Offset == 0 && Size >= MaxSize)
DwarfRegs.push_back(Register::createRegister(Reg, "sub-register"));
else
DwarfRegs.push_back(Register::createSubRegister(
Reg, std::min<unsigned>(Size, MaxSize - Offset), "sub-register"));
}
Coverage.set(Offset, Offset + Size);
CurPos = Offset + Size;
}
if (CurPos == 0)
return false;
if (CurPos < RegSize)
DwarfRegs.push_back(Register::createSubRegister(
-1, RegSize - CurPos, "no DWARF register encoding"));
return true;
}
void DwarfExpression::addStackValue() {
if (DwarfVersion >= 4)
emitOp(dwarf::DW_OP_stack_value);
}
void DwarfExpression::addSignedConstant(int64_t Value) {
assert(isImplicitLocation() || isUnknownLocation());
LocationKind = Implicit;
emitOp(dwarf::DW_OP_consts);
emitSigned(Value);
}
void DwarfExpression::addUnsignedConstant(uint64_t Value) {
assert(isImplicitLocation() || isUnknownLocation());
LocationKind = Implicit;
emitConstu(Value);
}
void DwarfExpression::addUnsignedConstant(const APInt &Value) {
assert(isImplicitLocation() || isUnknownLocation());
LocationKind = Implicit;
unsigned Size = Value.getBitWidth();
const uint64_t *Data = Value.getRawData();
unsigned Offset = 0;
while (Offset < Size) {
addUnsignedConstant(*Data++);
if (Offset == 0 && Size <= 64)
break;
addStackValue();
addOpPiece(std::min(Size - Offset, 64u), Offset);
Offset += 64;
}
}
void DwarfExpression::addConstantFP(const APFloat &APF, const AsmPrinter &AP) {
assert(isImplicitLocation() || isUnknownLocation());
APInt API = APF.bitcastToAPInt();
int NumBytes = API.getBitWidth() / 8;
if (NumBytes == 4 || NumBytes == 8 ) {
emitOp(dwarf::DW_OP_implicit_value);
emitUnsigned(NumBytes );
if (AP.getDataLayout().isBigEndian())
API = API.byteSwap();
for (int i = 0; i < NumBytes; ++i) {
emitData1(API.getZExtValue() & 0xFF);
API = API.lshr(8);
}
return;
}
LLVM_DEBUG(
dbgs() << "Skipped DW_OP_implicit_value creation for ConstantFP of size: "
<< API.getBitWidth() << " bits\n");
}
bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,
DIExpressionCursor &ExprCursor,
llvm::Register MachineReg,
unsigned FragmentOffsetInBits) {
auto Fragment = ExprCursor.getFragmentInfo();
if (!addMachineReg(TRI, MachineReg, Fragment ? Fragment->SizeInBits : ~1U)) {
LocationKind = Unknown;
return false;
}
bool HasComplexExpression = false;
auto Op = ExprCursor.peek();
if (Op && Op->getOp() != dwarf::DW_OP_LLVM_fragment)
HasComplexExpression = true;
if ((HasComplexExpression || IsEmittingEntryValue) && DwarfRegs.size() > 1) {
if (IsEmittingEntryValue)
cancelEntryValue();
DwarfRegs.clear();
LocationKind = Unknown;
return false;
}
if ((!isParameterValue() && !isMemoryLocation() && !HasComplexExpression) ||
isEntryValue()) {
auto FragmentInfo = ExprCursor.getFragmentInfo();
unsigned RegSize = 0;
for (auto &Reg : DwarfRegs) {
RegSize += Reg.SubRegSize;
if (Reg.DwarfRegNo >= 0)
addReg(Reg.DwarfRegNo, Reg.Comment);
if (FragmentInfo)
if (RegSize > FragmentInfo->SizeInBits)
break;
addOpPiece(Reg.SubRegSize);
}
if (isEntryValue()) {
finalizeEntryValue();
if (!isIndirect() && !isParameterValue() && !HasComplexExpression &&
DwarfVersion >= 4)
emitOp(dwarf::DW_OP_stack_value);
}
DwarfRegs.clear();
auto NextOp = ExprCursor.peek();
if (SubRegisterSizeInBits && NextOp &&
(NextOp->getOp() != dwarf::DW_OP_LLVM_fragment))
maskSubRegister();
return true;
}
if (DwarfVersion < 4)
if (any_of(ExprCursor, [](DIExpression::ExprOperand Op) -> bool {
return Op.getOp() == dwarf::DW_OP_stack_value;
})) {
DwarfRegs.clear();
LocationKind = Unknown;
return false;
}
if (DwarfRegs.size() > 1) {
LLVM_DEBUG(dbgs() << "TODO: giving up on debug information due to "
"multi-register usage.\n");
DwarfRegs.clear();
LocationKind = Unknown;
return false;
}
auto Reg = DwarfRegs[0];
bool FBReg = isFrameRegister(TRI, MachineReg);
int SignedOffset = 0;
assert(!Reg.isSubRegister() && "full register expected");
if (Op && (Op->getOp() == dwarf::DW_OP_plus_uconst)) {
uint64_t Offset = Op->getArg(0);
uint64_t IntMax = static_cast<uint64_t>(std::numeric_limits<int>::max());
if (Offset <= IntMax) {
SignedOffset = Offset;
ExprCursor.take();
}
}
if (Op && Op->getOp() == dwarf::DW_OP_constu) {
uint64_t Offset = Op->getArg(0);
uint64_t IntMax = static_cast<uint64_t>(std::numeric_limits<int>::max());
auto N = ExprCursor.peekNext();
if (N && N->getOp() == dwarf::DW_OP_plus && Offset <= IntMax) {
SignedOffset = Offset;
ExprCursor.consume(2);
} else if (N && N->getOp() == dwarf::DW_OP_minus &&
!SubRegisterSizeInBits && Offset <= IntMax + 1) {
SignedOffset = -static_cast<int64_t>(Offset);
ExprCursor.consume(2);
}
}
if (FBReg)
addFBReg(SignedOffset);
else
addBReg(Reg.DwarfRegNo, SignedOffset);
DwarfRegs.clear();
auto NextOp = ExprCursor.peek();
if (SubRegisterSizeInBits && NextOp &&
(NextOp->getOp() != dwarf::DW_OP_LLVM_fragment))
maskSubRegister();
return true;
}
void DwarfExpression::setEntryValueFlags(const MachineLocation &Loc) {
LocationFlags |= EntryValue;
if (Loc.isIndirect())
LocationFlags |= Indirect;
}
void DwarfExpression::setLocation(const MachineLocation &Loc,
const DIExpression *DIExpr) {
if (Loc.isIndirect())
setMemoryLocationKind();
if (DIExpr->isEntryValue())
setEntryValueFlags(Loc);
}
void DwarfExpression::beginEntryValueExpression(
DIExpressionCursor &ExprCursor) {
auto Op = ExprCursor.take();
(void)Op;
assert(Op && Op->getOp() == dwarf::DW_OP_LLVM_entry_value);
assert(!IsEmittingEntryValue && "Already emitting entry value?");
assert(Op->getArg(0) == 1 &&
"Can currently only emit entry values covering a single operation");
SavedLocationKind = LocationKind;
LocationKind = Register;
IsEmittingEntryValue = true;
enableTemporaryBuffer();
}
void DwarfExpression::finalizeEntryValue() {
assert(IsEmittingEntryValue && "Entry value not open?");
disableTemporaryBuffer();
emitOp(CU.getDwarf5OrGNULocationAtom(dwarf::DW_OP_entry_value));
unsigned Size = getTemporaryBufferSize();
emitUnsigned(Size);
commitTemporaryBuffer();
LocationFlags &= ~EntryValue;
LocationKind = SavedLocationKind;
IsEmittingEntryValue = false;
}
void DwarfExpression::cancelEntryValue() {
assert(IsEmittingEntryValue && "Entry value not open?");
disableTemporaryBuffer();
assert(getTemporaryBufferSize() == 0 &&
"Began emitting entry value block before cancelling entry value");
LocationKind = SavedLocationKind;
IsEmittingEntryValue = false;
}
unsigned DwarfExpression::getOrCreateBaseType(unsigned BitSize,
dwarf::TypeKind Encoding) {
unsigned I = 0, E = CU.ExprRefedBaseTypes.size();
for (; I != E; ++I)
if (CU.ExprRefedBaseTypes[I].BitSize == BitSize &&
CU.ExprRefedBaseTypes[I].Encoding == Encoding)
break;
if (I == E)
CU.ExprRefedBaseTypes.emplace_back(BitSize, Encoding);
return I;
}
static bool isMemoryLocation(DIExpressionCursor ExprCursor) {
while (ExprCursor) {
auto Op = ExprCursor.take();
switch (Op->getOp()) {
case dwarf::DW_OP_deref:
case dwarf::DW_OP_LLVM_fragment:
break;
default:
return false;
}
}
return true;
}
void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor) {
addExpression(std::move(ExprCursor),
[](unsigned Idx, DIExpressionCursor &Cursor) -> bool {
llvm_unreachable("unhandled opcode found in expression");
});
}
bool DwarfExpression::addExpression(
DIExpressionCursor &&ExprCursor,
llvm::function_ref<bool(unsigned, DIExpressionCursor &)> InsertArg) {
assert(!IsEmittingEntryValue && "Can't emit entry value around expression");
Optional<DIExpression::ExprOperand> PrevConvertOp = None;
while (ExprCursor) {
auto Op = ExprCursor.take();
uint64_t OpNum = Op->getOp();
if (OpNum >= dwarf::DW_OP_reg0 && OpNum <= dwarf::DW_OP_reg31) {
emitOp(OpNum);
continue;
} else if (OpNum >= dwarf::DW_OP_breg0 && OpNum <= dwarf::DW_OP_breg31) {
addBReg(OpNum - dwarf::DW_OP_breg0, Op->getArg(0));
continue;
}
switch (OpNum) {
case dwarf::DW_OP_LLVM_arg:
if (!InsertArg(Op->getArg(0), ExprCursor)) {
LocationKind = Unknown;
return false;
}
break;
case dwarf::DW_OP_LLVM_fragment: {
unsigned SizeInBits = Op->getArg(1);
unsigned FragmentOffset = Op->getArg(0);
assert(OffsetInBits >= FragmentOffset && "fragment offset not added?");
assert(SizeInBits >= OffsetInBits - FragmentOffset && "size underflow");
SizeInBits -= OffsetInBits - FragmentOffset;
if (SubRegisterSizeInBits)
SizeInBits = std::min<unsigned>(SizeInBits, SubRegisterSizeInBits);
if (isImplicitLocation())
addStackValue();
addOpPiece(SizeInBits, SubRegisterOffsetInBits);
setSubRegisterPiece(0, 0);
LocationKind = Unknown;
return true;
}
case dwarf::DW_OP_plus_uconst:
assert(!isRegisterLocation());
emitOp(dwarf::DW_OP_plus_uconst);
emitUnsigned(Op->getArg(0));
break;
case dwarf::DW_OP_plus:
case dwarf::DW_OP_minus:
case dwarf::DW_OP_mul:
case dwarf::DW_OP_div:
case dwarf::DW_OP_mod:
case dwarf::DW_OP_or:
case dwarf::DW_OP_and:
case dwarf::DW_OP_xor:
case dwarf::DW_OP_shl:
case dwarf::DW_OP_shr:
case dwarf::DW_OP_shra:
case dwarf::DW_OP_lit0:
case dwarf::DW_OP_not:
case dwarf::DW_OP_dup:
case dwarf::DW_OP_push_object_address:
case dwarf::DW_OP_over:
emitOp(OpNum);
break;
case dwarf::DW_OP_deref:
assert(!isRegisterLocation());
if (!isMemoryLocation() && ::isMemoryLocation(ExprCursor))
LocationKind = Memory;
else
emitOp(dwarf::DW_OP_deref);
break;
case dwarf::DW_OP_constu:
assert(!isRegisterLocation());
emitConstu(Op->getArg(0));
break;
case dwarf::DW_OP_consts:
assert(!isRegisterLocation());
emitOp(dwarf::DW_OP_consts);
emitSigned(Op->getArg(0));
break;
case dwarf::DW_OP_LLVM_convert: {
unsigned BitSize = Op->getArg(0);
dwarf::TypeKind Encoding = static_cast<dwarf::TypeKind>(Op->getArg(1));
if (DwarfVersion >= 5 && CU.getDwarfDebug().useOpConvert()) {
emitOp(dwarf::DW_OP_convert);
emitBaseTypeRef(getOrCreateBaseType(BitSize, Encoding));
} else {
if (PrevConvertOp && PrevConvertOp->getArg(0) < BitSize) {
if (Encoding == dwarf::DW_ATE_signed)
emitLegacySExt(PrevConvertOp->getArg(0));
else if (Encoding == dwarf::DW_ATE_unsigned)
emitLegacyZExt(PrevConvertOp->getArg(0));
PrevConvertOp = None;
} else {
PrevConvertOp = Op;
}
}
break;
}
case dwarf::DW_OP_stack_value:
LocationKind = Implicit;
break;
case dwarf::DW_OP_swap:
assert(!isRegisterLocation());
emitOp(dwarf::DW_OP_swap);
break;
case dwarf::DW_OP_xderef:
assert(!isRegisterLocation());
emitOp(dwarf::DW_OP_xderef);
break;
case dwarf::DW_OP_deref_size:
emitOp(dwarf::DW_OP_deref_size);
emitData1(Op->getArg(0));
break;
case dwarf::DW_OP_LLVM_tag_offset:
TagOffset = Op->getArg(0);
break;
case dwarf::DW_OP_regx:
emitOp(dwarf::DW_OP_regx);
emitUnsigned(Op->getArg(0));
break;
case dwarf::DW_OP_bregx:
emitOp(dwarf::DW_OP_bregx);
emitUnsigned(Op->getArg(0));
emitSigned(Op->getArg(1));
break;
default:
llvm_unreachable("unhandled opcode found in expression");
}
}
if (isImplicitLocation() && !isParameterValue())
addStackValue();
return true;
}
void DwarfExpression::maskSubRegister() {
assert(SubRegisterSizeInBits && "no subregister was registered");
if (SubRegisterOffsetInBits > 0)
addShr(SubRegisterOffsetInBits);
uint64_t Mask = (1ULL << (uint64_t)SubRegisterSizeInBits) - 1ULL;
addAnd(Mask);
}
void DwarfExpression::finalize() {
assert(DwarfRegs.size() == 0 && "dwarf registers not emitted");
if (SubRegisterSizeInBits == 0)
return;
if (SubRegisterOffsetInBits == 0)
return;
addOpPiece(SubRegisterSizeInBits, SubRegisterOffsetInBits);
}
void DwarfExpression::addFragmentOffset(const DIExpression *Expr) {
if (!Expr || !Expr->isFragment())
return;
uint64_t FragmentOffset = Expr->getFragmentInfo()->OffsetInBits;
assert(FragmentOffset >= OffsetInBits &&
"overlapping or duplicate fragments");
if (FragmentOffset > OffsetInBits)
addOpPiece(FragmentOffset - OffsetInBits);
OffsetInBits = FragmentOffset;
}
void DwarfExpression::emitLegacySExt(unsigned FromBits) {
emitOp(dwarf::DW_OP_dup);
emitOp(dwarf::DW_OP_constu);
emitUnsigned(FromBits - 1);
emitOp(dwarf::DW_OP_shr);
emitOp(dwarf::DW_OP_lit0);
emitOp(dwarf::DW_OP_not);
emitOp(dwarf::DW_OP_mul);
emitOp(dwarf::DW_OP_constu);
emitUnsigned(FromBits);
emitOp(dwarf::DW_OP_shl);
emitOp(dwarf::DW_OP_or);
}
void DwarfExpression::emitLegacyZExt(unsigned FromBits) {
if (FromBits / 7 < 1+1+1+1+1) {
emitOp(dwarf::DW_OP_constu);
emitUnsigned((1ULL << FromBits) - 1);
} else {
emitOp(dwarf::DW_OP_lit1);
emitOp(dwarf::DW_OP_constu);
emitUnsigned(FromBits);
emitOp(dwarf::DW_OP_shl);
emitOp(dwarf::DW_OP_lit1);
emitOp(dwarf::DW_OP_minus);
}
emitOp(dwarf::DW_OP_and);
}
void DwarfExpression::addWasmLocation(unsigned Index, uint64_t Offset) {
emitOp(dwarf::DW_OP_WASM_location);
emitUnsigned(Index == 4 ? 0 : Index);
emitUnsigned(Offset);
if (Index == 4 ) {
assert(LocationKind == Unknown);
LocationKind = Memory;
} else {
assert(LocationKind == Implicit || LocationKind == Unknown);
LocationKind = Implicit;
}
}