/// EmitDwarfRegOp - Emit dwarf register operation. void AsmPrinter::EmitDwarfRegOp(ByteStreamer &Streamer, const MachineLocation &MLoc, bool Indirect) const { const TargetRegisterInfo *TRI = TM.getRegisterInfo(); int Reg = TRI->getDwarfRegNum(MLoc.getReg(), false); if (Reg < 0) { // We assume that pointers are always in an addressable register. if (Indirect || MLoc.isIndirect()) { // FIXME: We have no reasonable way of handling errors in here. The // caller might be in the middle of a dwarf expression. We should // probably assert that Reg >= 0 once debug info generation is more // mature. Streamer.EmitInt8(dwarf::DW_OP_nop, "nop (invalid dwarf register number for indirect loc)"); return; } // Attempt to find a valid super- or sub-register. if (!Indirect && !MLoc.isIndirect()) return EmitDwarfRegOpPiece(Streamer, *this, MLoc); } if (MLoc.isIndirect()) emitDwarfRegOpIndirect(Streamer, Reg, MLoc.getOffset(), Indirect); else if (Indirect) emitDwarfRegOpIndirect(Streamer, Reg, 0, false); else emitDwarfRegOp(Streamer, Reg); }
/// EmitDwarfRegOp - Emit dwarf register operation. void AsmPrinter::EmitDwarfRegOp(ByteStreamer &Streamer, const MachineLocation &MLoc) const { DebugLocDwarfExpression Expr(*MF->getSubtarget().getRegisterInfo(), getDwarfDebug()->getDwarfVersion(), Streamer); const MCRegisterInfo *MRI = MMI->getContext().getRegisterInfo(); int Reg = MRI->getDwarfRegNum(MLoc.getReg(), false); if (Reg < 0) { // We assume that pointers are always in an addressable register. if (MLoc.isIndirect()) // FIXME: We have no reasonable way of handling errors in here. The // caller might be in the middle of a dwarf expression. We should // probably assert that Reg >= 0 once debug info generation is more // mature. return Expr.EmitOp(dwarf::DW_OP_nop, "nop (could not find a dwarf register number)"); // Attempt to find a valid super- or sub-register. if (!Expr.AddMachineRegPiece(MLoc.getReg())) Expr.EmitOp(dwarf::DW_OP_nop, "nop (could not find a dwarf register number)"); return; } if (MLoc.isIndirect()) Expr.AddRegIndirect(Reg, MLoc.getOffset()); else Expr.AddReg(Reg); }
/// addComplexAddress - Start with the address based on the location provided, /// and generate the DWARF information necessary to find the actual variable /// given the extra address information encoded in the DIVariable, starting from /// the starting location. Add the DWARF information to the die. /// void CompileUnit::addComplexAddress(DbgVariable *&DV, DIE *Die, unsigned Attribute, const MachineLocation &Location) { DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); unsigned N = DV->getNumAddrElements(); unsigned i = 0; if (Location.isReg()) { if (N >= 2 && DV->getAddrElement(0) == DIBuilder::OpPlus) { // If first address element is OpPlus then emit // DW_OP_breg + Offset instead of DW_OP_reg + Offset. addRegisterOffset(Block, Location.getReg(), DV->getAddrElement(1)); i = 2; } else addRegisterOp(Block, Location.getReg()); } else addRegisterOffset(Block, Location.getReg(), Location.getOffset()); for (;i < N; ++i) { uint64_t Element = DV->getAddrElement(i); if (Element == DIBuilder::OpPlus) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); addUInt(Block, 0, dwarf::DW_FORM_udata, DV->getAddrElement(++i)); } else if (Element == DIBuilder::OpDeref) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); } else llvm_unreachable("unknown DIBuilder Opcode"); } // Now attach the location information to the DIE. addBlock(Die, Attribute, 0, Block); }
// Some targets do not provide a DWARF register number for every // register. This function attempts to emit a DWARF register by // emitting a piece of a super-register or by piecing together // multiple subregisters that alias the register. void AsmPrinter::EmitDwarfRegOpPiece(ByteStreamer &Streamer, const MachineLocation &MLoc, unsigned PieceSizeInBits, unsigned PieceOffsetInBits) const { assert(MLoc.isReg() && "MLoc must be a register"); DebugLocDwarfExpression Expr(*this, Streamer); Expr.AddMachineRegPiece(MLoc.getReg(), PieceSizeInBits, PieceOffsetInBits); }
MachineLocation X86AsmPrinter::getDebugValueLocation(const MachineInstr *MI) const { MachineLocation Location; assert (MI->getNumOperands() == 7 && "Invalid no. of machine operands!"); // Frame address. Currently handles register +- offset only. assert(MI->getOperand(0).isReg() && MI->getOperand(3).isImm()); Location.set(MI->getOperand(0).getReg(), MI->getOperand(3).getImm()); return Location; }
MachineLocation AArch64AsmPrinter::getDebugValueLocation(const MachineInstr *MI) const { MachineLocation Location; assert(MI->getNumOperands() == 4 && "Invalid no. of machine operands!"); // Frame address. Currently handles register +- offset only. if (MI->getOperand(0).isReg() && MI->getOperand(1).isImm()) Location.set(MI->getOperand(0).getReg(), MI->getOperand(1).getImm()); else { DEBUG(dbgs() << "DBG_VALUE instruction ignored! " << *MI << "\n"); } return Location; }
/// addAddress - Add an address attribute to a die based on the location /// provided. void CompileUnit::addAddress(DIE *Die, unsigned Attribute, const MachineLocation &Location) { DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); if (Location.isReg()) addRegisterOp(Block, Location.getReg()); else addRegisterOffset(Block, Location.getReg(), Location.getOffset()); // Now attach the location information to the DIE. addBlock(Die, Attribute, 0, Block); }
/// Add an address attribute to a die based on the location provided. void DwarfCompileUnit::addAddress(DIE &Die, dwarf::Attribute Attribute, const MachineLocation &Location) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); if (Location.isIndirect()) DwarfExpr.setMemoryLocationKind(); DIExpressionCursor Cursor({}); const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo(); if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg())) return; DwarfExpr.addExpression(std::move(Cursor)); // Now attach the location information to the DIE. addBlock(Die, Attribute, DwarfExpr.finalize()); }
/// Some targets do not provide a DWARF register number for every /// register. This function attempts to emit a dwarf register by /// emitting a piece of a super-register or by piecing together /// multiple subregisters that alias the register. static void EmitDwarfRegOpPiece(ByteStreamer &Streamer, const AsmPrinter &AP, const MachineLocation &MLoc) { assert(!MLoc.isIndirect()); const TargetRegisterInfo *TRI = AP.TM.getRegisterInfo(); int Reg = TRI->getDwarfRegNum(MLoc.getReg(), false); // Walk up the super-register chain until we find a valid number. // For example, EAX on x86_64 is a 32-bit piece of RAX with offset 0. for (MCSuperRegIterator SR(MLoc.getReg(), TRI); SR.isValid(); ++SR) { Reg = TRI->getDwarfRegNum(*SR, false); if (Reg >= 0) { unsigned Idx = TRI->getSubRegIndex(*SR, MLoc.getReg()); unsigned Size = TRI->getSubRegIdxSize(Idx); unsigned Offset = TRI->getSubRegIdxOffset(Idx); AP.OutStreamer.AddComment("super-register"); emitDwarfRegOp(Streamer, Reg); emitDwarfOpPiece(Streamer, Size, Offset); return; } } // Otherwise, attempt to find a covering set of sub-register numbers. // For example, Q0 on ARM is a composition of D0+D1. // // Keep track of the current position so we can emit the more // efficient DW_OP_piece. unsigned CurPos = 0; // The size of the register in bits, assuming 8 bits per byte. unsigned RegSize = TRI->getMinimalPhysRegClass(MLoc.getReg())->getSize() * 8; // Keep track of the bits in the register we already emitted, so we // can avoid emitting redundant aliasing subregs. SmallBitVector Coverage(RegSize, false); for (MCSubRegIterator SR(MLoc.getReg(), TRI); SR.isValid(); ++SR) { unsigned Idx = TRI->getSubRegIndex(MLoc.getReg(), *SR); unsigned Size = TRI->getSubRegIdxSize(Idx); unsigned Offset = TRI->getSubRegIdxOffset(Idx); Reg = TRI->getDwarfRegNum(*SR, false); // Intersection between the bits we already emitted and the bits // covered by this subregister. SmallBitVector Intersection(RegSize, false); Intersection.set(Offset, Offset + Size); Intersection ^= Coverage; // If this sub-register has a DWARF number and we haven't covered // its range, emit a DWARF piece for it. if (Reg >= 0 && Intersection.any()) { AP.OutStreamer.AddComment("sub-register"); emitDwarfRegOp(Streamer, Reg); emitDwarfOpPiece(Streamer, Size, Offset == CurPos ? 0 : Offset); CurPos = Offset + Size; // Mark it as emitted. Coverage.set(Offset, Offset + Size); } } if (CurPos == 0) { // FIXME: We have no reasonable way of handling errors in here. Streamer.EmitInt8(dwarf::DW_OP_nop, "nop (could not find a dwarf register number)"); } }
// Some targets do not provide a DWARF register number for every // register. This function attempts to emit a DWARF register by // emitting a piece of a super-register or by piecing together // multiple subregisters that alias the register. void AsmPrinter::EmitDwarfRegOpPiece(ByteStreamer &Streamer, const MachineLocation &MLoc, unsigned PieceSizeInBits, unsigned PieceOffsetInBits) const { assert(MLoc.isReg() && "MLoc must be a register"); const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo(); int Reg = TRI->getDwarfRegNum(MLoc.getReg(), false); // If this is a valid register number, emit it. if (Reg >= 0) { emitDwarfRegOp(Streamer, Reg); EmitDwarfOpPiece(Streamer, PieceSizeInBits, PieceOffsetInBits); return; } // Walk up the super-register chain until we find a valid number. // For example, EAX on x86_64 is a 32-bit piece of RAX with offset 0. for (MCSuperRegIterator SR(MLoc.getReg(), TRI); SR.isValid(); ++SR) { Reg = TRI->getDwarfRegNum(*SR, false); if (Reg >= 0) { unsigned Idx = TRI->getSubRegIndex(*SR, MLoc.getReg()); unsigned Size = TRI->getSubRegIdxSize(Idx); unsigned RegOffset = TRI->getSubRegIdxOffset(Idx); OutStreamer.AddComment("super-register"); emitDwarfRegOp(Streamer, Reg); if (PieceOffsetInBits == RegOffset) { EmitDwarfOpPiece(Streamer, Size, RegOffset); } else { // If this is part of a variable in a sub-register at a // non-zero offset, we need to manually shift the value into // place, since the DW_OP_piece describes the part of the // variable, not the position of the subregister. if (RegOffset) emitDwarfOpShr(Streamer, RegOffset); EmitDwarfOpPiece(Streamer, Size, PieceOffsetInBits); } return; } } // Otherwise, attempt to find a covering set of sub-register numbers. // For example, Q0 on ARM is a composition of D0+D1. // // Keep track of the current position so we can emit the more // efficient DW_OP_piece. unsigned CurPos = PieceOffsetInBits; // The size of the register in bits, assuming 8 bits per byte. unsigned RegSize = TRI->getMinimalPhysRegClass(MLoc.getReg())->getSize() * 8; // Keep track of the bits in the register we already emitted, so we // can avoid emitting redundant aliasing subregs. SmallBitVector Coverage(RegSize, false); for (MCSubRegIterator SR(MLoc.getReg(), TRI); SR.isValid(); ++SR) { unsigned Idx = TRI->getSubRegIndex(MLoc.getReg(), *SR); unsigned Size = TRI->getSubRegIdxSize(Idx); unsigned Offset = TRI->getSubRegIdxOffset(Idx); Reg = TRI->getDwarfRegNum(*SR, false); // Intersection between the bits we already emitted and the bits // covered by this subregister. SmallBitVector Intersection(RegSize, false); Intersection.set(Offset, Offset + Size); Intersection ^= Coverage; // If this sub-register has a DWARF number and we haven't covered // its range, emit a DWARF piece for it. if (Reg >= 0 && Intersection.any()) { OutStreamer.AddComment("sub-register"); emitDwarfRegOp(Streamer, Reg); EmitDwarfOpPiece(Streamer, Size, Offset == CurPos ? 0 : Offset); CurPos = Offset + Size; // Mark it as emitted. Coverage.set(Offset, Offset + Size); } } if (CurPos == PieceOffsetInBits) { // FIXME: We have no reasonable way of handling errors in here. Streamer.EmitInt8(dwarf::DW_OP_nop, "nop (could not find a dwarf register number)"); } }
/// addBlockByrefAddress - Start with the address based on the location /// provided, and generate the DWARF information necessary to find the /// actual Block variable (navigating the Block struct) based on the /// starting location. Add the DWARF information to the die. For /// more information, read large comment just above here. /// void CompileUnit::addBlockByrefAddress(DbgVariable *&DV, DIE *Die, unsigned Attribute, const MachineLocation &Location) { DIType Ty = DV->getType(); DIType TmpTy = Ty; unsigned Tag = Ty.getTag(); bool isPointer = false; StringRef varName = DV->getName(); if (Tag == dwarf::DW_TAG_pointer_type) { DIDerivedType DTy = DIDerivedType(Ty); TmpTy = DTy.getTypeDerivedFrom(); isPointer = true; } DICompositeType blockStruct = DICompositeType(TmpTy); // Find the __forwarding field and the variable field in the __Block_byref // struct. DIArray Fields = blockStruct.getTypeArray(); DIDescriptor varField = DIDescriptor(); DIDescriptor forwardingField = DIDescriptor(); for (unsigned i = 0, N = Fields.getNumElements(); i < N; ++i) { DIDescriptor Element = Fields.getElement(i); DIDerivedType DT = DIDerivedType(Element); StringRef fieldName = DT.getName(); if (fieldName == "__forwarding") forwardingField = Element; else if (fieldName == varName) varField = Element; } // Get the offsets for the forwarding field and the variable field. unsigned forwardingFieldOffset = DIDerivedType(forwardingField).getOffsetInBits() >> 3; unsigned varFieldOffset = DIDerivedType(varField).getOffsetInBits() >> 3; // Decode the original location, and use that as the start of the byref // variable's location. const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); unsigned Reg = RI->getDwarfRegNum(Location.getReg(), false); DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); if (Location.isReg()) { if (Reg < 32) addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_reg0 + Reg); else { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_regx); addUInt(Block, 0, dwarf::DW_FORM_udata, Reg); } } else { if (Reg < 32) addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_breg0 + Reg); else { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_bregx); addUInt(Block, 0, dwarf::DW_FORM_udata, Reg); } addUInt(Block, 0, dwarf::DW_FORM_sdata, Location.getOffset()); } // If we started with a pointer to the __Block_byref... struct, then // the first thing we need to do is dereference the pointer (DW_OP_deref). if (isPointer) addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); // Next add the offset for the '__forwarding' field: // DW_OP_plus_uconst ForwardingFieldOffset. Note there's no point in // adding the offset if it's 0. if (forwardingFieldOffset > 0) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); addUInt(Block, 0, dwarf::DW_FORM_udata, forwardingFieldOffset); } // Now dereference the __forwarding field to get to the real __Block_byref // struct: DW_OP_deref. addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); // Now that we've got the real __Block_byref... struct, add the offset // for the variable's field to get to the location of the actual variable: // DW_OP_plus_uconst varFieldOffset. Again, don't add if it's 0. if (varFieldOffset > 0) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); addUInt(Block, 0, dwarf::DW_FORM_udata, varFieldOffset); } // Now attach the location information to the DIE. addBlock(Die, Attribute, 0, Block); }