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"
Eric Christopher
committed
#include "DwarfAccelTable.h"
#include "DwarfCompileUnit.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/DIBuilder.h"
#include "llvm/DebugInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
Devang Patel
committed
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/ValueHandle.h"
#include "llvm/Target/TargetFrameLowering.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegisterInfo.h"
using namespace llvm;
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 absence of debug location information explicit."),
cl::init(false));
static cl::opt<bool> GenerateDwarfPubNamesSection("generate-dwarf-pubnames",
cl::Hidden, cl::ZeroOrMore, cl::init(false),
cl::desc("Generate DWARF pubnames section"));
namespace {
enum DefaultOnOff {
Default, Enable, Disable
};
}
Eric Christopher
committed
static cl::opt<DefaultOnOff> DwarfAccelTables("dwarf-accel-tables", cl::Hidden,
cl::desc("Output prototype dwarf accelerator tables."),
cl::values(
clEnumVal(Default, "Default for platform"),
clEnumVal(Enable, "Enabled"),
clEnumVal(Disable, "Disabled"),
clEnumValEnd),
cl::init(Default));
static cl::opt<DefaultOnOff> DarwinGDBCompat("darwin-gdb-compat", cl::Hidden,
cl::desc("Compatibility with Darwin gdb."),
cl::values(
clEnumVal(Default, "Default for platform"),
clEnumVal(Enable, "Enabled"),
clEnumVal(Disable, "Disabled"),
clEnumValEnd),
cl::init(Default));
static cl::opt<DefaultOnOff> SplitDwarf("split-dwarf", cl::Hidden,
cl::desc("Output prototype dwarf split debug info."),
Eric Christopher
committed
cl::values(
clEnumVal(Default, "Default for platform"),
clEnumVal(Enable, "Enabled"),
clEnumVal(Disable, "Disabled"),
clEnumValEnd),
cl::init(Default));
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 {
Nick Lewycky
committed
DIType DbgVariable::getType() const {
Devang Patel
committed
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.
Devang Patel
committed
However, as far as the original *programmer* is concerned, the
variable should still have type 'SomeType', as originally declared.
Devang Patel
committed
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.
Devang Patel
committed
The original type 'SomeType' will be the type of the field named
'VarName' inside the __Block_byref_x_VarName struct.
Devang Patel
committed
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();
Devang Patel
committed
if (tag == dwarf::DW_TAG_pointer_type) {
DIDerivedType DTy = DIDerivedType(Ty);
subType = DTy.getTypeDerivedFrom();
}
Devang Patel
committed
DICompositeType blockStruct = DICompositeType(subType);
DIArray Elements = blockStruct.getTypeArray();
Devang Patel
committed
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());
Devang Patel
committed
return Ty;
}
} // end llvm namespace
DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M)
AbbreviationsSet(InitAbbreviationsSetSize),
SourceIdMap(DIEValueAllocator),
PrevLabel(NULL), GlobalCUIndexCount(0),
InfoHolder(A, &AbbreviationsSet, &Abbreviations, "info_string",
DIEValueAllocator),
SkeletonAbbrevSet(InitAbbreviationsSetSize),
SkeletonHolder(A, &SkeletonAbbrevSet, &SkeletonAbbrevs, "skel_string",
DIEValueAllocator) {
DwarfInfoSectionSym = DwarfAbbrevSectionSym = 0;
DwarfStrSectionSym = TextSectionSym = 0;
DwarfDebugRangeSectionSym = DwarfDebugLocSectionSym = DwarfLineSectionSym = 0;
DwarfAbbrevDWOSectionSym = DwarfStrDWOSectionSym = 0;
FunctionBeginSym = FunctionEndSym = 0;
// Turn on accelerator tables and older gdb compatibility
// for Darwin.
bool IsDarwin = Triple(M->getTargetTriple()).isOSDarwin();
if (DarwinGDBCompat == Default) {
if (IsDarwin)
IsDarwinGDBCompat = true;
IsDarwinGDBCompat = false;
} else
IsDarwinGDBCompat = DarwinGDBCompat == Enable ? true : false;
if (DwarfAccelTables == Default) {
if (IsDarwin)
HasDwarfAccelTables = true;
HasDwarfAccelTables = false;
} else
HasDwarfAccelTables = DwarfAccelTables == Enable ? true : false;
if (SplitDwarf == Default)
HasSplitDwarf = false;
Eric Christopher
committed
else
HasSplitDwarf = SplitDwarf == Enable ? true : false;
Eric Christopher
committed
{
NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled);
beginModule();
}
DwarfDebug::~DwarfDebug() {
}
// Switch to the specified MCSection and emit an assembler
// temporary label to it if SymbolStem is specified.
static MCSymbol *emitSectionSym(AsmPrinter *Asm, const MCSection *Section,
const char *SymbolStem = 0) {
Asm->OutStreamer.SwitchSection(Section);
if (!SymbolStem) return 0;
MCSymbol *TmpSym = Asm->GetTempSymbol(SymbolStem);
Asm->OutStreamer.EmitLabel(TmpSym);
return TmpSym;
}
MCSymbol *DwarfUnits::getStringPoolSym() {
return Asm->GetTempSymbol(StringPref);
MCSymbol *DwarfUnits::getStringPoolEntry(StringRef Str) {
std::pair<MCSymbol*, unsigned> &Entry =
StringPool.GetOrCreateValue(Str).getValue();
if (Entry.first) return Entry.first;
Entry.second = NextStringPoolNumber++;
return Entry.first = Asm->GetTempSymbol(StringPref, Entry.second);
unsigned DwarfUnits::getStringPoolIndex(StringRef Str) {
std::pair<MCSymbol*, unsigned> &Entry =
StringPool.GetOrCreateValue(Str).getValue();
if (Entry.first) return Entry.second;
Entry.second = NextStringPoolNumber++;
Entry.first = Asm->GetTempSymbol(StringPref, Entry.second);
return Entry.second;
}
unsigned DwarfUnits::getAddrPoolIndex(MCSymbol *Sym) {
std::pair<MCSymbol*, unsigned> &Entry = AddressPool[Sym];
if (Entry.first) return Entry.second;
Entry.second = NextAddrPoolNumber++;
Entry.first = Sym;
return Entry.second;
}
// Define a unique number for the abbreviation.
//
void DwarfUnits::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());
}
}
// If special LLVM prefix that is used to inform the asm
// printer to not emit usual symbol prefix before the symbol name is used then
// return linkage name after skipping this special LLVM prefix.
static StringRef getRealLinkageName(StringRef LinkageName) {
char One = '\1';
if (LinkageName.startswith(StringRef(&One, 1)))
return LinkageName.substr(1);
return LinkageName;
}
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
static bool isObjCClass(StringRef Name) {
return Name.startswith("+") || Name.startswith("-");
}
static bool hasObjCCategory(StringRef Name) {
if (!isObjCClass(Name)) return false;
size_t pos = Name.find(')');
if (pos != std::string::npos) {
if (Name[pos+1] != ' ') return false;
return true;
}
return false;
}
static void getObjCClassCategory(StringRef In, StringRef &Class,
StringRef &Category) {
if (!hasObjCCategory(In)) {
Class = In.slice(In.find('[') + 1, In.find(' '));
Category = "";
return;
}
Class = In.slice(In.find('[') + 1, In.find('('));
Category = In.slice(In.find('[') + 1, In.find(' '));
return;
}
static StringRef getObjCMethodName(StringRef In) {
return In.slice(In.find(' ') + 1, In.find(']'));
}
// Add the various names to the Dwarf accelerator table names.
static void addSubprogramNames(CompileUnit *TheCU, DISubprogram SP,
DIE* Die) {
if (!SP.isDefinition()) return;
TheCU->addAccelName(SP.getName(), Die);
// If the linkage name is different than the name, go ahead and output
// that as well into the name table.
if (SP.getLinkageName() != "" && SP.getName() != SP.getLinkageName())
TheCU->addAccelName(SP.getLinkageName(), Die);
// If this is an Objective-C selector name add it to the ObjC accelerator
// too.
if (isObjCClass(SP.getName())) {
StringRef Class, Category;
getObjCClassCategory(SP.getName(), Class, Category);
TheCU->addAccelObjC(Class, Die);
if (Category != "")
TheCU->addAccelObjC(Category, Die);
// Also add the base method name to the name table.
TheCU->addAccelName(getObjCMethodName(SP.getName()), Die);
}
}
// Find DIE for the given subprogram and attach appropriate DW_AT_low_pc
// and DW_AT_high_pc attributes. If there are global variables in this
// scope then create and insert DIEs for these variables.
Devang Patel
committed
DIE *DwarfDebug::updateSubprogramScopeDIE(CompileUnit *SPCU,
const MDNode *SPNode) {
DIE *SPDie = SPCU->getDIE(SPNode);
assert(SPDie && "Unable to find subprogram DIE!");
DISubprogram SP(SPNode);
// If we're updating an abstract DIE, then we will be adding the children and
// object pointer later on. But what we don't want to do is process the
// concrete DIE twice.
if (DIE *AbsSPDIE = AbstractSPDies.lookup(SPNode)) {
// Pick up abstract subprogram DIE.
SPDie = new DIE(dwarf::DW_TAG_subprogram);
Devang Patel
committed
SPCU->addDIEEntry(SPDie, dwarf::DW_AT_abstract_origin,
dwarf::DW_FORM_ref4, AbsSPDIE);
SPCU->addDie(SPDie);
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
} else {
DISubprogram SPDecl = SP.getFunctionDeclaration();
if (!SPDecl.isSubprogram()) {
// There is not any need to generate specification DIE for a function
// defined at compile unit level. If a function is defined inside another
// function then gdb prefers the definition at top level and but does not
// expect specification DIE in parent function. So avoid creating
// specification DIE for a function defined inside a function.
if (SP.isDefinition() && !SP.getContext().isCompileUnit() &&
!SP.getContext().isFile() &&
!isSubprogramContext(SP.getContext())) {
SPCU->addFlag(SPDie, dwarf::DW_AT_declaration);
// Add arguments.
DICompositeType SPTy = SP.getType();
DIArray Args = SPTy.getTypeArray();
unsigned SPTag = SPTy.getTag();
if (SPTag == dwarf::DW_TAG_subroutine_type)
for (unsigned i = 1, N = Args.getNumElements(); i < N; ++i) {
DIE *Arg = new DIE(dwarf::DW_TAG_formal_parameter);
DIType ATy = DIType(Args.getElement(i));
SPCU->addType(Arg, ATy);
if (ATy.isArtificial())
SPCU->addFlag(Arg, dwarf::DW_AT_artificial);
if (ATy.isObjectPointer())
SPCU->addDIEEntry(SPDie, dwarf::DW_AT_object_pointer,
dwarf::DW_FORM_ref4, Arg);
SPDie->addChild(Arg);
}
DIE *SPDeclDie = SPDie;
SPDie = new DIE(dwarf::DW_TAG_subprogram);
SPCU->addDIEEntry(SPDie, dwarf::DW_AT_specification,
dwarf::DW_FORM_ref4, SPDeclDie);
SPCU->addDie(SPDie);
}
}
}
SPCU->addLabelAddress(SPDie, dwarf::DW_AT_low_pc,
Asm->GetTempSymbol("func_begin",
Asm->getFunctionNumber()));
SPCU->addLabelAddress(SPDie, dwarf::DW_AT_high_pc,
Asm->GetTempSymbol("func_end",
Asm->getFunctionNumber()));
const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo();
MachineLocation Location(RI->getFrameRegister(*Asm->MF));
Devang Patel
committed
SPCU->addAddress(SPDie, dwarf::DW_AT_frame_base, Location);
// Add name to the name table, we do this here because we're guaranteed
// to have concrete versions of our DW_TAG_subprogram nodes.
addSubprogramNames(SPCU, SP, SPDie);
// Construct new DW_TAG_lexical_block for this scope and attach
// DW_AT_low_pc/DW_AT_high_pc labels.
DIE *DwarfDebug::constructLexicalScopeDIE(CompileUnit *TheCU,
Devang Patel
committed
LexicalScope *Scope) {
DIE *ScopeDIE = new DIE(dwarf::DW_TAG_lexical_block);
if (Scope->isAbstractScope())
return ScopeDIE;
const SmallVector<InsnRange, 4> &Ranges = Scope->getRanges();
Devang Patel
committed
if (Ranges.empty())
return 0;
SmallVector<InsnRange, 4>::const_iterator RI = Ranges.begin();
Devang Patel
committed
if (Ranges.size() > 1) {
// .debug_range section has not been laid out yet. Emit offset in
// .debug_range as a uint, size 4, for now. emitDIE will handle
Devang Patel
committed
// DW_AT_ranges appropriately.
Devang Patel
committed
TheCU->addUInt(ScopeDIE, dwarf::DW_AT_ranges, dwarf::DW_FORM_data4,
* Asm->getDataLayout().getPointerSize());
for (SmallVector<InsnRange, 4>::const_iterator RI = Ranges.begin(),
Devang Patel
committed
RE = Ranges.end(); RI != RE; ++RI) {
DebugRangeSymbols.push_back(getLabelBeforeInsn(RI->first));
DebugRangeSymbols.push_back(getLabelAfterInsn(RI->second));
Devang Patel
committed
}
DebugRangeSymbols.push_back(NULL);
DebugRangeSymbols.push_back(NULL);
return ScopeDIE;
}
MCSymbol *Start = getLabelBeforeInsn(RI->first);
MCSymbol *End = getLabelAfterInsn(RI->second);
Devang Patel
committed
Devang Patel
committed
assert(Start->isDefined() && "Invalid starting label for an inlined scope!");
assert(End->isDefined() && "Invalid end label for an inlined scope!");
TheCU->addLabelAddress(ScopeDIE, dwarf::DW_AT_low_pc, Start);
TheCU->addLabelAddress(ScopeDIE, dwarf::DW_AT_high_pc, End);
return ScopeDIE;
}
// This scope represents inlined body of a function. Construct DIE to
// represent this concrete inlined copy of the function.
Devang Patel
committed
DIE *DwarfDebug::constructInlinedScopeDIE(CompileUnit *TheCU,
LexicalScope *Scope) {
const SmallVector<InsnRange, 4> &Ranges = Scope->getRanges();
Nick Lewycky
committed
assert(Ranges.empty() == false &&
"LexicalScope does not have instruction markers!");
Devang Patel
committed
Devang Patel
committed
if (!Scope->getScopeNode())
return NULL;
DIScope DS(Scope->getScopeNode());
DISubprogram InlinedSP = getDISubprogram(DS);
DIE *OriginDIE = TheCU->getDIE(InlinedSP);
if (!OriginDIE) {
DEBUG(dbgs() << "Unable to find original DIE for an inlined subprogram.");
Devang Patel
committed
return NULL;
}
SmallVector<InsnRange, 4>::const_iterator RI = Ranges.begin();
MCSymbol *StartLabel = getLabelBeforeInsn(RI->first);
MCSymbol *EndLabel = getLabelAfterInsn(RI->second);
Devang Patel
committed
Devang Patel
committed
if (StartLabel == 0 || EndLabel == 0) {
llvm_unreachable("Unexpected Start and End labels for an inlined scope!");
Devang Patel
committed
}
assert(StartLabel->isDefined() &&
"Invalid starting label for an inlined scope!");
assert(EndLabel->isDefined() &&
"Invalid end label for an inlined scope!");
Devang Patel
committed
DIE *ScopeDIE = new DIE(dwarf::DW_TAG_inlined_subroutine);
Devang Patel
committed
TheCU->addDIEEntry(ScopeDIE, dwarf::DW_AT_abstract_origin,
dwarf::DW_FORM_ref4, OriginDIE);
Devang Patel
committed
if (Ranges.size() > 1) {
// .debug_range section has not been laid out yet. Emit offset in
// .debug_range as a uint, size 4, for now. emitDIE will handle
// DW_AT_ranges appropriately.
TheCU->addUInt(ScopeDIE, dwarf::DW_AT_ranges, dwarf::DW_FORM_data4,
* Asm->getDataLayout().getPointerSize());
for (SmallVector<InsnRange, 4>::const_iterator RI = Ranges.begin(),
Devang Patel
committed
RE = Ranges.end(); RI != RE; ++RI) {
DebugRangeSymbols.push_back(getLabelBeforeInsn(RI->first));
DebugRangeSymbols.push_back(getLabelAfterInsn(RI->second));
}
DebugRangeSymbols.push_back(NULL);
DebugRangeSymbols.push_back(NULL);
} else {
TheCU->addLabelAddress(ScopeDIE, dwarf::DW_AT_low_pc, StartLabel);
TheCU->addLabelAddress(ScopeDIE, dwarf::DW_AT_high_pc, EndLabel);
Devang Patel
committed
}
InlinedSubprogramDIEs.insert(OriginDIE);
// Track the start label for this inlined function.
Devang Patel
committed
//.debug_inlined section specification does not clearly state how
// to emit inlined scope that is split into multiple instruction ranges.
// For now, use first instruction range and emit low_pc/high_pc pair and
// corresponding .debug_inlined section entry for this pair.
DenseMap<const MDNode *, SmallVector<InlineInfoLabels, 4> >::iterator
I = InlineInfo.find(InlinedSP);
if (I == InlineInfo.end()) {
Nick Lewycky
committed
InlineInfo[InlinedSP].push_back(std::make_pair(StartLabel, ScopeDIE));
InlinedSPNodes.push_back(InlinedSP);
I->second.push_back(std::make_pair(StartLabel, ScopeDIE));
DILocation DL(Scope->getInlinedAt());
TheCU->addUInt(ScopeDIE, dwarf::DW_AT_call_file, 0,
getOrCreateSourceID(DL.getFilename(), DL.getDirectory(),
TheCU->getUniqueID()));
Devang Patel
committed
TheCU->addUInt(ScopeDIE, dwarf::DW_AT_call_line, 0, DL.getLineNumber());
// Add name to the name table, we do this here because we're guaranteed
// to have concrete versions of our DW_TAG_inlined_subprogram nodes.
addSubprogramNames(TheCU, InlinedSP, ScopeDIE);
// Construct a DIE for this scope.
Devang Patel
committed
DIE *DwarfDebug::constructScopeDIE(CompileUnit *TheCU, LexicalScope *Scope) {
if (!Scope || !Scope->getScopeNode())
return NULL;
DIScope DS(Scope->getScopeNode());
// Early return to avoid creating dangling variable|scope DIEs.
if (!Scope->getInlinedAt() && DS.isSubprogram() && Scope->isAbstractScope() &&
!TheCU->getDIE(DS))
return NULL;
Nick Lewycky
committed
SmallVector<DIE *, 8> Children;
Devang Patel
committed
// Collect arguments for current function.
if (LScopes.isCurrentFunctionScope(Scope))
Devang Patel
committed
for (unsigned i = 0, N = CurrentFnArguments.size(); i < N; ++i)
if (DbgVariable *ArgDV = CurrentFnArguments[i])
TheCU->constructVariableDIE(ArgDV, Scope->isAbstractScope())) {
Devang Patel
committed
Children.push_back(Arg);
if (ArgDV->isObjectPointer()) ObjectPointer = Arg;
}
Devang Patel
committed
const SmallVector<DbgVariable *, 8> &Variables = ScopeVariables.lookup(Scope);
Devang Patel
committed
for (unsigned i = 0, N = Variables.size(); i < N; ++i)
TheCU->constructVariableDIE(Variables[i], Scope->isAbstractScope())) {
Devang Patel
committed
Children.push_back(Variable);
if (Variables[i]->isObjectPointer()) ObjectPointer = Variable;
}
const SmallVector<LexicalScope *, 4> &Scopes = Scope->getChildren();
Devang Patel
committed
for (unsigned j = 0, M = Scopes.size(); j < M; ++j)
Devang Patel
committed
if (DIE *Nested = constructScopeDIE(TheCU, Scopes[j]))
Devang Patel
committed
Children.push_back(Nested);
DIE *ScopeDIE = NULL;
if (Scope->getInlinedAt())
Devang Patel
committed
ScopeDIE = constructInlinedScopeDIE(TheCU, Scope);
ProcessedSPNodes.insert(DS);
if (Scope->isAbstractScope()) {
Devang Patel
committed
ScopeDIE = TheCU->getDIE(DS);
// Note down abstract DIE.
if (ScopeDIE)
AbstractSPDies.insert(std::make_pair(DS, ScopeDIE));
}
Devang Patel
committed
ScopeDIE = updateSubprogramScopeDIE(TheCU, DS);
Devang Patel
committed
else {
// There is no need to emit empty lexical block DIE.
if (Children.empty())
return NULL;
Devang Patel
committed
ScopeDIE = constructLexicalScopeDIE(TheCU, Scope);
Devang Patel
committed
if (!ScopeDIE) return NULL;
Devang Patel
committed
// Add children
for (SmallVector<DIE *, 8>::iterator I = Children.begin(),
E = Children.end(); I != E; ++I)
ScopeDIE->addChild(*I);
if (DS.isSubprogram() && ObjectPointer != NULL)
TheCU->addDIEEntry(ScopeDIE, dwarf::DW_AT_object_pointer,
dwarf::DW_FORM_ref4, ObjectPointer);
TheCU->addPubTypes(DISubprogram(DS));
return ScopeDIE;
// Look up the source id with the given directory and source file names.
// If none currently exists, create a new id and insert it in the
// SourceIds map. This can update DirectoryNames and SourceFileNames maps
// as well.
unsigned DwarfDebug::getOrCreateSourceID(StringRef FileName,
StringRef DirName, unsigned CUID) {
// If we use .loc in assembly, we can't separate .file entries according to
// compile units. Thus all files will belong to the default compile unit.
if (Asm->TM.hasMCUseLoc() &&
Asm->OutStreamer.getKind() == MCStreamer::SK_AsmStreamer)
CUID = 0;
Devang Patel
committed
// If FE did not provide a file name, then assume stdin.
if (FileName.empty())
return getOrCreateSourceID("<stdin>", StringRef(), CUID);
Devang Patel
committed
// TODO: this might not belong here. See if we can factor this better.
if (DirName == CompilationDir)
DirName = "";
// FileIDCUMap stores the current ID for the given compile unit.
unsigned SrcId = FileIDCUMap[CUID] + 1;
// We look up the CUID/file/dir by concatenating them with a zero byte.
Benjamin Kramer
committed
SmallString<128> NamePair;
NamePair += CUID;
NamePair += '\0';
Benjamin Kramer
committed
NamePair += DirName;
NamePair += '\0'; // Zero bytes are not allowed in paths.
NamePair += FileName;
StringMapEntry<unsigned> &Ent = SourceIdMap.GetOrCreateValue(NamePair, SrcId);
if (Ent.getValue() != SrcId)
return Ent.getValue();
FileIDCUMap[CUID] = SrcId;
Rafael Espindola
committed
// Print out a .file directive to specify files for .loc directives.
Asm->OutStreamer.EmitDwarfFileDirective(SrcId, DirName, FileName, CUID);
// Create new CompileUnit for the given metadata node with tag
// DW_TAG_compile_unit.
Devang Patel
committed
CompileUnit *DwarfDebug::constructCompileUnit(const MDNode *N) {
StringRef FN = DIUnit.getFilename();
CompilationDir = DIUnit.getDirectory();
DIE *Die = new DIE(dwarf::DW_TAG_compile_unit);
CompileUnit *NewCU = new CompileUnit(GlobalCUIndexCount++,
DIUnit.getLanguage(), Die, Asm,
this, &InfoHolder);
FileIDCUMap[NewCU->getUniqueID()] = 0;
// Call this to emit a .file directive if it wasn't emitted for the source
// file this CU comes from yet.
getOrCreateSourceID(FN, CompilationDir, NewCU->getUniqueID());
NewCU->addString(Die, dwarf::DW_AT_producer, DIUnit.getProducer());
Devang Patel
committed
NewCU->addUInt(Die, dwarf::DW_AT_language, dwarf::DW_FORM_data2,
DIUnit.getLanguage());
NewCU->addString(Die, dwarf::DW_AT_name, FN);
Eric Christopher
committed
// 2.17.1 requires that we use DW_AT_low_pc for a single entry point
// into an entity. We're using 0 (or a NULL label) for this.
NewCU->addLabelAddress(Die, dwarf::DW_AT_low_pc, NULL);
Manman Ren
committed
// Define start line table label for each Compile Unit.
MCSymbol *LineTableStartSym = Asm->GetTempSymbol("line_table_start",
NewCU->getUniqueID());
Asm->OutStreamer.getContext().setMCLineTableSymbol(LineTableStartSym,
NewCU->getUniqueID());
// DW_AT_stmt_list is a offset of line number information for this
// compile unit in debug_line section.
// The line table entries are not always emitted in assembly, so it
// is not okay to use line_table_start here.
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
NewCU->addLabel(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4,
NewCU->getUniqueID() == 0 ?
Asm->GetTempSymbol("section_line") : LineTableStartSym);
else if (NewCU->getUniqueID() == 0)
NewCU->addUInt(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4, 0);
Devang Patel
committed
else
Manman Ren
committed
NewCU->addDelta(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4,
LineTableStartSym, DwarfLineSectionSym);
if (!CompilationDir.empty())
NewCU->addString(Die, dwarf::DW_AT_comp_dir, CompilationDir);
NewCU->addFlag(Die, dwarf::DW_AT_APPLE_optimized);
StringRef Flags = DIUnit.getFlags();
if (!Flags.empty())
NewCU->addString(Die, dwarf::DW_AT_APPLE_flags, Flags);
if (unsigned RVer = DIUnit.getRunTimeVersion())
Devang Patel
committed
NewCU->addUInt(Die, dwarf::DW_AT_APPLE_major_runtime_vers,
dwarf::DW_FORM_data1, RVer);
if (!FirstCU)
FirstCU = NewCU;
if (useSplitDwarf()) {
// This should be a unique identifier when we want to build .dwp files.
NewCU->addUInt(Die, dwarf::DW_AT_GNU_dwo_id, dwarf::DW_FORM_data8, 0);
// Now construct the skeleton CU associated.
constructSkeletonCU(N);
}
InfoHolder.addUnit(NewCU);
CUMap.insert(std::make_pair(N, NewCU));
Devang Patel
committed
return NewCU;
// Construct subprogram DIE.
void DwarfDebug::constructSubprogramDIE(CompileUnit *TheCU,
Devang Patel
committed
const MDNode *N) {
Rafael Espindola
committed
CompileUnit *&CURef = SPMap[N];
if (CURef)
return;
CURef = TheCU;
if (!SP.isDefinition())
// This is a method declaration which will be handled while constructing
// class type.
Bill Wendling
committed
Devang Patel
committed
DIE *SubprogramDie = TheCU->getOrCreateSubprogramDIE(SP);
// Add to map.
TheCU->insertDIE(N, SubprogramDie);
Devang Patel
committed
TheCU->addToContextOwner(SubprogramDie, SP.getContext());
// Expose as global, if requested.
if (GenerateDwarfPubNamesSection)
TheCU->addGlobalName(SP.getName(), SubprogramDie);
// Emit all Dwarf sections that should come prior to the content. Create
// global DIEs and emit initial debug info sections. This is invoked by
// the target AsmPrinter.
void DwarfDebug::beginModule() {
Devang Patel
committed
if (DisableDebugInfoPrinting)
return;
const Module *M = MMI->getModule();
Nick Lewycky
committed
// If module has named metadata anchors then use them, otherwise scan the
// module using debug info finder to collect debug info.
Devang Patel
committed
NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu");
// Emit initial sections so we can reference labels later.
emitSectionLabels();
for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) {
DICompileUnit CUNode(CU_Nodes->getOperand(i));
CompileUnit *CU = constructCompileUnit(CUNode);
DIArray GVs = CUNode.getGlobalVariables();
for (unsigned i = 0, e = GVs.getNumElements(); i != e; ++i)
CU->createGlobalVariableDIE(GVs.getElement(i));
DIArray SPs = CUNode.getSubprograms();
for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i)
constructSubprogramDIE(CU, SPs.getElement(i));
DIArray EnumTypes = CUNode.getEnumTypes();
for (unsigned i = 0, e = EnumTypes.getNumElements(); i != e; ++i)
CU->getOrCreateTypeDIE(EnumTypes.getElement(i));
DIArray RetainedTypes = CUNode.getRetainedTypes();
for (unsigned i = 0, e = RetainedTypes.getNumElements(); i != e; ++i)
CU->getOrCreateTypeDIE(RetainedTypes.getElement(i));
}
// Tell MMI that we have debug info.
MMI->setDebugInfoAvailability(true);
SectionMap.insert(Asm->getObjFileLowering().getTextSection());
// Attach DW_AT_inline attribute with inlined subprogram DIEs.
void DwarfDebug::computeInlinedDIEs() {
// Attach DW_AT_inline attribute with inlined subprogram DIEs.
for (SmallPtrSet<DIE *, 4>::iterator AI = InlinedSubprogramDIEs.begin(),
AE = InlinedSubprogramDIEs.end(); AI != AE; ++AI) {
DIE *ISP = *AI;
FirstCU->addUInt(ISP, dwarf::DW_AT_inline, 0, dwarf::DW_INL_inlined);
}
for (DenseMap<const MDNode *, DIE *>::iterator AI = AbstractSPDies.begin(),
DIE *ISP = AI->second;
if (InlinedSubprogramDIEs.count(ISP))
continue;
FirstCU->addUInt(ISP, dwarf::DW_AT_inline, 0, dwarf::DW_INL_inlined);
}
}
// Collect info for variables that were optimized out.
void DwarfDebug::collectDeadVariables() {
const Module *M = MMI->getModule();
DenseMap<const MDNode *, LexicalScope *> DeadFnScopeMap;
Devang Patel
committed
if (NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu")) {
for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) {
DICompileUnit TheCU(CU_Nodes->getOperand(i));
DIArray Subprograms = TheCU.getSubprograms();
for (unsigned i = 0, e = Subprograms.getNumElements(); i != e; ++i) {
DISubprogram SP(Subprograms.getElement(i));
if (ProcessedSPNodes.count(SP) != 0) continue;
if (!SP.Verify()) continue;
if (!SP.isDefinition()) continue;
DIArray Variables = SP.getVariables();
if (Variables.getNumElements() == 0) continue;
LexicalScope *Scope =
new LexicalScope(NULL, DIDescriptor(SP), NULL, false);
DeadFnScopeMap[SP] = Scope;
// Construct subprogram DIE and add variables DIEs.
CompileUnit *SPCU = CUMap.lookup(TheCU);
assert(SPCU && "Unable to find Compile Unit!");
constructSubprogramDIE(SPCU, SP);
DIE *ScopeDIE = SPCU->getDIE(SP);
for (unsigned vi = 0, ve = Variables.getNumElements(); vi != ve; ++vi) {
DIVariable DV(Variables.getElement(vi));
if (!DV.Verify()) continue;
DbgVariable *NewVar = new DbgVariable(DV, NULL);
if (DIE *VariableDIE =
SPCU->constructVariableDIE(NewVar, Scope->isAbstractScope()))
ScopeDIE->addChild(VariableDIE);
}
DeleteContainerSeconds(DeadFnScopeMap);
}
void DwarfDebug::finalizeModuleInfo() {
// Collect info for variables that were optimized out.
collectDeadVariables();
// Attach DW_AT_inline attribute with inlined subprogram DIEs.
computeInlinedDIEs();
Eric Christopher
committed
// Emit DW_AT_containing_type attribute to connect types with their
// vtable holding type.
Devang Patel
committed
for (DenseMap<const MDNode *, CompileUnit *>::iterator CUI = CUMap.begin(),
Devang Patel
committed
CompileUnit *TheCU = CUI->second;
TheCU->constructContainingTypeDIEs();
Devang Patel
committed
}
// Compute DIE offsets and sizes.
InfoHolder.computeSizeAndOffsets();
if (useSplitDwarf())
SkeletonHolder.computeSizeAndOffsets();
}
void DwarfDebug::endSections() {
// Standard sections final addresses.
Asm->OutStreamer.SwitchSection(Asm->getObjFileLowering().getTextSection());
Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("text_end"));
Asm->OutStreamer.SwitchSection(Asm->getObjFileLowering().getDataSection());
Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("data_end"));
Benjamin Kramer
committed
for (unsigned I = 0, E = SectionMap.size(); I != E; ++I) {
Asm->OutStreamer.SwitchSection(SectionMap[I]);
Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("section_end", I+1));
}
// Emit all Dwarf sections that should come after the content.
void DwarfDebug::endModule() {
if (!FirstCU) return;
// End any existing sections.
// TODO: Does this need to happen?
endSections();
// Finalize the debug info for the module.
finalizeModuleInfo();
if (!useSplitDwarf()) {
// Emit all the DIEs into a debug info section.
emitDebugInfo();
// Corresponding abbreviations into a abbrev section.
emitAbbreviations();
// Emit info into a debug loc section.
emitDebugLoc();
// Emit info into a debug aranges section.
emitDebugARanges();
// Emit info into a debug ranges section.
emitDebugRanges();
// Emit info into a debug macinfo section.
emitDebugMacInfo();
// Emit inline info.
// TODO: When we don't need the option anymore we
// can remove all of the code that this section
// depends upon.
if (useDarwinGDBCompat())
emitDebugInlineInfo();
} else {
// TODO: Fill this in for separated debug sections and separate
// out information into new sections.
// Emit the debug info section and compile units.
emitDebugInfo();
emitDebugInfoDWO();
// Corresponding abbreviations into a abbrev section.
emitAbbreviations();
emitDebugAbbrevDWO();
// Emit info into a debug loc section.
emitDebugLoc();
// Emit info into a debug aranges section.
emitDebugARanges();
// Emit info into a debug ranges section.
emitDebugRanges();
// Emit info into a debug macinfo section.
emitDebugMacInfo();
// Emit DWO addresses.
InfoHolder.emitAddresses(Asm->getObjFileLowering().getDwarfAddrSection());
// Emit inline info.
// TODO: When we don't need the option anymore we
// can remove all of the code that this section
// depends upon.
if (useDarwinGDBCompat())
emitDebugInlineInfo();
}
if (useDwarfAccelTables()) {
Eric Christopher
committed
emitAccelNames();
emitAccelObjC();
emitAccelNamespaces();
emitAccelTypes();
}
// Emit info into a debug pubnames section, if requested.
if (GenerateDwarfPubNamesSection)
emitDebugPubnames();
// TODO: When we don't need the option anymore we can
// remove all of the code that adds to the table.
if (useDarwinGDBCompat())
emitDebugPubTypes();
// Finally emit string information into a string table.
emitDebugStr();
if (useSplitDwarf())
emitDebugStrDWO();
Devang Patel
committed
SPMap.clear();
for (DenseMap<const MDNode *, CompileUnit *>::iterator I = CUMap.begin(),
E = CUMap.end(); I != E; ++I)
delete I->second;
for (SmallVector<CompileUnit *, 1>::iterator I = SkeletonCUs.begin(),
E = SkeletonCUs.end(); I != E; ++I)
delete *I;
// Reset these for the next Module if we have one.
FirstCU = NULL;