| //===- llvm/CodeGen/DwarfExpression.cpp - Dwarf Debug Framework -----------===// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file contains support for writing dwarf debug info into asm files. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #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/MC/MCAsmInfo.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include <algorithm> | |
| using namespace llvm; | |
| #define DEBUG_TYPE "dwarfdebug" | |
| /// Return whether the rest of the expression needs the complex register path. | |
| /// We use this to decide whether we can emit a simple register location and | |
| /// whether a subregister needs to be masked. Non-emitting operations don't | |
| /// affect either decision, so look past them. | |
| static bool isRemainingExpressionComplex(const DIExpressionCursor &ExprCursor) { | |
| for (DIExpression::ExprOperand Op : ExprCursor) { | |
| if (Op.isNonEmitting()) | |
| continue; | |
| return Op.getOp() != dwarf::DW_OP_LLVM_fragment; | |
| } | |
| return false; | |
| } | |
| void DwarfExpression::emitConstu(uint64_t Value) { | |
| if (Value < 32) | |
| emitOp(dwarf::DW_OP_lit0 + Value); | |
| else if (Value == std::numeric_limits<uint64_t>::max()) { | |
| // Only do this for 64-bit values as the DWARF expression stack uses | |
| // target-address-size values. | |
| emitOp(dwarf::DW_OP_lit0); | |
| emitOp(dwarf::DW_OP_not); | |
| } else { | |
| emitOp(dwarf::DW_OP_constu); | |
| emitUnsigned(Value); | |
| } | |
| } | |
| void DwarfExpression::addReg(int64_t 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(int64_t DwarfReg, int64_t 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(int64_t 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 (!MachineReg.isPhysical()) { | |
| if (isFrameRegister(TRI, MachineReg)) { | |
| DwarfRegs.push_back(Register::createRegister(-1, nullptr)); | |
| return true; | |
| } | |
| // Try getting dwarf register for targets that use virtual registers. | |
| int64_t Reg = TRI.getDwarfRegNumForVirtReg(MachineReg, false); | |
| if (Reg > 0) { | |
| DwarfRegs.push_back(Register::createRegister(Reg, nullptr)); | |
| return true; | |
| } | |
| return false; | |
| } | |
| int64_t Reg = TRI.getDwarfRegNum(MachineReg, false); | |
| // If this is a valid register number, emit it. | |
| if (Reg >= 0) { | |
| DwarfRegs.push_back(Register::createRegister(Reg, nullptr)); | |
| return true; | |
| } | |
| // The frame register is referenced through DW_OP_fbreg relative to | |
| // DW_AT_frame_base, so it needs no DWARF register number of its own. | |
| if (isFrameRegister(TRI, MachineReg)) { | |
| DwarfRegs.push_back(Register::createRegister(-1, nullptr)); | |
| return true; | |
| } | |
| // Walk up the super-register chain until we find a valid number. | |
| // For example, EAX on x86_64 is a 32-bit fragment of RAX with offset 0. | |
| for (MCPhysReg SR : TRI.superregs(MachineReg)) { | |
| 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")); | |
| // Use a DW_OP_bit_piece to describe the sub-register. | |
| setSubRegisterPiece(Size, RegOffset); | |
| return true; | |
| } | |
| } | |
| // Otherwise, attempt to find a covering set of sub-register numbers. | |
| // For example, Q0 on ARM is a composition of D0+D1. | |
| unsigned CurPos = 0; | |
| // The size of the register in bits. | |
| const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(MachineReg); | |
| unsigned RegSize = TRI.getRegSizeInBits(*RC); | |
| // Keep track of the bits in the register we already emitted, so we | |
| // can avoid emitting redundant aliasing subregs. Because this is | |
| // just doing a greedy scan of all subregisters, it is possible that | |
| // this doesn't find a combination of subregisters that fully cover | |
| // the register (even though one may exist). | |
| SmallBitVector Coverage(RegSize, false); | |
| for (MCPhysReg SR : TRI.subregs(MachineReg)) { | |
| unsigned Idx = TRI.getSubRegIndex(MachineReg, SR); | |
| unsigned Size = TRI.getSubRegIdxSize(Idx); | |
| unsigned Offset = TRI.getSubRegIdxOffset(Idx); | |
| Reg = TRI.getDwarfRegNum(SR, false); | |
| if (Reg < 0 || Offset + Size > RegSize) | |
| continue; | |
| // Used to build the intersection between the bits we already | |
| // emitted and the bits covered by this subregister. | |
| SmallBitVector CurSubReg(RegSize, false); | |
| CurSubReg.set(Offset, Offset + Size); | |
| // If this sub-register has a DWARF number and we haven't covered | |
| // its range, and its range covers the value, emit a DWARF piece for it. | |
| if (Offset < MaxSize && !CurSubReg.subsetOf(Coverage)) { | |
| // Emit a piece for any gap in the 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")); | |
| } | |
| // Mark it as emitted. | |
| Coverage.set(Offset, Offset + Size); | |
| CurPos = Offset + Size; | |
| } | |
| // Failed to find any DWARF encoding. | |
| if (CurPos == 0) | |
| return false; | |
| // Found a partial or complete DWARF encoding. | |
| 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::addBooleanConstant(int64_t Value) { | |
| assert(isImplicitLocation() || isUnknownLocation()); | |
| LocationKind = Implicit; | |
| if (Value == 0) | |
| emitOp(dwarf::DW_OP_lit0); | |
| else | |
| emitOp(dwarf::DW_OP_lit1); | |
| } | |
| 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(); | |
| // Chop it up into 64-bit pieces, because that's the maximum that | |
| // addUnsignedConstant takes. | |
| 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::addImplicitValue(const APInt &Value, | |
| const AsmPrinter &AP) { | |
| assert(isImplicitLocation() || isUnknownLocation()); | |
| assert(DwarfVersion >= 4); | |
| APInt API = Value; | |
| unsigned NumBytes = API.getBitWidth() / 8; | |
| assert(API.getBitWidth() == NumBytes * 8 && | |
| "implicit value must be byte-sized"); | |
| emitOp(dwarf::DW_OP_implicit_value); | |
| emitUnsigned(NumBytes); | |
| // The loop below is emitting the value starting at the least significant | |
| // byte, so byte-swap first for big-endian targets. | |
| if (AP.getDataLayout().isBigEndian()) | |
| API = API.byteSwap(); | |
| for (unsigned I = 0; I < NumBytes; ++I) | |
| emitData1(API.extractBits(8, I * 8).getZExtValue()); | |
| } | |
| void DwarfExpression::addConstantFP(const APFloat &APF, const AsmPrinter &AP) { | |
| assert(isImplicitLocation() || isUnknownLocation()); | |
| APInt API = APF.bitcastToAPInt(); | |
| int NumBytes = API.getBitWidth() / 8; | |
| if (NumBytes == 4 /*float*/ || NumBytes == 8 /*double*/) { | |
| // FIXME: Add support for `long double`. | |
| emitOp(dwarf::DW_OP_implicit_value); | |
| emitUnsigned(NumBytes /*Size of the block in bytes*/); | |
| // The loop below is emitting the value starting at least significant byte, | |
| // so we need to perform a byte-swap to get the byte order correct in case | |
| // of a big-endian target. | |
| 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 = isRemainingExpressionComplex(ExprCursor); | |
| // If the register can only be described by a complex expression (i.e., | |
| // multiple subregisters) it doesn't safely compose with another complex | |
| // expression. For example, it is not possible to apply a DW_OP_deref | |
| // operation to multiple DW_OP_pieces, since composite location descriptions | |
| // do not push anything on the DWARF stack. | |
| // | |
| // DW_OP_entry_value operations can only hold a DWARF expression or a | |
| // register location description, so we can't emit a single entry value | |
| // covering a composite location description. In the future we may want to | |
| // emit entry value operations for each register location in the composite | |
| // location, but until that is supported do not emit anything. | |
| if ((HasComplexExpression || IsEmittingEntryValue) && DwarfRegs.size() > 1) { | |
| if (IsEmittingEntryValue) | |
| cancelEntryValue(); | |
| DwarfRegs.clear(); | |
| LocationKind = Unknown; | |
| return false; | |
| } | |
| // Handle simple register locations. If we are supposed to emit | |
| // a call site parameter expression and if that expression is just a register | |
| // location, emit it with addBReg and offset 0, because we should emit a DWARF | |
| // expression representing a value, rather than a location. | |
| if ((!isParameterValue() && !isMemoryLocation() && !HasComplexExpression) || | |
| isEntryValue()) { | |
| unsigned RegSize = 0; | |
| for (auto &Reg : DwarfRegs) { | |
| RegSize += Reg.SubRegSize; | |
| if (Reg.DwarfRegNo >= 0) | |
| addReg(Reg.DwarfRegNo, Reg.Comment); | |
| if (Fragment && RegSize > Fragment->SizeInBits) | |
| // If the register is larger than the current fragment stop | |
| // once the fragment is covered. | |
| break; | |
| addOpPiece(Reg.SubRegSize); | |
| } | |
| if (isEntryValue()) { | |
| finalizeEntryValue(); | |
| if (!isIndirect() && !isParameterValue() && !HasComplexExpression && | |
| DwarfVersion >= 4) | |
| emitOp(dwarf::DW_OP_stack_value); | |
| } | |
| DwarfRegs.clear(); | |
| // If we need to mask out a subregister, do it now, unless the next | |
| // operation would emit an OpPiece anyway. | |
| if (SubRegisterSizeInBits && isRemainingExpressionComplex(ExprCursor)) | |
| maskSubRegister(); | |
| return true; | |
| } | |
| // Don't emit locations that cannot be expressed without DW_OP_stack_value. | |
| 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; | |
| } | |
| // TODO: We should not give up here but the following code needs to be changed | |
| // to deal with multiple (sub)registers first. | |
| 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; | |
| } | |
| // Consume leading tag offsets before matching the register expression. | |
| // Record the tag offset here because addExpression won't see a consumed | |
| // operation. | |
| while (auto Op = ExprCursor.peek()) { | |
| auto Tag = dyn_cast<DIExpression::TagOffsetOp>(*Op); | |
| if (!Tag) | |
| break; | |
| TagOffset = Tag.getTagOffset(); | |
| ExprCursor.take(); | |
| } | |
| auto Op = ExprCursor.peek(); | |
| auto Reg = DwarfRegs[0]; | |
| int SignedOffset = 0; | |
| assert(!Reg.isSubRegister() && "full register expected"); | |
| // Pattern-match combinations for which more efficient representations exist. | |
| if (Op) { | |
| const uint64_t IntMax = | |
| static_cast<uint64_t>(std::numeric_limits<int>::max()); | |
| // [Reg, DW_OP_plus_uconst, Offset] --> [DW_OP_breg, Offset]. | |
| if (auto PlusUconst = dyn_cast<DIExpression::PlusUconstOp>(*Op)) { | |
| uint64_t Offset = PlusUconst.getOffset(); | |
| if (Offset <= IntMax) { | |
| SignedOffset = Offset; | |
| ExprCursor.take(); | |
| } | |
| } else if (auto Constant = dyn_cast<DIExpression::ConstuOp>(*Op)) { | |
| // [Reg, DW_OP_constu, Offset, DW_OP_plus] --> [DW_OP_breg, Offset] | |
| // [Reg, DW_OP_constu, Offset, DW_OP_minus] --> [DW_OP_breg,-Offset] | |
| // If Reg is a subregister we need to mask it out before subtracting. | |
| uint64_t Offset = Constant.getValue(); | |
| 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 (isFrameRegister(TRI, MachineReg)) | |
| addFBReg(SignedOffset); | |
| else | |
| addBReg(Reg.DwarfRegNo, SignedOffset); | |
| DwarfRegs.clear(); | |
| // If we need to mask out a subregister, do it now, unless the next | |
| // operation would emit an OpPiece anyway. | |
| if (SubRegisterSizeInBits && isRemainingExpressionComplex(ExprCursor)) | |
| 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 && isa<DIExpression::EntryValueOp>(*Op)); | |
| assert(!IsEmittingEntryValue && "Already emitting entry value?"); | |
| assert(cast<DIExpression::EntryValueOp>(*Op).getNumOperations() == 1 && | |
| "Can currently only emit entry values covering a single operation"); | |
| SavedLocationKind = LocationKind; | |
| LocationKind = Register; | |
| LocationFlags |= EntryValue; | |
| IsEmittingEntryValue = true; | |
| enableTemporaryBuffer(); | |
| } | |
| void DwarfExpression::finalizeEntryValue() { | |
| assert(IsEmittingEntryValue && "Entry value not open?"); | |
| disableTemporaryBuffer(); | |
| emitOp(CU.getDwarf5OrGNULocationAtom(dwarf::DW_OP_entry_value)); | |
| // Emit the entry value's size operand. | |
| unsigned Size = getTemporaryBufferSize(); | |
| emitUnsigned(Size); | |
| // Emit the entry value's DWARF block operand. | |
| commitTemporaryBuffer(); | |
| LocationFlags &= ~EntryValue; | |
| LocationKind = SavedLocationKind; | |
| IsEmittingEntryValue = false; | |
| } | |
| void DwarfExpression::cancelEntryValue() { | |
| assert(IsEmittingEntryValue && "Entry value not open?"); | |
| disableTemporaryBuffer(); | |
| // The temporary buffer can't be emptied, so for now just assert that nothing | |
| // has been emitted to it. | |
| assert(getTemporaryBufferSize() == 0 && | |
| "Began emitting entry value block before cancelling entry value"); | |
| LocationKind = SavedLocationKind; | |
| IsEmittingEntryValue = false; | |
| } | |
| unsigned DwarfExpression::getOrCreateBaseType(unsigned BitSize, | |
| dwarf::TypeKind Encoding) { | |
| // Reuse the base_type if we already have one in this CU otherwise we | |
| // create a new one. | |
| 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; | |
| } | |
| /// Assuming a well-formed expression, match "DW_OP_deref* | |
| /// DW_OP_LLVM_fragment?". | |
| 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) { | |
| // Entry values can currently only cover the initial register location, | |
| // and not any other parts of the following DWARF expression. | |
| assert(!IsEmittingEntryValue && "Can't emit entry value around expression"); | |
| std::optional<DIExpression::ConvertOp> PrevConvertOp; | |
| 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(cast<DIExpression::ArgOp>(*Op).getIndex(), ExprCursor)) { | |
| LocationKind = Unknown; | |
| return false; | |
| } | |
| break; | |
| case dwarf::DW_OP_LLVM_fragment: { | |
| auto Fragment = cast<DIExpression::FragmentOp>(*Op); | |
| unsigned SizeInBits = Fragment.getSizeInBits(); | |
| unsigned FragmentOffset = Fragment.getOffsetInBits(); | |
| // The fragment offset must have already been adjusted by emitting an | |
| // empty DW_OP_piece / DW_OP_bit_piece before we emitted the base | |
| // location. | |
| assert(OffsetInBits >= FragmentOffset && "fragment offset not added?"); | |
| assert(SizeInBits >= OffsetInBits - FragmentOffset && "size underflow"); | |
| // If addMachineReg already emitted DW_OP_piece operations to represent | |
| // a super-register by splicing together sub-registers, subtract the size | |
| // of the pieces that was already emitted. | |
| SizeInBits -= OffsetInBits - FragmentOffset; | |
| // If addMachineReg requested a DW_OP_bit_piece to stencil out a | |
| // sub-register that is smaller than the current fragment's size, use it. | |
| if (SubRegisterSizeInBits) | |
| SizeInBits = std::min<unsigned>(SizeInBits, SubRegisterSizeInBits); | |
| // Emit a DW_OP_stack_value for implicit location descriptions. | |
| if (isImplicitLocation()) | |
| addStackValue(); | |
| // Emit the DW_OP_piece. | |
| addOpPiece(SizeInBits, SubRegisterOffsetInBits); | |
| setSubRegisterPiece(0, 0); | |
| // Reset the location description kind. | |
| LocationKind = Unknown; | |
| return true; | |
| } | |
| case dwarf::DW_OP_LLVM_extract_bits_sext: | |
| case dwarf::DW_OP_LLVM_extract_bits_zext: { | |
| auto Extract = cast<DIExpression::ExtractBitsOp>(*Op); | |
| unsigned SizeInBits = Extract.getSizeInBits(); | |
| unsigned BitOffset = Extract.getOffsetInBits(); | |
| bool IsSigned = Extract.isSigned(); | |
| unsigned DerefSize = 0; | |
| // Operations are done in the DWARF "generic type" whose size | |
| // is the size of a pointer. | |
| unsigned PtrSizeInBytes = CU.getAsmPrinter()->MAI.getCodePointerSize(); | |
| // If we have a memory location then dereference to get the value, though | |
| // we have to make sure we don't dereference any bytes past the end of the | |
| // object. | |
| if (isMemoryLocation()) { | |
| DerefSize = alignTo(BitOffset + SizeInBits, 8) / 8; | |
| if (DerefSize == PtrSizeInBytes) { | |
| emitOp(dwarf::DW_OP_deref); | |
| } else { | |
| emitOp(dwarf::DW_OP_deref_size); | |
| emitUnsigned(DerefSize); | |
| } | |
| } | |
| // If a dereference was emitted for an unsigned value, and | |
| // there's no bit offset, then a bit of optimization is | |
| // possible. | |
| if (!IsSigned && BitOffset == 0) { | |
| if (8 * DerefSize == SizeInBits) { | |
| // The correct value is already on the stack. | |
| } else { | |
| // No need to shift, we can just mask off the desired bits. | |
| emitOp(dwarf::DW_OP_constu); | |
| emitUnsigned((1u << SizeInBits) - 1); | |
| emitOp(dwarf::DW_OP_and); | |
| } | |
| } else { | |
| // Extract the bits by a shift left (to shift out the bits after what we | |
| // want to extract) followed by shift right (to shift the bits to | |
| // position 0 and also sign/zero extend). | |
| unsigned LeftShift = PtrSizeInBytes * 8 - (SizeInBits + BitOffset); | |
| unsigned RightShift = LeftShift + BitOffset; | |
| if (LeftShift) { | |
| emitOp(dwarf::DW_OP_constu); | |
| emitUnsigned(LeftShift); | |
| emitOp(dwarf::DW_OP_shl); | |
| } | |
| if (RightShift) { | |
| emitOp(dwarf::DW_OP_constu); | |
| emitUnsigned(RightShift); | |
| emitOp(IsSigned ? dwarf::DW_OP_shra : dwarf::DW_OP_shr); | |
| } | |
| } | |
| // The value is now at the top of the stack, so set the location to | |
| // implicit so that we get a stack_value at the end. | |
| LocationKind = Implicit; | |
| break; | |
| } | |
| case dwarf::DW_OP_plus_uconst: | |
| assert(!isRegisterLocation()); | |
| emitOp(dwarf::DW_OP_plus_uconst); | |
| emitUnsigned(cast<DIExpression::PlusUconstOp>(*Op).getOffset()); | |
| 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: | |
| case dwarf::DW_OP_rot: | |
| case dwarf::DW_OP_eq: | |
| case dwarf::DW_OP_ne: | |
| case dwarf::DW_OP_gt: | |
| case dwarf::DW_OP_ge: | |
| case dwarf::DW_OP_lt: | |
| case dwarf::DW_OP_le: | |
| case dwarf::DW_OP_neg: | |
| case dwarf::DW_OP_abs: | |
| emitOp(OpNum); | |
| break; | |
| case dwarf::DW_OP_deref: | |
| assert(!isRegisterLocation()); | |
| if (!isMemoryLocation() && ::isMemoryLocation(ExprCursor)) | |
| // Turning this into a memory location description makes the deref | |
| // implicit. | |
| LocationKind = Memory; | |
| else | |
| emitOp(dwarf::DW_OP_deref); | |
| break; | |
| case dwarf::DW_OP_constu: | |
| assert(!isRegisterLocation()); | |
| emitConstu(cast<DIExpression::ConstuOp>(*Op).getValue()); | |
| break; | |
| case dwarf::DW_OP_consts: | |
| assert(!isRegisterLocation()); | |
| emitOp(dwarf::DW_OP_consts); | |
| emitSigned(Op->getArg(0)); | |
| break; | |
| case dwarf::DW_OP_LLVM_convert: { | |
| auto Convert = cast<DIExpression::ConvertOp>(*Op); | |
| unsigned BitSize = Convert.getBitSize(); | |
| dwarf::TypeKind Encoding = | |
| static_cast<dwarf::TypeKind>(Convert.getEncoding()); | |
| if (DwarfVersion >= 5 && CU.getDwarfDebug().useOpConvert()) { | |
| emitOp(dwarf::DW_OP_convert); | |
| // If targeting a location-list; simply emit the index into the raw | |
| // byte stream as ULEB128, DwarfDebug::emitDebugLocEntry has been | |
| // fitted with means to extract it later. | |
| // If targeting a inlined DW_AT_location; insert a DIEBaseTypeRef | |
| // (containing the index and a resolve mechanism during emit) into the | |
| // DIE value list. | |
| emitBaseTypeRef(getOrCreateBaseType(BitSize, Encoding)); | |
| } else { | |
| if (PrevConvertOp && PrevConvertOp->getBitSize() < BitSize) { | |
| if (Encoding == dwarf::DW_ATE_signed) | |
| emitLegacySExt(PrevConvertOp->getBitSize()); | |
| else if (Encoding == dwarf::DW_ATE_unsigned) | |
| emitLegacyZExt(PrevConvertOp->getBitSize()); | |
| PrevConvertOp = std::nullopt; | |
| } else { | |
| PrevConvertOp = Convert; | |
| } | |
| } | |
| 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 = cast<DIExpression::TagOffsetOp>(*Op).getTagOffset(); | |
| 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; | |
| case dwarf::DW_OP_LLVM_implicit_pointer: | |
| // Handled in DwarfCompileUnit::emitImplicitPointerLocation for | |
| // Loc::Single variables. If we reach here, the variable has a | |
| // location list or other unsupported path. Drop the | |
| // location rather than crashing. | |
| return false; | |
| default: | |
| llvm_unreachable("unhandled opcode found in expression"); | |
| } | |
| } | |
| if (isImplicitLocation() && !isParameterValue()) | |
| // Turn this into an implicit location description. | |
| addStackValue(); | |
| return true; | |
| } | |
| /// Emit shift/mask operations for the pending subregister. After the operations | |
| /// are emitted, consume the pending subregister description by clearing | |
| /// SubRegisterSizeInBits and SubRegisterOffsetInBits. | |
| void DwarfExpression::maskSubRegister() { | |
| assert(SubRegisterSizeInBits && "no subregister was registered"); | |
| if (SubRegisterOffsetInBits > 0) | |
| addShr(SubRegisterOffsetInBits); | |
| uint64_t Mask = (1ULL << (uint64_t)SubRegisterSizeInBits) - 1ULL; | |
| addAnd(Mask); | |
| // The mask consumes the pending subregister description. | |
| setSubRegisterPiece(0, 0); | |
| } | |
| void DwarfExpression::finalize() { | |
| assert(DwarfRegs.size() == 0 && "dwarf registers not emitted"); | |
| // Emit any outstanding DW_OP_piece operations to mask out subregisters. | |
| if (SubRegisterSizeInBits == 0) | |
| return; | |
| // Don't emit a DW_OP_piece for a subregister at offset 0. | |
| 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) { | |
| // (((X >> (FromBits - 1)) * (~0)) << FromBits) | X | |
| 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) { | |
| // Heuristic to decide the most efficient encoding. | |
| // A ULEB can encode 7 1-bits per byte. | |
| if (FromBits / 7 < 1+1+1+1+1) { | |
| // (X & (1 << FromBits - 1)) | |
| emitOp(dwarf::DW_OP_constu); | |
| emitUnsigned((1ULL << FromBits) - 1); | |
| } else { | |
| // Note that the DWARF 4 stack consists of pointer-sized elements, | |
| // so technically it doesn't make sense to shift left more than 64 | |
| // bits. We leave that for the consumer to decide though. LLDB for | |
| // example uses APInt for the stack elements and can still deal | |
| // with this. | |
| 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/*TI_LOCAL_INDIRECT*/ ? 0/*TI_LOCAL*/ : Index); | |
| emitUnsigned(Offset); | |
| if (Index == 4 /*TI_LOCAL_INDIRECT*/) { | |
| assert(LocationKind == Unknown); | |
| LocationKind = Memory; | |
| } else { | |
| assert(LocationKind == Implicit || LocationKind == Unknown); | |
| LocationKind = Implicit; | |
| } | |
| } |