Newer
Older
//===-- llvm/CodeGen/DwarfDebug.cpp - Dwarf Debug Framework ---------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains support for writing dwarf debug info into asm files.
//
//===----------------------------------------------------------------------===//
#include "DwarfDebug.h"
Bill Wendling
committed
#include "llvm/Constants.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Target/Mangler.h"
#include "llvm/Target/TargetData.h"
Anton Korobeynikov
committed
#include "llvm/Target/TargetFrameLowering.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/ADT/Statistic.h"
Jeffrey Yasskin
committed
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
Devang Patel
committed
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ValueHandle.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Timer.h"
using namespace llvm;
Devang Patel
committed
static cl::opt<bool> PrintDbgScope("print-dbgscope", cl::Hidden,
cl::desc("Print DbgScope information for each machine instruction"));
static cl::opt<bool> DisableDebugInfoPrinting("disable-debug-info-print",
Devang Patel
committed
cl::desc("Disable debug info printing"));
static cl::opt<bool> UnknownLocations("use-unknown-locations", cl::Hidden,
cl::desc("Make an absense of debug location information explicit."),
cl::init(false));
#ifndef NDEBUG
STATISTIC(BlocksWithoutLineNo, "Number of blocks without any line number");
#endif
namespace {
const char *DWARFGroupName = "DWARF Emission";
const char *DbgTimerName = "DWARF Debug Writer";
} // end anonymous namespace
//===----------------------------------------------------------------------===//
/// Configuration values for initial hash set sizes (log2).
///
static const unsigned InitAbbreviationsSetSize = 9; // log2(512)
namespace llvm {
//===----------------------------------------------------------------------===//
/// CompileUnit - This dwarf writer support class manages information associate
/// with a source file.
/// ID - File identifier for source.
///
unsigned ID;
/// Die - Compile unit debug information entry.
///
Jeffrey Yasskin
committed
const OwningPtr<DIE> CUDie;
/// IndexTyDie - An anonymous type for index type. Owned by CUDie.
/// MDNodeToDieMap - Tracks the mapping of unit level debug informaton
/// variables to debug information entries.
/// MDNodeToDIEEntryMap - Tracks the mapping of unit level debug informaton
/// descriptors to debug information entries using a DIEEntry proxy.
DenseMap<const MDNode *, DIEEntry *> MDNodeToDIEEntryMap;
/// Globals - A map of globally visible named entities for this unit.
///
StringMap<DIE*> Globals;
/// GlobalTypes - A map of globally visible types for this unit.
///
StringMap<DIE*> GlobalTypes;
public:
CompileUnit(unsigned I, DIE *D)
: ID(I), CUDie(D), IndexTyDie(0) {}
// Accessors.
DIE* getCUDie() const { return CUDie.get(); }
const StringMap<DIE*> &getGlobals() const { return Globals; }
const StringMap<DIE*> &getGlobalTypes() const { return GlobalTypes; }
/// hasContent - Return true if this compile unit has something to write out.
///
bool hasContent() const { return !CUDie->getChildren().empty(); }
/// addGlobal - Add a new global entity to the compile unit.
void addGlobal(StringRef Name, DIE *Die) { Globals[Name] = Die; }
/// addGlobalType - Add a new global type to the compile unit.
///
void addGlobalType(StringRef Name, DIE *Die) {
GlobalTypes[Name] = Die;
/// getDIE - Returns the debug information entry map slot for the
/// specified debug variable.
DIE *getDIE(const MDNode *N) { return MDNodeToDieMap.lookup(N); }
/// insertDIE - Insert DIE into the map.
void insertDIE(const MDNode *N, DIE *D) {
}
/// getDIEEntry - Returns the debug information entry for the speciefied
/// debug variable.
DIEEntry *getDIEEntry(const MDNode *N) {
DenseMap<const MDNode *, DIEEntry *>::iterator I =
MDNodeToDIEEntryMap.find(N);
return NULL;
return I->second;
}
/// insertDIEEntry - Insert debug information entry into the map.
void insertDIEEntry(const MDNode *N, DIEEntry *E) {
/// addDie - Adds or interns the DIE to the compile unit.
void addDie(DIE *Buffer) {
this->CUDie->addChild(Buffer);
// getIndexTyDie - Get an anonymous type for index type.
DIE *getIndexTyDie() {
return IndexTyDie;
// setIndexTyDie - Set D as anonymous type for index which can be reused
// later.
void setIndexTyDie(DIE *D) {
IndexTyDie = D;
}
};
//===----------------------------------------------------------------------===//
/// DbgVariable - This class is used to track local variable information.
///
DIVariable Var; // Variable Descriptor.
DIE *TheDIE; // Variable DIE.
unsigned DotDebugLocOffset; // Offset in DotDebugLocEntries.
Jeffrey Yasskin
committed
// AbsVar may be NULL.
DbgVariable(DIVariable V) : Var(V), TheDIE(0), DotDebugLocOffset(~0U) {}
// Accessors.
DIVariable getVariable() const { return Var; }
void setDIE(DIE *D) { TheDIE = D; }
DIE *getDIE() const { return TheDIE; }
void setDotDebugLocOffset(unsigned O) { DotDebugLocOffset = O; }
unsigned getDotDebugLocOffset() const { return DotDebugLocOffset; }
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
StringRef getName() const { return Var.getName(); }
unsigned getTag() const { return Var.getTag(); }
bool variableHasComplexAddress() const {
assert(Var.Verify() && "Invalid complex DbgVariable!");
return Var.hasComplexAddress();
}
bool isBlockByrefVariable() const {
assert(Var.Verify() && "Invalid complex DbgVariable!");
return Var.isBlockByrefVariable();
}
unsigned getNumAddrElements() const {
assert(Var.Verify() && "Invalid complex DbgVariable!");
return Var.getNumAddrElements();
}
uint64_t getAddrElement(unsigned i) const {
return Var.getAddrElement(i);
}
DIType getType() const {
DIType Ty = Var.getType();
// FIXME: isBlockByrefVariable should be reformulated in terms of complex
// addresses instead.
if (Var.isBlockByrefVariable()) {
/* Byref variables, in Blocks, are declared by the programmer as
"SomeType VarName;", but the compiler creates a
__Block_byref_x_VarName struct, and gives the variable VarName
either the struct, or a pointer to the struct, as its type. This
is necessary for various behind-the-scenes things the compiler
needs to do with by-reference variables in blocks.
However, as far as the original *programmer* is concerned, the
variable should still have type 'SomeType', as originally declared.
The following function dives into the __Block_byref_x_VarName
struct to find the original type of the variable. This will be
passed back to the code generating the type for the Debug
Information Entry for the variable 'VarName'. 'VarName' will then
have the original type 'SomeType' in its debug information.
The original type 'SomeType' will be the type of the field named
'VarName' inside the __Block_byref_x_VarName struct.
NOTE: In order for this to not completely fail on the debugger
side, the Debug Information Entry for the variable VarName needs to
have a DW_AT_location that tells the debugger how to unwind through
the pointers and __Block_byref_x_VarName struct to find the actual
value of the variable. The function addBlockByrefType does this. */
DIType subType = Ty;
unsigned tag = Ty.getTag();
if (tag == dwarf::DW_TAG_pointer_type) {
DIDerivedType DTy = DIDerivedType(Ty);
subType = DTy.getTypeDerivedFrom();
}
DICompositeType blockStruct = DICompositeType(subType);
DIArray Elements = blockStruct.getTypeArray();
for (unsigned i = 0, N = Elements.getNumElements(); i < N; ++i) {
DIDescriptor Element = Elements.getElement(i);
DIDerivedType DT = DIDerivedType(Element);
if (getName() == DT.getName())
return (DT.getTypeDerivedFrom());
}
return Ty;
}
return Ty;
}
Devang Patel
committed
//===----------------------------------------------------------------------===//
/// DbgRange - This is used to track range of instructions with identical
/// debug info scope.
///
typedef std::pair<const MachineInstr *, const MachineInstr *> DbgRange;
//===----------------------------------------------------------------------===//
/// DbgScope - This class is used to track scope information.
///
DbgScope *Parent; // Parent to this scope.
DIDescriptor Desc; // Debug info descriptor for scope.
// Location at which this scope is inlined.
AssertingVH<const MDNode> InlinedAtLocation;
bool AbstractScope; // Abstract Scope
const MachineInstr *LastInsn; // Last instruction of this scope.
const MachineInstr *FirstInsn; // First instruction of this scope.
Devang Patel
committed
unsigned DFSIn, DFSOut;
Jeffrey Yasskin
committed
// Scopes defined in scope. Contents not owned.
SmallVector<DbgScope *, 4> Scopes;
// Variables declared in scope. Contents owned.
SmallVector<DbgVariable *, 8> Variables;
Devang Patel
committed
SmallVector<DbgRange, 4> Ranges;
// Private state for dump()
mutable unsigned IndentLevel;
DbgScope(DbgScope *P, DIDescriptor D, const MDNode *I = 0)
: Parent(P), Desc(D), InlinedAtLocation(I), AbstractScope(false),
Devang Patel
committed
LastInsn(0), FirstInsn(0),
DFSIn(0), DFSOut(0), IndentLevel(0) {}
virtual ~DbgScope();
// Accessors.
DbgScope *getParent() const { return Parent; }
void setParent(DbgScope *P) { Parent = P; }
DIDescriptor getDesc() const { return Desc; }
const MDNode *getInlinedAt() const { return InlinedAtLocation; }
const MDNode *getScopeNode() const { return Desc; }
Jeffrey Yasskin
committed
const SmallVector<DbgScope *, 4> &getScopes() { return Scopes; }
const SmallVector<DbgVariable *, 8> &getDbgVariables() { return Variables; }
Devang Patel
committed
const SmallVector<DbgRange, 4> &getRanges() { return Ranges; }
/// openInsnRange - This scope covers instruction range starting from MI.
void openInsnRange(const MachineInstr *MI) {
Devang Patel
committed
FirstInsn = MI;
Devang Patel
committed
if (Parent)
Parent->openInsnRange(MI);
}
/// extendInsnRange - Extend the current instruction range covered by
Devang Patel
committed
/// this scope.
void extendInsnRange(const MachineInstr *MI) {
assert (FirstInsn && "MI Range is not open!");
LastInsn = MI;
if (Parent)
Parent->extendInsnRange(MI);
}
/// closeInsnRange - Create a range based on FirstInsn and LastInsn collected
/// until now. This is used when a new scope is encountered while walking
/// machine instructions.
void closeInsnRange(DbgScope *NewScope = NULL) {
assert (LastInsn && "Last insn missing!");
Ranges.push_back(DbgRange(FirstInsn, LastInsn));
Devang Patel
committed
LastInsn = NULL;
// If Parent dominates NewScope then do not close Parent's instruction
Devang Patel
committed
// range.
if (Parent && (!NewScope || !Parent->dominates(NewScope)))
Parent->closeInsnRange(NewScope);
}
void setAbstractScope() { AbstractScope = true; }
bool isAbstractScope() const { return AbstractScope; }
Devang Patel
committed
// Depth First Search support to walk and mainpluate DbgScope hierarchy.
unsigned getDFSOut() const { return DFSOut; }
void setDFSOut(unsigned O) { DFSOut = O; }
unsigned getDFSIn() const { return DFSIn; }
void setDFSIn(unsigned I) { DFSIn = I; }
bool dominates(const DbgScope *S) {
Devang Patel
committed
return true;
if (DFSIn < S->getDFSIn() && DFSOut > S->getDFSOut())
return true;
return false;
}
/// addScope - Add a scope to the scope.
void addScope(DbgScope *S) { Scopes.push_back(S); }
/// addVariable - Add a variable to the scope.
void addVariable(DbgVariable *V) { Variables.push_back(V); }
#ifndef NDEBUG
void dump() const;
#endif
};
Devang Patel
committed
} // end llvm namespace
#ifndef NDEBUG
void DbgScope::dump() const {
err.indent(IndentLevel);
N->dump();
if (AbstractScope)
err << "Abstract Scope\n";
IndentLevel += 2;
if (!Scopes.empty())
err << "Children ...\n";
for (unsigned i = 0, e = Scopes.size(); i != e; ++i)
if (Scopes[i] != this)
Scopes[i]->dump();
IndentLevel -= 2;
}
#endif
DbgScope::~DbgScope() {
for (unsigned j = 0, M = Variables.size(); j < M; ++j)
delete Variables[j];
}
DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M)
: Asm(A), MMI(Asm->MMI), FirstCU(0),
AbbreviationsSet(InitAbbreviationsSetSize),
CurrentFnDbgScope(0), PrevLabel(NULL) {
NextStringPoolNumber = 0;
DwarfFrameSectionSym = DwarfInfoSectionSym = DwarfAbbrevSectionSym = 0;
DwarfStrSectionSym = TextSectionSym = 0;
DwarfDebugRangeSectionSym = DwarfDebugLocSectionSym = 0;
FunctionBeginSym = FunctionEndSym = 0;
Devang Patel
committed
DIEIntegerOne = new (DIEValueAllocator) DIEInteger(1);
{
NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled);
beginModule(M);
}
DwarfDebug::~DwarfDebug() {
for (unsigned j = 0, M = DIEBlocks.size(); j < M; ++j)
DIEBlocks[j]->~DIEBlock();
MCSymbol *DwarfDebug::getStringPoolEntry(StringRef Str) {
std::pair<MCSymbol*, unsigned> &Entry = StringPool[Str];
if (Entry.first) return Entry.first;
Entry.second = NextStringPoolNumber++;
return Entry.first = Asm->GetTempSymbol("string", Entry.second);
/// assignAbbrevNumber - Define a unique number for the abbreviation.
void DwarfDebug::assignAbbrevNumber(DIEAbbrev &Abbrev) {
// Profile the node so that we can make it unique.
FoldingSetNodeID ID;
Abbrev.Profile(ID);
// Check the set for priors.
DIEAbbrev *InSet = AbbreviationsSet.GetOrInsertNode(&Abbrev);
// If it's newly added.
if (InSet == &Abbrev) {
// Add to abbreviation list.
Abbreviations.push_back(&Abbrev);
// Assign the vector position + 1 as its number.
Abbrev.setNumber(Abbreviations.size());
} else {
// Assign existing abbreviation number.
Abbrev.setNumber(InSet->getNumber());
}
}
/// createDIEEntry - Creates a new DIEEntry to be a proxy for a debug
Bill Wendling
committed
/// information entry.
DIEEntry *DwarfDebug::createDIEEntry(DIE *Entry) {
DIEEntry *Value = new (DIEValueAllocator) DIEEntry(Entry);
return Value;
}
/// addUInt - Add an unsigned integer attribute data and value.
void DwarfDebug::addUInt(DIE *Die, unsigned Attribute,
unsigned Form, uint64_t Integer) {
if (!Form) Form = DIEInteger::BestForm(false, Integer);
DIEValue *Value = Integer == 1 ?
Devang Patel
committed
DIEIntegerOne : new (DIEValueAllocator) DIEInteger(Integer);
Die->addValue(Attribute, Form, Value);
/// addSInt - Add an signed integer attribute data and value.
void DwarfDebug::addSInt(DIE *Die, unsigned Attribute,
unsigned Form, int64_t Integer) {
if (!Form) Form = DIEInteger::BestForm(true, Integer);
DIEValue *Value = new (DIEValueAllocator) DIEInteger(Integer);
Die->addValue(Attribute, Form, Value);
/// addString - Add a string attribute data and value. DIEString only
void DwarfDebug::addString(DIE *Die, unsigned Attribute, unsigned Form,
StringRef String) {
DIEValue *Value = new (DIEValueAllocator) DIEString(String);
Die->addValue(Attribute, Form, Value);
/// addLabel - Add a Dwarf label attribute data and value.
void DwarfDebug::addLabel(DIE *Die, unsigned Attribute, unsigned Form,
const MCSymbol *Label) {
DIEValue *Value = new (DIEValueAllocator) DIELabel(Label);
Die->addValue(Attribute, Form, Value);
/// addSectionOffset - Add a Dwarf section relative label attribute data and
/// value.
///
void DwarfDebug::addSectionOffset(DIE *Die, unsigned Attribute, unsigned Form,
const MCSymbol *Label) {
DIEValue *Value = new (DIEValueAllocator) DIESectionOffset(Label);
Die->addValue(Attribute, Form, Value);
}
/// addDelta - Add a label delta attribute data and value.
void DwarfDebug::addDelta(DIE *Die, unsigned Attribute, unsigned Form,
const MCSymbol *Hi, const MCSymbol *Lo) {
DIEValue *Value = new (DIEValueAllocator) DIEDelta(Hi, Lo);
Die->addValue(Attribute, Form, Value);
/// addDIEEntry - Add a DIE attribute data and value.
///
void DwarfDebug::addDIEEntry(DIE *Die, unsigned Attribute, unsigned Form,
DIE *Entry) {
Die->addValue(Attribute, Form, createDIEEntry(Entry));
}
/// addBlock - Add block data.
void DwarfDebug::addBlock(DIE *Die, unsigned Attribute, unsigned Form,
DIEBlock *Block) {
Block->ComputeSize(Asm);
DIEBlocks.push_back(Block); // Memoize so we can call the destructor later on.
Die->addValue(Attribute, Block->BestForm(), Block);
/// addSourceLine - Add location information to specified debug information
void DwarfDebug::addSourceLine(DIE *Die, DIVariable V) {
Devang Patel
committed
// Verify variable.
return;
unsigned Line = V.getLineNumber();
Devang Patel
committed
if (Line == 0)
return;
Rafael Espindola
committed
unsigned FileID = GetOrCreateSourceID(V.getContext().getFilename());
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, 0, Line);
/// addSourceLine - Add location information to specified debug information
void DwarfDebug::addSourceLine(DIE *Die, DIGlobalVariable G) {
Devang Patel
committed
// Verify global variable.
return;
unsigned Line = G.getLineNumber();
Devang Patel
committed
if (Line == 0)
return;
Rafael Espindola
committed
unsigned FileID = GetOrCreateSourceID(G.getContext().getFilename());
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, 0, Line);
/// addSourceLine - Add location information to specified debug information
void DwarfDebug::addSourceLine(DIE *Die, DISubprogram SP) {
Devang Patel
committed
// Verify subprogram.
if (!SP.Verify())
// If the line number is 0, don't add it.
if (SP.getLineNumber() == 0)
unsigned Line = SP.getLineNumber();
if (!SP.getContext().Verify())
Devang Patel
committed
return;
Rafael Espindola
committed
unsigned FileID = GetOrCreateSourceID(SP.getFilename());
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, 0, Line);
/// addSourceLine - Add location information to specified debug information
void DwarfDebug::addSourceLine(DIE *Die, DIType Ty) {
Devang Patel
committed
// Verify type.
if (!Ty.Verify())
return;
unsigned Line = Ty.getLineNumber();
Devang Patel
committed
if (Line == 0 || !Ty.getContext().Verify())
Devang Patel
committed
return;
Rafael Espindola
committed
unsigned FileID = GetOrCreateSourceID(Ty.getFilename());
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, 0, Line);
/// addSourceLine - Add location information to specified debug information
/// entry.
void DwarfDebug::addSourceLine(DIE *Die, DINameSpace NS) {
Devang Patel
committed
// Verify namespace.
if (!NS.Verify())
unsigned Line = NS.getLineNumber();
Devang Patel
committed
if (Line == 0)
return;
StringRef FN = NS.getFilename();
Rafael Espindola
committed
unsigned FileID = GetOrCreateSourceID(FN);
assert(FileID && "Invalid file id");
addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID);
addUInt(Die, dwarf::DW_AT_decl_line, 0, Line);
}
/// addVariableAddress - Add DW_AT_location attribute for a DbgVariable based
/// on provided frame index.
void DwarfDebug::addVariableAddress(DbgVariable *&DV, DIE *Die, int64_t FI) {
MachineLocation Location;
unsigned FrameReg;
Anton Korobeynikov
committed
const TargetFrameLowering *TFI = Asm->TM.getFrameLowering();
int Offset = TFI->getFrameIndexReference(*Asm->MF, FI, FrameReg);
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);
Caroline Tice
committed
}
/// 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 DwarfDebug::addComplexAddress(DbgVariable *&DV, DIE *Die,
unsigned Attribute,
const MachineLocation &Location) {
DIType Ty = DV->getType();
// 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);
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);
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());
for (unsigned i = 0, N = DV->getNumAddrElements(); i < N; ++i) {
uint64_t Element = DV->getAddrElement(i);
addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
addUInt(Block, 0, dwarf::DW_FORM_udata, DV->getAddrElement(++i));
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);
Caroline Tice
committed
/* Byref variables, in Blocks, are declared by the programmer as "SomeType
VarName;", but the compiler creates a __Block_byref_x_VarName struct, and
gives the variable VarName either the struct, or a pointer to the struct, as
its type. This is necessary for various behind-the-scenes things the
compiler needs to do with by-reference variables in Blocks.
However, as far as the original *programmer* is concerned, the variable
should still have type 'SomeType', as originally declared.
The function getBlockByrefType dives into the __Block_byref_x_VarName
Caroline Tice
committed
struct to find the original type of the variable, which is then assigned to
the variable's Debug Information Entry as its real type. So far, so good.
However now the debugger will expect the variable VarName to have the type
SomeType. So we need the location attribute for the variable to be an
expression that explains to the debugger how to navigate through the
Caroline Tice
committed
pointers and struct to find the actual variable of type SomeType.
The following function does just that. We start by getting
the "normal" location for the variable. This will be the location
of either the struct __Block_byref_x_VarName or the pointer to the
struct __Block_byref_x_VarName.
The struct will look something like:
struct __Block_byref_x_VarName {
... <various fields>
struct __Block_byref_x_VarName *forwarding;
... <various other fields>
SomeType VarName;
... <maybe more fields>
};
If we are given the struct directly (as our starting point) we
need to tell the debugger to:
1). Add the offset of the forwarding field.
2). Follow that pointer to get the real __Block_byref_x_VarName
Caroline Tice
committed
struct to use (the real one may have been copied onto the heap).
3). Add the offset for the field VarName, to find the actual variable.
If we started with a pointer to the struct, then we need to
dereference that pointer first, before the other steps.
Translating this into DWARF ops, we will need to append the following
to the current location description for the variable:
DW_OP_deref -- optional, if we start with a pointer
DW_OP_plus_uconst <forward_fld_offset>
DW_OP_deref
DW_OP_plus_uconst <varName_fld_offset>
That is what this function does. */
/// addBlockByrefAddress - Start with the address based on the location
Caroline Tice
committed
/// 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 DwarfDebug::addBlockByrefAddress(DbgVariable *&DV, DIE *Die,
unsigned Attribute,
const MachineLocation &Location) {
DIType Ty = DV->getType();
Caroline Tice
committed
DIType TmpTy = Ty;
unsigned Tag = Ty.getTag();
bool isPointer = false;
StringRef varName = DV->getName();
Caroline Tice
committed
if (Tag == dwarf::DW_TAG_pointer_type) {
DIDerivedType DTy = DIDerivedType(Ty);
Caroline Tice
committed
TmpTy = DTy.getTypeDerivedFrom();
isPointer = true;
}
DICompositeType blockStruct = DICompositeType(TmpTy);
Caroline Tice
committed
// Find the __forwarding field and the variable field in the __Block_byref
// struct.
DIArray Fields = blockStruct.getTypeArray();
DIDescriptor varField = DIDescriptor();
DIDescriptor forwardingField = DIDescriptor();
Caroline Tice
committed
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")
else if (fieldName == varName)
// Get the offsets for the forwarding field and the variable field.
DIDerivedType(forwardingField).getOffsetInBits() >> 3;
DIDerivedType(varField).getOffsetInBits() >> 3;
Caroline Tice
committed
// 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();
Caroline Tice
committed
addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_reg0 + Reg);
addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_regx);
addUInt(Block, 0, dwarf::DW_FORM_udata, Reg);
addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_breg0 + Reg);
addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_bregx);
addUInt(Block, 0, dwarf::DW_FORM_udata, Reg);
Caroline Tice
committed
addUInt(Block, 0, dwarf::DW_FORM_sdata, Location.getOffset());
Caroline Tice
committed
// 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);
Caroline Tice
committed
// 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);
Caroline Tice
committed
// 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);
Caroline Tice
committed
// 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);
Caroline Tice
committed
addBlock(Die, Attribute, 0, Block);
Caroline Tice
committed
}
/// addAddress - Add an address attribute to a die based on the location
/// provided.
void DwarfDebug::addAddress(DIE *Die, unsigned Attribute,
const MachineLocation &Location) {
const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo();
unsigned Reg = RI->getDwarfRegNum(Location.getReg(), false);
DIEBlock *Block = new (DIEValueAllocator) DIEBlock();
&& Location.getOffset()) {
// If variable offset is based in frame register then use fbreg.
addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_fbreg);
addSInt(Block, 0, dwarf::DW_FORM_sdata, Location.getOffset());
addBlock(Die, Attribute, 0, Block);
return;
}
if (Location.isReg()) {
if (Reg < 32) {
addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_reg0 + Reg);
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);
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());
addBlock(Die, Attribute, 0, Block);
/// addRegisterAddress - Add register location entry in variable DIE.
Devang Patel
committed
bool DwarfDebug::addRegisterAddress(DIE *Die, const MachineOperand &MO) {
assert (MO.isReg() && "Invalid machine operand!");
if (!MO.getReg())
return false;
MachineLocation Location;
Location.set(MO.getReg());
addAddress(Die, dwarf::DW_AT_location, Location);
return true;
}
/// addConstantValue - Add constant value entry in variable DIE.
Devang Patel
committed
bool DwarfDebug::addConstantValue(DIE *Die, const MachineOperand &MO) {
assert (MO.isImm() && "Invalid machine operand!");
DIEBlock *Block = new (DIEValueAllocator) DIEBlock();
unsigned Imm = MO.getImm();
addUInt(Block, 0, dwarf::DW_FORM_udata, Imm);
addBlock(Die, dwarf::DW_AT_const_value, 0, Block);
return true;
}
/// addConstantFPValue - Add constant value entry in variable DIE.
Devang Patel
committed
bool DwarfDebug::addConstantFPValue(DIE *Die, const MachineOperand &MO) {
assert (MO.isFPImm() && "Invalid machine operand!");
DIEBlock *Block = new (DIEValueAllocator) DIEBlock();
APFloat FPImm = MO.getFPImm()->getValueAPF();
// Get the raw data form of the floating point.
const APInt FltVal = FPImm.bitcastToAPInt();
const char *FltPtr = (const char*)FltVal.getRawData();
int NumBytes = FltVal.getBitWidth() / 8; // 8 bits per byte.
bool LittleEndian = Asm->getTargetData().isLittleEndian();
int Incr = (LittleEndian ? 1 : -1);
int Start = (LittleEndian ? 0 : NumBytes - 1);
int Stop = (LittleEndian ? NumBytes : -1);
// Output the constant to DWARF one byte at a time.
for (; Start != Stop; Start += Incr)
addUInt(Block, 0, dwarf::DW_FORM_data1,
(unsigned char)0xFF & FltPtr[Start]);
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
/// addConstantValue - Add constant value entry in variable DIE.
bool DwarfDebug::addConstantValue(DIE *Die, ConstantInt *CI,
bool Unsigned) {
if (CI->getBitWidth() <= 64) {
if (Unsigned)
addUInt(Die, dwarf::DW_AT_const_value, dwarf::DW_FORM_udata,
CI->getZExtValue());
else
addSInt(Die, dwarf::DW_AT_const_value, dwarf::DW_FORM_sdata,
CI->getSExtValue());
return true;
}
DIEBlock *Block = new (DIEValueAllocator) DIEBlock();
// Get the raw data form of the large APInt.
const APInt Val = CI->getValue();
const char *Ptr = (const char*)Val.getRawData();
int NumBytes = Val.getBitWidth() / 8; // 8 bits per byte.
bool LittleEndian = Asm->getTargetData().isLittleEndian();
int Incr = (LittleEndian ? 1 : -1);
int Start = (LittleEndian ? 0 : NumBytes - 1);
int Stop = (LittleEndian ? NumBytes : -1);
// Output the constant to DWARF one byte at a time.
for (; Start != Stop; Start += Incr)
addUInt(Block, 0, dwarf::DW_FORM_data1,
(unsigned char)0xFF & Ptr[Start]);
addBlock(Die, dwarf::DW_AT_const_value, 0, Block);
return true;
}
/// addToContextOwner - Add Die into the list of its context owner's children.
void DwarfDebug::addToContextOwner(DIE *Die, DIDescriptor Context) {
DIE *ContextDIE = getOrCreateTypeDIE(DIType(Context));
ContextDIE->addChild(Die);
} else if (Context.isNameSpace()) {
DIE *ContextDIE = getOrCreateNameSpace(DINameSpace(Context));
ContextDIE->addChild(Die);
Stuart Hastings
committed
} else if (Context.isSubprogram()) {
DIE *ContextDIE = createSubprogramDIE(DISubprogram(Context));
Stuart Hastings
committed
ContextDIE->addChild(Die);
} else if (DIE *ContextDIE = getCompileUnit(Context)->getDIE(Context))
ContextDIE->addChild(Die);
getCompileUnit(Context)->addDie(Die);
/// getOrCreateTypeDIE - Find existing DIE or create new DIE for the
/// given DIType.
DIE *DwarfDebug::getOrCreateTypeDIE(DIType Ty) {
CompileUnit *TypeCU = getCompileUnit(Ty);
DIE *TyDIE = TypeCU->getDIE(Ty);
if (TyDIE)
return TyDIE;
// Create new type.
TyDIE = new DIE(dwarf::DW_TAG_base_type);
TypeCU->insertDIE(Ty, TyDIE);
constructTypeDIE(*TyDIE, DIBasicType(Ty));
constructTypeDIE(*TyDIE, DICompositeType(Ty));
else {
assert(Ty.isDerivedType() && "Unknown kind of DIType");
constructTypeDIE(*TyDIE, DIDerivedType(Ty));
addToContextOwner(TyDIE, Ty.getContext());
/// addType - Add a new type attribute to the specified entity.
void DwarfDebug::addType(DIE *Entity, DIType Ty) {
return;
// Check for pre-existence.
CompileUnit *TypeCU = getCompileUnit(Ty);
DIEEntry *Entry = TypeCU->getDIEEntry(Ty);
// If it exists then use the existing value.
if (Entry) {
Entity->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, Entry);
return;
}
// Construct type.
Jeffrey Yasskin
committed
// Set up proxy.
Entry = createDIEEntry(Buffer);
TypeCU->insertDIEEntry(Ty, Entry);