#define DEBUG_TYPE "dwarfdebug"
#include "DwarfUnit.h"
#include "DwarfAccelTable.h"
#include "DwarfDebug.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/DIBuilder.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Mangler.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetFrameLowering.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
using namespace llvm;
static cl::opt<bool>
GenerateDwarfTypeUnits("generate-type-units", cl::Hidden,
cl::desc("Generate DWARF4 type units."),
cl::init(false));
DwarfUnit::DwarfUnit(unsigned UID, DIE *D, DICompileUnit Node, AsmPrinter *A,
DwarfDebug *DW, DwarfFile *DWU)
: UniqueID(UID), CUNode(Node), UnitDie(D), DebugInfoOffset(0), Asm(A),
DD(DW), DU(DWU), IndexTyDie(0), Section(0), Skeleton(0) {
DIEIntegerOne = new (DIEValueAllocator) DIEInteger(1);
}
DwarfCompileUnit::DwarfCompileUnit(unsigned UID, DIE *D, DICompileUnit Node,
AsmPrinter *A, DwarfDebug *DW,
DwarfFile *DWU)
: DwarfUnit(UID, D, Node, A, DW, DWU) {
insertDIE(Node, D);
}
DwarfTypeUnit::DwarfTypeUnit(unsigned UID, DIE *D, DICompileUnit CUNode,
AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU)
: DwarfUnit(UID, D, CUNode, A, DW, DWU) {}
DwarfUnit::~DwarfUnit() {
for (unsigned j = 0, M = DIEBlocks.size(); j < M; ++j)
DIEBlocks[j]->~DIEBlock();
}
DIEEntry *DwarfUnit::createDIEEntry(DIE *Entry) {
DIEEntry *Value = new (DIEValueAllocator) DIEEntry(Entry);
return Value;
}
int64_t DwarfUnit::getDefaultLowerBound() const {
switch (getLanguage()) {
default:
break;
case dwarf::DW_LANG_C89:
case dwarf::DW_LANG_C99:
case dwarf::DW_LANG_C:
case dwarf::DW_LANG_C_plus_plus:
case dwarf::DW_LANG_ObjC:
case dwarf::DW_LANG_ObjC_plus_plus:
return 0;
case dwarf::DW_LANG_Fortran77:
case dwarf::DW_LANG_Fortran90:
case dwarf::DW_LANG_Fortran95:
return 1;
case dwarf::DW_LANG_Java:
case dwarf::DW_LANG_Python:
case dwarf::DW_LANG_UPC:
case dwarf::DW_LANG_D:
if (dwarf::DWARF_VERSION >= 4)
return 0;
break;
case dwarf::DW_LANG_Ada83:
case dwarf::DW_LANG_Ada95:
case dwarf::DW_LANG_Cobol74:
case dwarf::DW_LANG_Cobol85:
case dwarf::DW_LANG_Modula2:
case dwarf::DW_LANG_Pascal83:
case dwarf::DW_LANG_PLI:
if (dwarf::DWARF_VERSION >= 4)
return 1;
break;
}
return -1;
}
static bool isShareableAcrossCUs(DIDescriptor D) {
return (D.isType() ||
(D.isSubprogram() && !DISubprogram(D).isDefinition())) &&
!GenerateDwarfTypeUnits;
}
DIE *DwarfUnit::getDIE(DIDescriptor D) const {
if (isShareableAcrossCUs(D))
return DD->getDIE(D);
return MDNodeToDieMap.lookup(D);
}
void DwarfUnit::insertDIE(DIDescriptor Desc, DIE *D) {
if (isShareableAcrossCUs(Desc)) {
DD->insertDIE(Desc, D);
return;
}
MDNodeToDieMap.insert(std::make_pair(Desc, D));
}
void DwarfUnit::addFlag(DIE *Die, dwarf::Attribute Attribute) {
if (DD->getDwarfVersion() >= 4)
Die->addValue(Attribute, dwarf::DW_FORM_flag_present, DIEIntegerOne);
else
Die->addValue(Attribute, dwarf::DW_FORM_flag, DIEIntegerOne);
}
void DwarfUnit::addUInt(DIE *Die, dwarf::Attribute Attribute,
Optional<dwarf::Form> Form, uint64_t Integer) {
if (!Form)
Form = DIEInteger::BestForm(false, Integer);
DIEValue *Value = Integer == 1 ? DIEIntegerOne : new (DIEValueAllocator)
DIEInteger(Integer);
Die->addValue(Attribute, *Form, Value);
}
void DwarfUnit::addUInt(DIEBlock *Block, dwarf::Form Form, uint64_t Integer) {
addUInt(Block, (dwarf::Attribute)0, Form, Integer);
}
void DwarfUnit::addSInt(DIE *Die, dwarf::Attribute Attribute,
Optional<dwarf::Form> Form, int64_t Integer) {
if (!Form)
Form = DIEInteger::BestForm(true, Integer);
DIEValue *Value = new (DIEValueAllocator) DIEInteger(Integer);
Die->addValue(Attribute, *Form, Value);
}
void DwarfUnit::addSInt(DIEBlock *Die, Optional<dwarf::Form> Form,
int64_t Integer) {
addSInt(Die, (dwarf::Attribute)0, Form, Integer);
}
void DwarfUnit::addString(DIE *Die, dwarf::Attribute Attribute,
StringRef String) {
if (!DD->useSplitDwarf())
return addLocalString(Die, Attribute, String);
unsigned idx = DU->getStringPoolIndex(String);
DIEValue *Value = new (DIEValueAllocator) DIEInteger(idx);
DIEValue *Str = new (DIEValueAllocator) DIEString(Value, String);
Die->addValue(Attribute, dwarf::DW_FORM_GNU_str_index, Str);
}
void DwarfUnit::addLocalString(DIE *Die, dwarf::Attribute Attribute,
StringRef String) {
MCSymbol *Symb = DU->getStringPoolEntry(String);
DIEValue *Value;
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
Value = new (DIEValueAllocator) DIELabel(Symb);
else {
MCSymbol *StringPool = DU->getStringPoolSym();
Value = new (DIEValueAllocator) DIEDelta(Symb, StringPool);
}
DIEValue *Str = new (DIEValueAllocator) DIEString(Value, String);
Die->addValue(Attribute, dwarf::DW_FORM_strp, Str);
}
void DwarfUnit::addExpr(DIEBlock *Die, dwarf::Form Form, const MCExpr *Expr) {
DIEValue *Value = new (DIEValueAllocator) DIEExpr(Expr);
Die->addValue((dwarf::Attribute)0, Form, Value);
}
void DwarfUnit::addLabel(DIE *Die, dwarf::Attribute Attribute, dwarf::Form Form,
const MCSymbol *Label) {
DIEValue *Value = new (DIEValueAllocator) DIELabel(Label);
Die->addValue(Attribute, Form, Value);
}
void DwarfUnit::addLabel(DIEBlock *Die, dwarf::Form Form,
const MCSymbol *Label) {
addLabel(Die, (dwarf::Attribute)0, Form, Label);
}
void DwarfUnit::addSectionLabel(DIE *Die, dwarf::Attribute Attribute,
const MCSymbol *Label) {
if (DD->getDwarfVersion() >= 4)
addLabel(Die, Attribute, dwarf::DW_FORM_sec_offset, Label);
else
addLabel(Die, Attribute, dwarf::DW_FORM_data4, Label);
}
void DwarfUnit::addSectionOffset(DIE *Die, dwarf::Attribute Attribute,
uint64_t Integer) {
if (DD->getDwarfVersion() >= 4)
addUInt(Die, Attribute, dwarf::DW_FORM_sec_offset, Integer);
else
addUInt(Die, Attribute, dwarf::DW_FORM_data4, Integer);
}
void DwarfCompileUnit::addLabelAddress(DIE *Die, dwarf::Attribute Attribute,
MCSymbol *Label) {
if (Label)
DD->addArangeLabel(SymbolCU(this, Label));
if (!DD->useSplitDwarf()) {
if (Label) {
DIEValue *Value = new (DIEValueAllocator) DIELabel(Label);
Die->addValue(Attribute, dwarf::DW_FORM_addr, Value);
} else {
DIEValue *Value = new (DIEValueAllocator) DIEInteger(0);
Die->addValue(Attribute, dwarf::DW_FORM_addr, Value);
}
} else {
unsigned idx = DU->getAddrPoolIndex(Label);
DIEValue *Value = new (DIEValueAllocator) DIEInteger(idx);
Die->addValue(Attribute, dwarf::DW_FORM_GNU_addr_index, Value);
}
}
void DwarfUnit::addOpAddress(DIEBlock *Die, const MCSymbol *Sym) {
if (!DD->useSplitDwarf()) {
addUInt(Die, dwarf::DW_FORM_data1, dwarf::DW_OP_addr);
addLabel(Die, dwarf::DW_FORM_udata, Sym);
} else {
addUInt(Die, dwarf::DW_FORM_data1, dwarf::DW_OP_GNU_addr_index);
addUInt(Die, dwarf::DW_FORM_GNU_addr_index, DU->getAddrPoolIndex(Sym));
}
}
void DwarfUnit::addSectionDelta(DIE *Die, dwarf::Attribute Attribute,
const MCSymbol *Hi, const MCSymbol *Lo) {
DIEValue *Value = new (DIEValueAllocator) DIEDelta(Hi, Lo);
if (DD->getDwarfVersion() >= 4)
Die->addValue(Attribute, dwarf::DW_FORM_sec_offset, Value);
else
Die->addValue(Attribute, dwarf::DW_FORM_data4, Value);
}
void DwarfUnit::addDIEEntry(DIE *Die, dwarf::Attribute Attribute, DIE *Entry) {
addDIEEntry(Die, Attribute, createDIEEntry(Entry));
}
void DwarfUnit::addDIETypeSignature(DIE *Die, const DwarfTypeUnit &Type) {
Die->addValue(dwarf::DW_AT_signature, dwarf::DW_FORM_ref_sig8,
new (DIEValueAllocator) DIETypeSignature(Type));
}
void DwarfUnit::addDIEEntry(DIE *Die, dwarf::Attribute Attribute,
DIEEntry *Entry) {
const DIE *DieCU = Die->getUnitOrNull();
const DIE *EntryCU = Entry->getEntry()->getUnitOrNull();
if (!DieCU)
DieCU = getUnitDie();
if (!EntryCU)
EntryCU = getUnitDie();
Die->addValue(Attribute, EntryCU == DieCU ? dwarf::DW_FORM_ref4
: dwarf::DW_FORM_ref_addr,
Entry);
}
DIE *DwarfUnit::createAndAddDIE(unsigned Tag, DIE &Parent, DIDescriptor N) {
DIE *Die = new DIE(Tag);
Parent.addChild(Die);
if (N)
insertDIE(N, Die);
return Die;
}
void DwarfUnit::addBlock(DIE *Die, dwarf::Attribute Attribute,
DIEBlock *Block) {
Block->ComputeSize(Asm);
DIEBlocks.push_back(Block); Die->addValue(Attribute, Block->BestForm(), Block);
}
void DwarfUnit::addSourceLine(DIE *Die, DIVariable V) {
if (!V.isVariable())
return;
unsigned Line = V.getLineNumber();
if (Line == 0)
return;
unsigned FileID =
DD->getOrCreateSourceID(V.getContext().getFilename(),
V.getContext().getDirectory(), getUniqueID());
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, None, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, None, Line);
}
void DwarfUnit::addSourceLine(DIE *Die, DIGlobalVariable G) {
if (!G.isGlobalVariable())
return;
unsigned Line = G.getLineNumber();
if (Line == 0)
return;
unsigned FileID =
DD->getOrCreateSourceID(G.getFilename(), G.getDirectory(), getUniqueID());
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, None, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, None, Line);
}
void DwarfUnit::addSourceLine(DIE *Die, DISubprogram SP) {
if (!SP.isSubprogram())
return;
unsigned Line = SP.getLineNumber();
if (Line == 0)
return;
unsigned FileID = DD->getOrCreateSourceID(SP.getFilename(), SP.getDirectory(),
getUniqueID());
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, None, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, None, Line);
}
void DwarfUnit::addSourceLine(DIE *Die, DIType Ty) {
if (!Ty.isType())
return;
unsigned Line = Ty.getLineNumber();
if (Line == 0)
return;
unsigned FileID = DD->getOrCreateSourceID(Ty.getFilename(), Ty.getDirectory(),
getUniqueID());
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, None, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, None, Line);
}
void DwarfUnit::addSourceLine(DIE *Die, DIObjCProperty Ty) {
if (!Ty.isObjCProperty())
return;
unsigned Line = Ty.getLineNumber();
if (Line == 0)
return;
DIFile File = Ty.getFile();
unsigned FileID = DD->getOrCreateSourceID(File.getFilename(),
File.getDirectory(), getUniqueID());
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, None, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, None, Line);
}
void DwarfUnit::addSourceLine(DIE *Die, DINameSpace NS) {
if (!NS.Verify())
return;
unsigned Line = NS.getLineNumber();
if (Line == 0)
return;
StringRef FN = NS.getFilename();
unsigned FileID =
DD->getOrCreateSourceID(FN, NS.getDirectory(), getUniqueID());
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, None, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, None, Line);
}
void DwarfUnit::addSourceLine(DIE *Die, DIModule M) {
if (!M.Verify())
return;
unsigned Line = M.getLineNumber();
if (Line == 0)
return;
StringRef FN = M.getFilename();
unsigned FileID =
DD->getOrCreateSourceID(FN, M.getDirectory(), getUniqueID());
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, None, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, None, Line);
}
void DwarfUnit::addVariableAddress(const DbgVariable &DV, DIE *Die,
MachineLocation Location) {
if (DV.variableHasComplexAddress())
addComplexAddress(DV, Die, dwarf::DW_AT_location, Location);
else if (DV.isBlockByrefVariable())
addBlockByrefAddress(DV, Die, dwarf::DW_AT_location, Location);
else
addAddress(Die, dwarf::DW_AT_location, Location,
DV.getVariable().isIndirect());
}
void DwarfUnit::addRegisterOp(DIEBlock *TheDie, unsigned Reg) {
const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo();
int DWReg = RI->getDwarfRegNum(Reg, false);
bool isSubRegister = DWReg < 0;
unsigned Idx = 0;
for (MCSuperRegIterator SR(Reg, RI); SR.isValid() && DWReg < 0; ++SR) {
DWReg = RI->getDwarfRegNum(*SR, false);
if (DWReg >= 0)
Idx = RI->getSubRegIndex(*SR, Reg);
}
if (DWReg < 0) {
DEBUG(llvm::dbgs() << "Invalid Dwarf register number.\n");
addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_nop);
return;
}
if (DWReg < 32)
addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_reg0 + DWReg);
else {
addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_regx);
addUInt(TheDie, dwarf::DW_FORM_udata, DWReg);
}
if (isSubRegister) {
unsigned Size = RI->getSubRegIdxSize(Idx);
unsigned Offset = RI->getSubRegIdxOffset(Idx);
if (Offset > 0) {
addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_bit_piece);
addUInt(TheDie, dwarf::DW_FORM_data1, Size);
addUInt(TheDie, dwarf::DW_FORM_data1, Offset);
} else {
unsigned ByteSize = Size / 8; addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_piece);
addUInt(TheDie, dwarf::DW_FORM_data1, ByteSize);
}
}
}
void DwarfUnit::addRegisterOffset(DIEBlock *TheDie, unsigned Reg,
int64_t Offset) {
const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo();
unsigned DWReg = RI->getDwarfRegNum(Reg, false);
const TargetRegisterInfo *TRI = Asm->TM.getRegisterInfo();
if (Reg == TRI->getFrameRegister(*Asm->MF))
addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_fbreg);
else if (DWReg < 32)
addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_breg0 + DWReg);
else {
addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_bregx);
addUInt(TheDie, dwarf::DW_FORM_udata, DWReg);
}
addSInt(TheDie, dwarf::DW_FORM_sdata, Offset);
}
void DwarfUnit::addAddress(DIE *Die, dwarf::Attribute Attribute,
const MachineLocation &Location, bool Indirect) {
DIEBlock *Block = new (DIEValueAllocator) DIEBlock();
if (Location.isReg() && !Indirect)
addRegisterOp(Block, Location.getReg());
else {
addRegisterOffset(Block, Location.getReg(), Location.getOffset());
if (Indirect && !Location.isReg()) {
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_deref);
}
}
addBlock(Die, Attribute, Block);
}
void DwarfUnit::addComplexAddress(const DbgVariable &DV, DIE *Die,
dwarf::Attribute 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) {
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, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
addUInt(Block, dwarf::DW_FORM_udata, DV.getAddrElement(++i));
} else if (Element == DIBuilder::OpDeref) {
if (!Location.isReg())
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_deref);
} else if (Element == DIBuilder::OpPiece) {
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_bit_piece);
addUInt(Block, dwarf::DW_FORM_udata, DV.getAddrElement(++i));
addUInt(Block, dwarf::DW_FORM_udata, DV.getAddrElement(++i));
} else
llvm_unreachable("unknown DIBuilder Opcode");
}
addBlock(Die, Attribute, Block);
}
void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE *Die,
dwarf::Attribute Attribute,
const MachineLocation &Location) {
DIType Ty = DV.getType();
DIType TmpTy = Ty;
uint16_t Tag = Ty.getTag();
bool isPointer = false;
StringRef varName = DV.getName();
if (Tag == dwarf::DW_TAG_pointer_type) {
DIDerivedType DTy(Ty);
TmpTy = resolve(DTy.getTypeDerivedFrom());
isPointer = true;
}
DICompositeType blockStruct(TmpTy);
DIArray Fields = blockStruct.getTypeArray();
DIDerivedType varField;
DIDerivedType forwardingField;
for (unsigned i = 0, N = Fields.getNumElements(); i < N; ++i) {
DIDerivedType DT(Fields.getElement(i));
StringRef fieldName = DT.getName();
if (fieldName == "__forwarding")
forwardingField = DT;
else if (fieldName == varName)
varField = DT;
}
unsigned forwardingFieldOffset = forwardingField.getOffsetInBits() >> 3;
unsigned varFieldOffset = varField.getOffsetInBits() >> 2;
DIEBlock *Block = new (DIEValueAllocator) DIEBlock();
if (Location.isReg())
addRegisterOp(Block, Location.getReg());
else
addRegisterOffset(Block, Location.getReg(), Location.getOffset());
if (isPointer)
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_deref);
if (forwardingFieldOffset > 0) {
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
addUInt(Block, dwarf::DW_FORM_udata, forwardingFieldOffset);
}
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_deref);
if (varFieldOffset > 0) {
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
addUInt(Block, dwarf::DW_FORM_udata, varFieldOffset);
}
addBlock(Die, Attribute, Block);
}
static bool isTypeSigned(DwarfDebug *DD, DIType Ty, int *SizeInBits) {
if (Ty.isDerivedType())
return isTypeSigned(DD, DD->resolve(DIDerivedType(Ty).getTypeDerivedFrom()),
SizeInBits);
if (Ty.isBasicType())
if (DIBasicType(Ty).getEncoding() == dwarf::DW_ATE_signed ||
DIBasicType(Ty).getEncoding() == dwarf::DW_ATE_signed_char) {
*SizeInBits = Ty.getSizeInBits();
return true;
}
return false;
}
static bool isUnsignedDIType(DwarfDebug *DD, DIType Ty) {
DIDerivedType DTy(Ty);
if (DTy.isDerivedType())
return isUnsignedDIType(DD, DD->resolve(DTy.getTypeDerivedFrom()));
DIBasicType BTy(Ty);
if (BTy.isBasicType()) {
unsigned Encoding = BTy.getEncoding();
if (Encoding == dwarf::DW_ATE_unsigned ||
Encoding == dwarf::DW_ATE_unsigned_char ||
Encoding == dwarf::DW_ATE_boolean)
return true;
}
return false;
}
static uint64_t getBaseTypeSize(DwarfDebug *DD, DIDerivedType Ty) {
unsigned Tag = Ty.getTag();
if (Tag != dwarf::DW_TAG_member && Tag != dwarf::DW_TAG_typedef &&
Tag != dwarf::DW_TAG_const_type && Tag != dwarf::DW_TAG_volatile_type &&
Tag != dwarf::DW_TAG_restrict_type)
return Ty.getSizeInBits();
DIType BaseType = DD->resolve(Ty.getTypeDerivedFrom());
if (!BaseType.isValid())
return Ty.getSizeInBits();
if (BaseType.getTag() == dwarf::DW_TAG_reference_type ||
BaseType.getTag() == dwarf::DW_TAG_rvalue_reference_type)
return Ty.getSizeInBits();
if (BaseType.isDerivedType())
return getBaseTypeSize(DD, DIDerivedType(BaseType));
return BaseType.getSizeInBits();
}
void DwarfUnit::addConstantValue(DIE *Die, const MachineOperand &MO,
DIType Ty) {
assert(MO.isImm() && "Invalid machine operand!");
int SizeInBits = -1;
bool SignedConstant = isTypeSigned(DD, Ty, &SizeInBits);
dwarf::Form Form;
if (SignedConstant) {
addSInt(Die, dwarf::DW_AT_const_value, dwarf::DW_FORM_sdata, MO.getImm());
return;
}
switch (SizeInBits) {
case 8:
Form = dwarf::DW_FORM_data1;
break;
case 16:
Form = dwarf::DW_FORM_data2;
break;
case 32:
Form = dwarf::DW_FORM_data4;
break;
case 64:
Form = dwarf::DW_FORM_data8;
break;
default:
Form = dwarf::DW_FORM_udata;
addUInt(Die, dwarf::DW_AT_const_value, Form, MO.getImm());
return;
}
addUInt(Die, dwarf::DW_AT_const_value, Form, MO.getImm());
}
void DwarfUnit::addConstantFPValue(DIE *Die, const MachineOperand &MO) {
assert(MO.isFPImm() && "Invalid machine operand!");
DIEBlock *Block = new (DIEValueAllocator) DIEBlock();
APFloat FPImm = MO.getFPImm()->getValueAPF();
const APInt FltVal = FPImm.bitcastToAPInt();
const char *FltPtr = (const char *)FltVal.getRawData();
int NumBytes = FltVal.getBitWidth() / 8; bool LittleEndian = Asm->getDataLayout().isLittleEndian();
int Incr = (LittleEndian ? 1 : -1);
int Start = (LittleEndian ? 0 : NumBytes - 1);
int Stop = (LittleEndian ? NumBytes : -1);
for (; Start != Stop; Start += Incr)
addUInt(Block, dwarf::DW_FORM_data1, (unsigned char)0xFF & FltPtr[Start]);
addBlock(Die, dwarf::DW_AT_const_value, Block);
}
void DwarfUnit::addConstantFPValue(DIE *Die, const ConstantFP *CFP) {
addConstantValue(Die, CFP->getValueAPF().bitcastToAPInt(), true);
}
void DwarfUnit::addConstantValue(DIE *Die, const ConstantInt *CI,
bool Unsigned) {
addConstantValue(Die, CI->getValue(), Unsigned);
}
void DwarfUnit::addConstantValue(DIE *Die, const APInt &Val, bool Unsigned) {
unsigned CIBitWidth = Val.getBitWidth();
if (CIBitWidth <= 64) {
if (!Unsigned) {
addSInt(Die, dwarf::DW_AT_const_value, dwarf::DW_FORM_sdata,
Val.getSExtValue());
return;
}
dwarf::Form Form;
switch (CIBitWidth) {
case 8:
Form = dwarf::DW_FORM_data1;
break;
case 16:
Form = dwarf::DW_FORM_data2;
break;
case 32:
Form = dwarf::DW_FORM_data4;
break;
case 64:
Form = dwarf::DW_FORM_data8;
break;
default:
addUInt(Die, dwarf::DW_AT_const_value, dwarf::DW_FORM_udata,
Val.getZExtValue());
return;
}
addUInt(Die, dwarf::DW_AT_const_value, Form, Val.getZExtValue());
return;
}
DIEBlock *Block = new (DIEValueAllocator) DIEBlock();
const uint64_t *Ptr64 = Val.getRawData();
int NumBytes = Val.getBitWidth() / 8; bool LittleEndian = Asm->getDataLayout().isLittleEndian();
for (int i = 0; i < NumBytes; i++) {
uint8_t c;
if (LittleEndian)
c = Ptr64[i / 8] >> (8 * (i & 7));
else
c = Ptr64[(NumBytes - 1 - i) / 8] >> (8 * ((NumBytes - 1 - i) & 7));
addUInt(Block, dwarf::DW_FORM_data1, c);
}
addBlock(Die, dwarf::DW_AT_const_value, Block);
}
void DwarfUnit::addTemplateParams(DIE &Buffer, DIArray TParams) {
for (unsigned i = 0, e = TParams.getNumElements(); i != e; ++i) {
DIDescriptor Element = TParams.getElement(i);
if (Element.isTemplateTypeParameter())
constructTemplateTypeParameterDIE(Buffer,
DITemplateTypeParameter(Element));
else if (Element.isTemplateValueParameter())
constructTemplateValueParameterDIE(Buffer,
DITemplateValueParameter(Element));
}
}
DIE *DwarfUnit::getOrCreateContextDIE(DIScope Context) {
if (!Context || Context.isFile())
return getUnitDie();
if (Context.isType())
return getOrCreateTypeDIE(DIType(Context));
if (Context.isNameSpace())
return getOrCreateNameSpace(DINameSpace(Context));
if (Context.isModule())
return getOrCreateModule(DIModule(Context));
if (Context.isSubprogram())
return getOrCreateSubprogramDIE(DISubprogram(Context));
return getDIE(Context);
}
DIE *DwarfUnit::createTypeDIE(DICompositeType Ty) {
DIScope Context = resolve(Ty.getContext());
DIE *ContextDIE = getOrCreateContextDIE(Context);
DIE *TyDIE = getDIE(Ty);
if (TyDIE)
return TyDIE;
TyDIE = createAndAddDIE(Ty.getTag(), *ContextDIE, Ty);
constructTypeDIE(*TyDIE, Ty);
updateAcceleratorTables(Context, Ty, TyDIE);
return TyDIE;
}
DIE *DwarfUnit::getOrCreateTypeDIE(const MDNode *TyNode) {
if (!TyNode)
return NULL;
DIType Ty(TyNode);
assert(Ty.isType());
DIScope Context = resolve(Ty.getContext());
DIE *ContextDIE = getOrCreateContextDIE(Context);
assert(ContextDIE);
DIE *TyDIE = getDIE(Ty);
if (TyDIE)
return TyDIE;
TyDIE = createAndAddDIE(Ty.getTag(), *ContextDIE, Ty);
if (Ty.isBasicType())
constructTypeDIE(*TyDIE, DIBasicType(Ty));
else if (Ty.isCompositeType()) {
DICompositeType CTy(Ty);
if (GenerateDwarfTypeUnits && !Ty.isForwardDecl())
if (MDString *TypeId = CTy.getIdentifier()) {
DD->addDwarfTypeUnitType(getCUNode(), TypeId->getString(), TyDIE, CTy);
return TyDIE;
}
constructTypeDIE(*TyDIE, CTy);
} else {
assert(Ty.isDerivedType() && "Unknown kind of DIType");
constructTypeDIE(*TyDIE, DIDerivedType(Ty));
}
updateAcceleratorTables(Context, Ty, TyDIE);
return TyDIE;
}
void DwarfUnit::updateAcceleratorTables(DIScope Context, DIType Ty,
const DIE *TyDIE) {
if (!Ty.getName().empty() && !Ty.isForwardDecl()) {
bool IsImplementation = 0;
if (Ty.isCompositeType()) {
DICompositeType CT(Ty);
IsImplementation = (CT.getRunTimeLang() == 0) || CT.isObjcClassComplete();
}
unsigned Flags = IsImplementation ? dwarf::DW_FLAG_type_implementation : 0;
addAccelType(Ty.getName(), std::make_pair(TyDIE, Flags));
if (!Context || Context.isCompileUnit() || Context.isFile() ||
Context.isNameSpace())
GlobalTypes[getParentContextString(Context) + Ty.getName().str()] = TyDIE;
}
}
void DwarfUnit::addType(DIE *Entity, DIType Ty, dwarf::Attribute Attribute) {
assert(Ty && "Trying to add a type that doesn't exist?");
DIEEntry *Entry = getDIEEntry(Ty);
if (Entry) {
addDIEEntry(Entity, Attribute, Entry);
return;
}
DIE *Buffer = getOrCreateTypeDIE(Ty);
Entry = createDIEEntry(Buffer);
insertDIEEntry(Ty, Entry);
addDIEEntry(Entity, Attribute, Entry);
}
void DwarfUnit::addAccelName(StringRef Name, const DIE *Die) {
DU->getStringPoolEntry(Name);
std::vector<const DIE *> &DIEs = AccelNames[Name];
DIEs.push_back(Die);
}
void DwarfUnit::addAccelObjC(StringRef Name, const DIE *Die) {
DU->getStringPoolEntry(Name);
std::vector<const DIE *> &DIEs = AccelObjC[Name];
DIEs.push_back(Die);
}
void DwarfUnit::addAccelNamespace(StringRef Name, const DIE *Die) {
DU->getStringPoolEntry(Name);
std::vector<const DIE *> &DIEs = AccelNamespace[Name];
DIEs.push_back(Die);
}
void DwarfUnit::addAccelType(StringRef Name,
std::pair<const DIE *, unsigned> Die) {
DU->getStringPoolEntry(Name);
std::vector<std::pair<const DIE *, unsigned> > &DIEs = AccelTypes[Name];
DIEs.push_back(Die);
}
void DwarfUnit::addGlobalName(StringRef Name, DIE *Die, DIScope Context) {
std::string FullName = getParentContextString(Context) + Name.str();
GlobalNames[FullName] = Die;
}
std::string DwarfUnit::getParentContextString(DIScope Context) const {
if (!Context)
return "";
if (getLanguage() != dwarf::DW_LANG_C_plus_plus)
return "";
std::string CS;
SmallVector<DIScope, 1> Parents;
while (!Context.isCompileUnit()) {
Parents.push_back(Context);
if (Context.getContext())
Context = resolve(Context.getContext());
else
break;
}
for (SmallVectorImpl<DIScope>::reverse_iterator I = Parents.rbegin(),
E = Parents.rend();
I != E; ++I) {
DIScope Ctx = *I;
StringRef Name = Ctx.getName();
if (!Name.empty()) {
CS += Name;
CS += "::";
}
}
return CS;
}
void DwarfUnit::constructTypeDIE(DIE &Buffer, DIBasicType BTy) {
StringRef Name = BTy.getName();
if (!Name.empty())
addString(&Buffer, dwarf::DW_AT_name, Name);
if (BTy.getTag() == dwarf::DW_TAG_unspecified_type)
return;
addUInt(&Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1,
BTy.getEncoding());
uint64_t Size = BTy.getSizeInBits() >> 3;
addUInt(&Buffer, dwarf::DW_AT_byte_size, None, Size);
}
void DwarfUnit::constructTypeDIE(DIE &Buffer, DIDerivedType DTy) {
StringRef Name = DTy.getName();
uint64_t Size = DTy.getSizeInBits() >> 3;
uint16_t Tag = Buffer.getTag();
DIType FromTy = resolve(DTy.getTypeDerivedFrom());
if (FromTy)
addType(&Buffer, FromTy);
if (!Name.empty())
addString(&Buffer, dwarf::DW_AT_name, Name);
if (Size && Tag != dwarf::DW_TAG_pointer_type)
addUInt(&Buffer, dwarf::DW_AT_byte_size, None, Size);
if (Tag == dwarf::DW_TAG_ptr_to_member_type)
addDIEEntry(&Buffer, dwarf::DW_AT_containing_type,
getOrCreateTypeDIE(resolve(DTy.getClassType())));
if (!DTy.isForwardDecl())
addSourceLine(&Buffer, DTy);
}
void DwarfUnit::constructSubprogramArguments(DIE &Buffer, DIArray Args) {
for (unsigned i = 1, N = Args.getNumElements(); i < N; ++i) {
DIDescriptor Ty = Args.getElement(i);
if (Ty.isUnspecifiedParameter()) {
assert(i == N-1 && "Unspecified parameter must be the last argument");
createAndAddDIE(dwarf::DW_TAG_unspecified_parameters, Buffer);
} else {
DIE *Arg = createAndAddDIE(dwarf::DW_TAG_formal_parameter, Buffer);
addType(Arg, DIType(Ty));
if (DIType(Ty).isArtificial())
addFlag(Arg, dwarf::DW_AT_artificial);
}
}
}
void DwarfUnit::constructTypeDIE(DIE &Buffer, DICompositeType CTy) {
StringRef Name = CTy.getName();
uint64_t Size = CTy.getSizeInBits() >> 3;
uint16_t Tag = Buffer.getTag();
switch (Tag) {
case dwarf::DW_TAG_array_type:
constructArrayTypeDIE(Buffer, CTy);
break;
case dwarf::DW_TAG_enumeration_type:
constructEnumTypeDIE(Buffer, CTy);
break;
case dwarf::DW_TAG_subroutine_type: {
DIArray Elements = CTy.getTypeArray();
DIType RTy(Elements.getElement(0));
if (RTy)
addType(&Buffer, RTy);
bool isPrototyped = true;
if (Elements.getNumElements() == 2 &&
Elements.getElement(1).isUnspecifiedParameter())
isPrototyped = false;
constructSubprogramArguments(Buffer, Elements);
uint16_t Language = getLanguage();
if (isPrototyped &&
(Language == dwarf::DW_LANG_C89 || Language == dwarf::DW_LANG_C99 ||
Language == dwarf::DW_LANG_ObjC))
addFlag(&Buffer, dwarf::DW_AT_prototyped);
if (CTy.isLValueReference())
addFlag(&Buffer, dwarf::DW_AT_reference);
if (CTy.isRValueReference())
addFlag(&Buffer, dwarf::DW_AT_rvalue_reference);
} break;
case dwarf::DW_TAG_structure_type:
case dwarf::DW_TAG_union_type:
case dwarf::DW_TAG_class_type: {
DIArray Elements = CTy.getTypeArray();
for (unsigned i = 0, N = Elements.getNumElements(); i < N; ++i) {
DIDescriptor Element = Elements.getElement(i);
DIE *ElemDie = NULL;
if (Element.isSubprogram())
ElemDie = getOrCreateSubprogramDIE(DISubprogram(Element));
else if (Element.isDerivedType()) {
DIDerivedType DDTy(Element);
if (DDTy.getTag() == dwarf::DW_TAG_friend) {
ElemDie = createAndAddDIE(dwarf::DW_TAG_friend, Buffer);
addType(ElemDie, resolve(DDTy.getTypeDerivedFrom()),
dwarf::DW_AT_friend);
} else if (DDTy.isStaticMember()) {
getOrCreateStaticMemberDIE(DDTy);
} else {
constructMemberDIE(Buffer, DDTy);
}
} else if (Element.isObjCProperty()) {
DIObjCProperty Property(Element);
ElemDie = createAndAddDIE(Property.getTag(), Buffer);
StringRef PropertyName = Property.getObjCPropertyName();
addString(ElemDie, dwarf::DW_AT_APPLE_property_name, PropertyName);
if (Property.getType())
addType(ElemDie, Property.getType());
addSourceLine(ElemDie, Property);
StringRef GetterName = Property.getObjCPropertyGetterName();
if (!GetterName.empty())
addString(ElemDie, dwarf::DW_AT_APPLE_property_getter, GetterName);
StringRef SetterName = Property.getObjCPropertySetterName();
if (!SetterName.empty())
addString(ElemDie, dwarf::DW_AT_APPLE_property_setter, SetterName);
unsigned PropertyAttributes = 0;
if (Property.isReadOnlyObjCProperty())
PropertyAttributes |= dwarf::DW_APPLE_PROPERTY_readonly;
if (Property.isReadWriteObjCProperty())
PropertyAttributes |= dwarf::DW_APPLE_PROPERTY_readwrite;
if (Property.isAssignObjCProperty())
PropertyAttributes |= dwarf::DW_APPLE_PROPERTY_assign;
if (Property.isRetainObjCProperty())
PropertyAttributes |= dwarf::DW_APPLE_PROPERTY_retain;
if (Property.isCopyObjCProperty())
PropertyAttributes |= dwarf::DW_APPLE_PROPERTY_copy;
if (Property.isNonAtomicObjCProperty())
PropertyAttributes |= dwarf::DW_APPLE_PROPERTY_nonatomic;
if (PropertyAttributes)
addUInt(ElemDie, dwarf::DW_AT_APPLE_property_attribute, None,
PropertyAttributes);
DIEEntry *Entry = getDIEEntry(Element);
if (!Entry) {
Entry = createDIEEntry(ElemDie);
insertDIEEntry(Element, Entry);
}
} else
continue;
}
if (CTy.isAppleBlockExtension())
addFlag(&Buffer, dwarf::DW_AT_APPLE_block);
DICompositeType ContainingType(resolve(CTy.getContainingType()));
if (ContainingType)
addDIEEntry(&Buffer, dwarf::DW_AT_containing_type,
getOrCreateTypeDIE(ContainingType));
if (CTy.isObjcClassComplete())
addFlag(&Buffer, dwarf::DW_AT_APPLE_objc_complete_type);
if (Tag == dwarf::DW_TAG_class_type ||
Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type)
addTemplateParams(Buffer, CTy.getTemplateParams());
break;
}
default:
break;
}
if (!Name.empty())
addString(&Buffer, dwarf::DW_AT_name, Name);
if ((CTy.getRunTimeLang() == dwarf::DW_LANG_Swift ||
CTy.getRunTimeLang() == dwarf::DW_LANG_PLI) && CTy.getIdentifier())
addString(&Buffer, dwarf::DW_AT_linkage_name,
CTy.getIdentifier()->getString());
if (Tag == dwarf::DW_TAG_enumeration_type ||
Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type ||
Tag == dwarf::DW_TAG_union_type) {
if (Size)
addUInt(&Buffer, dwarf::DW_AT_byte_size, None, Size);
else if (!CTy.isForwardDecl())
addUInt(&Buffer, dwarf::DW_AT_byte_size, None, 0);
if (CTy.isForwardDecl())
addFlag(&Buffer, dwarf::DW_AT_declaration);
if (!CTy.isForwardDecl())
addSourceLine(&Buffer, CTy);
unsigned RLang = CTy.getRunTimeLang();
if (RLang)
addUInt(&Buffer, dwarf::DW_AT_APPLE_runtime_class, None, RLang);
}
}
void DwarfUnit::constructTemplateTypeParameterDIE(DIE &Buffer,
DITemplateTypeParameter TP) {
DIE *ParamDIE =
createAndAddDIE(dwarf::DW_TAG_template_type_parameter, Buffer);
if (TP.getType())
addType(ParamDIE, resolve(TP.getType()));
if (!TP.getName().empty())
addString(ParamDIE, dwarf::DW_AT_name, TP.getName());
}
void
DwarfUnit::constructTemplateValueParameterDIE(DIE &Buffer,
DITemplateValueParameter VP) {
DIE *ParamDIE = createAndAddDIE(VP.getTag(), Buffer);
if (VP.getTag() == dwarf::DW_TAG_template_value_parameter)
addType(ParamDIE, resolve(VP.getType()));
if (!VP.getName().empty())
addString(ParamDIE, dwarf::DW_AT_name, VP.getName());
if (Value *Val = VP.getValue()) {
if (ConstantInt *CI = dyn_cast<ConstantInt>(Val))
addConstantValue(ParamDIE, CI,
isUnsignedDIType(DD, resolve(VP.getType())));
else if (GlobalValue *GV = dyn_cast<GlobalValue>(Val)) {
DIEBlock *Block = new (DIEValueAllocator) DIEBlock();
addOpAddress(Block, Asm->getSymbol(GV));
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_stack_value);
addBlock(ParamDIE, dwarf::DW_AT_location, Block);
} else if (VP.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
assert(isa<MDString>(Val));
addString(ParamDIE, dwarf::DW_AT_GNU_template_name,
cast<MDString>(Val)->getString());
} else if (VP.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
assert(isa<MDNode>(Val));
DIArray A(cast<MDNode>(Val));
addTemplateParams(*ParamDIE, A);
}
}
}
DIE *DwarfUnit::getOrCreateNameSpace(DINameSpace NS) {
DIE *ContextDIE = getOrCreateContextDIE(NS.getContext());
DIE *NDie = getDIE(NS);
if (NDie)
return NDie;
NDie = createAndAddDIE(dwarf::DW_TAG_namespace, *ContextDIE, NS);
if (!NS.getName().empty()) {
addString(NDie, dwarf::DW_AT_name, NS.getName());
addAccelNamespace(NS.getName(), NDie);
addGlobalName(NS.getName(), NDie, NS.getContext());
} else
addAccelNamespace("(anonymous namespace)", NDie);
addSourceLine(NDie, NS);
return NDie;
}
DIE *DwarfUnit::getOrCreateModule(DIModule M) {
DIE *ContextDIE = getOrCreateContextDIE(M.getContext());
DIE *MDie = getDIE(M);
if (MDie)
return MDie;
MDie = createAndAddDIE(dwarf::DW_TAG_module, *ContextDIE, M);
if (!M.getName().empty()) {
addString(MDie, dwarf::DW_AT_name, M.getName());
addGlobalName(M.getName(), MDie, M.getContext());
}
addSourceLine(MDie, M);
return MDie;
}
DIE *DwarfUnit::getOrCreateSubprogramDIE(DISubprogram SP) {
DIE *ContextDIE = getOrCreateContextDIE(resolve(SP.getContext()));
DIE *SPDie = getDIE(SP);
if (SPDie)
return SPDie;
DISubprogram SPDecl = SP.getFunctionDeclaration();
if (SPDecl.isSubprogram())
ContextDIE = UnitDie.get();
SPDie = createAndAddDIE(dwarf::DW_TAG_subprogram, *ContextDIE, SP);
DIE *DeclDie = NULL;
if (SPDecl.isSubprogram())
DeclDie = getOrCreateSubprogramDIE(SPDecl);
addTemplateParams(*SPDie, SP.getTemplateParams());
if (DeclDie)
addDIEEntry(SPDie, dwarf::DW_AT_specification, DeclDie);
StringRef LinkageName = SP.getLinkageName();
if (!LinkageName.empty()) {
if (SPDecl.isSubprogram() && !SPDecl.getLinkageName().empty())
assert(SPDecl.getLinkageName() == SP.getLinkageName() &&
"decl has a linkage name and it is different");
else
addString(SPDie, dwarf::DW_AT_MIPS_linkage_name,
GlobalValue::getRealLinkageName(LinkageName));
}
if (DeclDie)
return SPDie;
if (!SP.getName().empty())
addString(SPDie, dwarf::DW_AT_name, SP.getName());
addSourceLine(SPDie, SP);
uint16_t Language = getLanguage();
if (SP.isPrototyped() &&
(Language == dwarf::DW_LANG_C89 || Language == dwarf::DW_LANG_C99 ||
Language == dwarf::DW_LANG_ObjC))
addFlag(SPDie, dwarf::DW_AT_prototyped);
DICompositeType SPTy = SP.getType();
assert(SPTy.getTag() == dwarf::DW_TAG_subroutine_type &&
"the type of a subprogram should be a subroutine");
DIArray Args = SPTy.getTypeArray();
if (Args.getElement(0))
addType(SPDie, DIType(Args.getElement(0)));
unsigned VK = SP.getVirtuality();
if (VK) {
addUInt(SPDie, dwarf::DW_AT_virtuality, dwarf::DW_FORM_data1, VK);
DIEBlock *Block = getDIEBlock();
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_constu);
addUInt(Block, dwarf::DW_FORM_udata, SP.getVirtualIndex());
addBlock(SPDie, dwarf::DW_AT_vtable_elem_location, Block);
ContainingTypeMap.insert(
std::make_pair(SPDie, resolve(SP.getContainingType())));
}
if (!SP.isDefinition()) {
addFlag(SPDie, dwarf::DW_AT_declaration);
constructSubprogramArguments(*SPDie, Args);
}
if (SP.isArtificial())
addFlag(SPDie, dwarf::DW_AT_artificial);
if (!SP.isLocalToUnit())
addFlag(SPDie, dwarf::DW_AT_external);
if (SP.isOptimized())
addFlag(SPDie, dwarf::DW_AT_APPLE_optimized);
if (unsigned isa = Asm->getISAEncoding()) {
addUInt(SPDie, dwarf::DW_AT_APPLE_isa, dwarf::DW_FORM_flag, isa);
}
if (SP.isLValueReference())
addFlag(SPDie, dwarf::DW_AT_reference);
if (SP.isRValueReference())
addFlag(SPDie, dwarf::DW_AT_rvalue_reference);
if (SP.isProtected())
addUInt(SPDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1,
dwarf::DW_ACCESS_protected);
else if (SP.isPrivate())
addUInt(SPDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1,
dwarf::DW_ACCESS_private);
else
addUInt(SPDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1,
dwarf::DW_ACCESS_public);
if (SP.isExplicit())
addFlag(SPDie, dwarf::DW_AT_explicit);
return SPDie;
}
static const ConstantExpr *getMergedGlobalExpr(const Value *V) {
const ConstantExpr *CE = dyn_cast_or_null<ConstantExpr>(V);
if (!CE || CE->getNumOperands() != 3 ||
CE->getOpcode() != Instruction::GetElementPtr)
return NULL;
Value *Ptr = CE->getOperand(0);
if (!isa<GlobalValue>(Ptr) ||
!isa<StructType>(cast<PointerType>(Ptr->getType())->getElementType()))
return NULL;
const ConstantInt *CI = dyn_cast_or_null<ConstantInt>(CE->getOperand(1));
if (!CI || !CI->isZero())
return NULL;
if (!isa<ConstantInt>(CE->getOperand(2)))
return NULL;
return CE;
}
void DwarfCompileUnit::createGlobalVariableDIE(DIGlobalVariable GV) {
if (getDIE(GV))
return;
if (!GV.isGlobalVariable())
return;
DIScope GVContext = GV.getContext();
DIType GTy = GV.getType();
DIE *VariableDIE = NULL;
bool IsStaticMember = false;
DIDerivedType SDMDecl = GV.getStaticDataMemberDeclaration();
if (SDMDecl.Verify()) {
assert(SDMDecl.isStaticMember() && "Expected static member decl");
VariableDIE = getOrCreateStaticMemberDIE(SDMDecl);
IsStaticMember = true;
}
if (!VariableDIE) {
DIE *ContextDIE = getOrCreateContextDIE(GVContext);
VariableDIE = createAndAddDIE(GV.getTag(), *ContextDIE, GV);
addString(VariableDIE, dwarf::DW_AT_name, GV.getDisplayName());
addType(VariableDIE, GTy);
if (!GV.isLocalToUnit())
addFlag(VariableDIE, dwarf::DW_AT_external);
addSourceLine(VariableDIE, GV);
}
bool addToAccelTable = false;
DIE *VariableSpecDIE = NULL;
bool isGlobalVariable = GV.getGlobal() != NULL;
if (isGlobalVariable) {
addToAccelTable = true;
DIEBlock *Block = new (DIEValueAllocator) DIEBlock();
const MCSymbol *Sym = Asm->getSymbol(GV.getGlobal());
if (GV.getGlobal()->isThreadLocal()) {
unsigned PointerSize = Asm->getDataLayout().getPointerSize();
assert((PointerSize == 4 || PointerSize == 8) &&
"Add support for other sizes if necessary");
const MCExpr *Expr =
Asm->getObjFileLowering().getDebugThreadLocalSymbol(Sym);
if (!DD->useSplitDwarf()) {
addUInt(Block, dwarf::DW_FORM_data1,
PointerSize == 4 ? dwarf::DW_OP_const4u : dwarf::DW_OP_const8u);
addExpr(Block, dwarf::DW_FORM_udata, Expr);
} else {
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_GNU_const_index);
addUInt(Block, dwarf::DW_FORM_udata, DU->getAddrPoolIndex(Expr));
}
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_GNU_push_tls_address);
} else {
DD->addArangeLabel(SymbolCU(this, Sym));
addOpAddress(Block, Sym);
}
if (GVContext && GV.isDefinition() && !GVContext.isCompileUnit() &&
!GVContext.isFile() && !DD->isSubprogramContext(GVContext)) {
VariableSpecDIE = createAndAddDIE(dwarf::DW_TAG_variable, *UnitDie);
addDIEEntry(VariableSpecDIE, dwarf::DW_AT_specification, VariableDIE);
addBlock(VariableSpecDIE, dwarf::DW_AT_location, Block);
if (!SDMDecl.Verify())
addFlag(VariableDIE, dwarf::DW_AT_declaration);
} else {
addBlock(VariableDIE, dwarf::DW_AT_location, Block);
}
StringRef LinkageName = GV.getLinkageName();
if (!LinkageName.empty())
addString(IsStaticMember && VariableSpecDIE ? VariableSpecDIE
: VariableDIE,
dwarf::DW_AT_MIPS_linkage_name,
GlobalValue::getRealLinkageName(LinkageName));
} else if (const ConstantInt *CI =
dyn_cast_or_null<ConstantInt>(GV.getConstant())) {
if (!IsStaticMember)
addConstantValue(VariableDIE, CI, isUnsignedDIType(DD, GTy));
} else if (const ConstantExpr *CE = getMergedGlobalExpr(GV->getOperand(11))) {
addToAccelTable = true;
DIEBlock *Block = new (DIEValueAllocator) DIEBlock();
Value *Ptr = CE->getOperand(0);
MCSymbol *Sym = Asm->getSymbol(cast<GlobalValue>(Ptr));
DD->addArangeLabel(SymbolCU(this, Sym));
addOpAddress(Block, Sym);
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_constu);
SmallVector<Value *, 3> Idx(CE->op_begin() + 1, CE->op_end());
addUInt(Block, dwarf::DW_FORM_udata,
Asm->getDataLayout().getIndexedOffset(Ptr->getType(), Idx));
addUInt(Block, dwarf::DW_FORM_data1, dwarf::DW_OP_plus);
addBlock(VariableDIE, dwarf::DW_AT_location, Block);
}
if (addToAccelTable) {
DIE *AddrDIE = VariableSpecDIE ? VariableSpecDIE : VariableDIE;
addAccelName(GV.getName(), AddrDIE);
if (GV.getLinkageName() != "" && GV.getName() != GV.getLinkageName())
addAccelName(GV.getLinkageName(), AddrDIE);
}
if (!GV.isLocalToUnit())
addGlobalName(GV.getName(), VariableSpecDIE ? VariableSpecDIE : VariableDIE,
GV.getContext());
}
void DwarfUnit::constructSubrangeDIE(DIE &Buffer, DISubrange SR, DIE *IndexTy) {
DIE *DW_Subrange = createAndAddDIE(dwarf::DW_TAG_subrange_type, Buffer);
addDIEEntry(DW_Subrange, dwarf::DW_AT_type, IndexTy);
int64_t LowerBound = SR.getLo();
int64_t DefaultLowerBound = getDefaultLowerBound();
int64_t Count = SR.getCount();
if (DefaultLowerBound == -1 || LowerBound != DefaultLowerBound)
addUInt(DW_Subrange, dwarf::DW_AT_lower_bound, None, LowerBound);
if (Count != -1 && Count != 0)
addUInt(DW_Subrange, dwarf::DW_AT_upper_bound, None,
LowerBound + Count - 1);
}
void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, DICompositeType CTy) {
if (CTy.isVector())
addFlag(&Buffer, dwarf::DW_AT_GNU_vector);
addType(&Buffer, resolve(CTy.getTypeDerivedFrom()));
DIE *IdxTy = getIndexTyDie();
if (!IdxTy) {
IdxTy = createAndAddDIE(dwarf::DW_TAG_base_type, *UnitDie);
addString(IdxTy, dwarf::DW_AT_name, "int");
addUInt(IdxTy, dwarf::DW_AT_byte_size, None, sizeof(int32_t));
addUInt(IdxTy, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1,
dwarf::DW_ATE_signed);
setIndexTyDie(IdxTy);
}
DIArray Elements = CTy.getTypeArray();
for (unsigned i = 0, N = Elements.getNumElements(); i < N; ++i) {
DIDescriptor Element = Elements.getElement(i);
if (Element.getTag() == dwarf::DW_TAG_subrange_type)
constructSubrangeDIE(Buffer, DISubrange(Element), IdxTy);
}
}
void DwarfUnit::constructEnumTypeDIE(DIE &Buffer, DICompositeType CTy) {
DIArray Elements = CTy.getTypeArray();
for (unsigned i = 0, N = Elements.getNumElements(); i < N; ++i) {
DIEnumerator Enum(Elements.getElement(i));
if (Enum.isEnumerator()) {
DIE *Enumerator = createAndAddDIE(dwarf::DW_TAG_enumerator, Buffer);
StringRef Name = Enum.getName();
addString(Enumerator, dwarf::DW_AT_name, Name);
int64_t Value = Enum.getEnumValue();
addSInt(Enumerator, dwarf::DW_AT_const_value, dwarf::DW_FORM_sdata,
Value);
}
}
DIType DTy = resolve(CTy.getTypeDerivedFrom());
if (DTy) {
addType(&Buffer, DTy);
addFlag(&Buffer, dwarf::DW_AT_enum_class);
}
}
void DwarfUnit::constructContainingTypeDIEs() {
for (DenseMap<DIE *, const MDNode *>::iterator CI = ContainingTypeMap.begin(),
CE = ContainingTypeMap.end();
CI != CE; ++CI) {
DIE *SPDie = CI->first;
DIDescriptor D(CI->second);
if (!D)
continue;
DIE *NDie = getDIE(D);
if (!NDie)
continue;
addDIEEntry(SPDie, dwarf::DW_AT_containing_type, NDie);
}
}
DIE *DwarfUnit::constructVariableDIE(DbgVariable &DV, bool isScopeAbstract) {
StringRef Name = DV.getName();
DIE *VariableDie = new DIE(DV.getTag());
DbgVariable *AbsVar = DV.getAbstractVariable();
DIE *AbsDIE = AbsVar ? AbsVar->getDIE() : NULL;
if (AbsDIE)
addDIEEntry(VariableDie, dwarf::DW_AT_abstract_origin, AbsDIE);
else {
if (!Name.empty())
addString(VariableDie, dwarf::DW_AT_name, Name);
addSourceLine(VariableDie, DV.getVariable());
addType(VariableDie, DV.getType());
}
if (DV.isArtificial())
addFlag(VariableDie, dwarf::DW_AT_artificial);
if (isScopeAbstract) {
DV.setDIE(VariableDie);
return VariableDie;
}
unsigned Offset = DV.getDotDebugLocOffset();
if (Offset != ~0U) {
addSectionLabel(VariableDie, dwarf::DW_AT_location,
Asm->GetTempSymbol("debug_loc", Offset));
DV.setDIE(VariableDie);
return VariableDie;
}
if (const MachineInstr *DVInsn = DV.getMInsn()) {
assert(DVInsn->getNumOperands() == 3);
if (DVInsn->getOperand(0).isReg()) {
const MachineOperand RegOp = DVInsn->getOperand(0);
if (DVInsn->getOperand(1).isImm()) {
MachineLocation Location(RegOp.getReg(),
DVInsn->getOperand(1).getImm());
addVariableAddress(DV, VariableDie, Location);
} else if (RegOp.getReg())
addVariableAddress(DV, VariableDie, MachineLocation(RegOp.getReg()));
} else if (DVInsn->getOperand(0).isImm())
addConstantValue(VariableDie, DVInsn->getOperand(0), DV.getType());
else if (DVInsn->getOperand(0).isFPImm())
addConstantFPValue(VariableDie, DVInsn->getOperand(0));
else if (DVInsn->getOperand(0).isCImm())
addConstantValue(VariableDie, DVInsn->getOperand(0).getCImm(),
isUnsignedDIType(DD, DV.getType()));
DV.setDIE(VariableDie);
return VariableDie;
} else {
int FI = DV.getFrameIndex();
if (FI != ~0) {
unsigned FrameReg = 0;
const TargetFrameLowering *TFI = Asm->TM.getFrameLowering();
int Offset = TFI->getFrameIndexReference(*Asm->MF, FI, FrameReg);
MachineLocation Location(FrameReg, Offset);
addVariableAddress(DV, VariableDie, Location);
}
}
DV.setDIE(VariableDie);
return VariableDie;
}
void DwarfUnit::constructMemberDIE(DIE &Buffer, DIDerivedType DT) {
DIE *MemberDie = createAndAddDIE(DT.getTag(), Buffer);
StringRef Name = DT.getName();
if (!Name.empty())
addString(MemberDie, dwarf::DW_AT_name, Name);
addType(MemberDie, resolve(DT.getTypeDerivedFrom()));
addSourceLine(MemberDie, DT);
if (DT.getTag() == dwarf::DW_TAG_inheritance && DT.isVirtual()) {
DIEBlock *VBaseLocationDie = new (DIEValueAllocator) DIEBlock();
addUInt(VBaseLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_dup);
addUInt(VBaseLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_deref);
addUInt(VBaseLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_constu);
addUInt(VBaseLocationDie, dwarf::DW_FORM_udata, DT.getOffsetInBits());
addUInt(VBaseLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_minus);
addUInt(VBaseLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_deref);
addUInt(VBaseLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_plus);
addBlock(MemberDie, dwarf::DW_AT_data_member_location, VBaseLocationDie);
} else {
uint64_t Size = DT.getSizeInBits();
uint64_t FieldSize = getBaseTypeSize(DD, DT);
uint64_t OffsetInBytes;
if (Size != FieldSize) {
addUInt(MemberDie, dwarf::DW_AT_byte_size, None,
getBaseTypeSize(DD, DT) >> 3);
addUInt(MemberDie, dwarf::DW_AT_bit_size, None, DT.getSizeInBits());
uint64_t Offset = DT.getOffsetInBits();
uint64_t AlignMask = ~(DT.getAlignInBits() - 1);
uint64_t HiMark = (Offset + FieldSize) & AlignMask;
uint64_t FieldOffset = (HiMark - FieldSize);
Offset -= FieldOffset;
if (Asm->getDataLayout().isLittleEndian())
Offset = FieldSize - (Offset + Size);
addUInt(MemberDie, dwarf::DW_AT_bit_offset, None, Offset);
OffsetInBytes = FieldOffset >> 3;
} else
OffsetInBytes = DT.getOffsetInBits() >> 3;
if (DD->getDwarfVersion() <= 2) {
DIEBlock *MemLocationDie = new (DIEValueAllocator) DIEBlock();
addUInt(MemLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
addUInt(MemLocationDie, dwarf::DW_FORM_udata, OffsetInBytes);
addBlock(MemberDie, dwarf::DW_AT_data_member_location, MemLocationDie);
} else
addUInt(MemberDie, dwarf::DW_AT_data_member_location, None,
OffsetInBytes);
}
if (DT.isProtected())
addUInt(MemberDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1,
dwarf::DW_ACCESS_protected);
else if (DT.isPrivate())
addUInt(MemberDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1,
dwarf::DW_ACCESS_private);
else
addUInt(MemberDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1,
dwarf::DW_ACCESS_public);
if (DT.isVirtual())
addUInt(MemberDie, dwarf::DW_AT_virtuality, dwarf::DW_FORM_data1,
dwarf::DW_VIRTUALITY_virtual);
if (MDNode *PNode = DT.getObjCProperty())
if (DIEEntry *PropertyDie = getDIEEntry(PNode))
MemberDie->addValue(dwarf::DW_AT_APPLE_property, dwarf::DW_FORM_ref4,
PropertyDie);
if (DT.isArtificial())
addFlag(MemberDie, dwarf::DW_AT_artificial);
}
DIE *DwarfUnit::getOrCreateStaticMemberDIE(DIDerivedType DT) {
if (!DT.Verify())
return NULL;
DIE *ContextDIE = getOrCreateContextDIE(resolve(DT.getContext()));
assert(dwarf::isType(ContextDIE->getTag()) &&
"Static member should belong to a type.");
DIE *StaticMemberDIE = getDIE(DT);
if (StaticMemberDIE)
return StaticMemberDIE;
StaticMemberDIE = createAndAddDIE(DT.getTag(), *ContextDIE, DT);
DIType Ty = resolve(DT.getTypeDerivedFrom());
addString(StaticMemberDIE, dwarf::DW_AT_name, DT.getName());
addType(StaticMemberDIE, Ty);
addSourceLine(StaticMemberDIE, DT);
addFlag(StaticMemberDIE, dwarf::DW_AT_external);
addFlag(StaticMemberDIE, dwarf::DW_AT_declaration);
if (DT.isProtected())
addUInt(StaticMemberDIE, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1,
dwarf::DW_ACCESS_protected);
else if (DT.isPrivate())
addUInt(StaticMemberDIE, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1,
dwarf::DW_ACCESS_private);
else
addUInt(StaticMemberDIE, dwarf::DW_AT_accessibility, dwarf::DW_FORM_data1,
dwarf::DW_ACCESS_public);
if (const ConstantInt *CI = dyn_cast_or_null<ConstantInt>(DT.getConstant()))
addConstantValue(StaticMemberDIE, CI, isUnsignedDIType(DD, Ty));
if (const ConstantFP *CFP = dyn_cast_or_null<ConstantFP>(DT.getConstant()))
addConstantFPValue(StaticMemberDIE, CFP);
return StaticMemberDIE;
}
void DwarfUnit::emitHeader(const MCSection *ASection,
const MCSymbol *ASectionSym) const {
Asm->OutStreamer.AddComment("DWARF version number");
Asm->EmitInt16(DD->getDwarfVersion());
Asm->OutStreamer.AddComment("Offset Into Abbrev. Section");
Asm->EmitSectionOffset(ASectionSym, ASectionSym);
Asm->OutStreamer.AddComment("Address Size (in bytes)");
Asm->EmitInt8(Asm->getDataLayout().getPointerSize());
}
DwarfCompileUnit::~DwarfCompileUnit() {}
DwarfTypeUnit::~DwarfTypeUnit() {}
void DwarfTypeUnit::emitHeader(const MCSection *ASection,
const MCSymbol *ASectionSym) const {
DwarfUnit::emitHeader(ASection, ASectionSym);
Asm->OutStreamer.AddComment("Type Signature");
Asm->OutStreamer.EmitIntValue(TypeSignature, sizeof(TypeSignature));
Asm->OutStreamer.AddComment("Type DIE Offset");
Asm->OutStreamer.EmitIntValue(Ty ? Ty->getOffset() : 0,
sizeof(Ty->getOffset()));
}
void DwarfTypeUnit::initSection(const MCSection *Section) {
assert(!this->Section);
this->Section = Section;
this->SectionSym = this->LabelBegin =
Asm->GetTempSymbol(Section->getLabelBeginName(), getUniqueID());
this->LabelEnd =
Asm->GetTempSymbol(Section->getLabelEndName(), getUniqueID());
this->LabelRange = Asm->GetTempSymbol("gnu_ranges", getUniqueID());
}