#define DEBUG_TYPE "dwarfdebug"
#include "DwarfDebug.h"
+#include "DIE.h"
+#include "llvm/Constants.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Analysis/DebugInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/System/Path.h"
using namespace llvm;
+namespace {
+ const char *DWARFGroupName = "DWARF Emission";
+ const char *DbgTimerName = "DWARF Debug Writer";
+} // end anonymous namespace
+
//===----------------------------------------------------------------------===//
/// Configuration values for initial hash set sizes (log2).
void dump() const;
#endif
};
+
+} // end llvm namespace
#ifndef NDEBUG
void DbgScope::dump() const {
delete Variables[j];
}
-} // end llvm namespace
-
-DwarfDebug::DwarfDebug(AsmPrinter *A)
+DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M)
: Asm(A), MMI(Asm->MMI), ModuleCU(0),
- AbbreviationsSet(InitAbbreviationsSetSize), shouldEmit(false),
- CurrentFnDbgScope(0), DebugTimer(0) {
+ AbbreviationsSet(InitAbbreviationsSetSize),
+ CurrentFnDbgScope(0) {
NextStringPoolNumber = 0;
DwarfFrameSectionSym = DwarfInfoSectionSym = DwarfAbbrevSectionSym = 0;
DwarfStrSectionSym = TextSectionSym = 0;
- if (TimePassesIsEnabled)
- DebugTimer = new Timer("Dwarf Debug Writer");
+ beginModule(M);
}
DwarfDebug::~DwarfDebug() {
for (unsigned j = 0, M = DIEBlocks.size(); j < M; ++j)
DIEBlocks[j]->~DIEBlock();
-
- delete DebugTimer;
}
MCSymbol *DwarfDebug::getStringPoolEntry(StringRef Str) {
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->getTargetData());
+ Block->ComputeSize(Asm);
DIEBlocks.push_back(Block); // Memoize so we can call the destructor later on.
Die->addValue(Attribute, Block->BestForm(), Block);
}
return AScope;
}
+/// isSubprogramContext - Return true if Context is either a subprogram
+/// or another context nested inside a subprogram.
+bool isSubprogramContext(MDNode *Context) {
+ if (!Context)
+ return false;
+ DIDescriptor D(Context);
+ if (D.isSubprogram())
+ return true;
+ if (D.isType())
+ return isSubprogramContext(DIType(Context).getContext().getNode());
+ return false;
+}
+
/// updateSubprogramScopeDIE - 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
// 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() && !SP.getContext().isSubprogram()) {
+ !SP.getContext().isFile() &&
+ !isSubprogramContext(SP.getContext().getNode())) {
addUInt(SPDie, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag, 1);
// Add arguments.
unsigned Imm = DbgValueInsn->getOperand(0).getImm();
addUInt(Block, 0, dwarf::DW_FORM_udata, Imm);
addBlock(VariableDie, dwarf::DW_AT_const_value, 0, Block);
+ if (MCSymbol *VS = DV->getDbgValueLabel())
+ addLabel(VariableDie, dwarf::DW_AT_start_scope, dwarf::DW_FORM_addr,
+ VS);
+ } else if (DbgValueInsn->getOperand(0).getType() ==
+ MachineOperand::MO_FPImmediate) {
+ DIEBlock *Block = new (DIEValueAllocator) DIEBlock();
+ APFloat FPImm = DbgValueInsn->getOperand(0).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]);
+
+ addBlock(VariableDie, dwarf::DW_AT_const_value, 0, Block);
+
if (MCSymbol *VS = DV->getDbgValueLabel())
addLabel(VariableDie, dwarf::DW_AT_start_scope, dwarf::DW_FORM_addr,
VS);
// Do not create specification DIE if context is either compile unit
// or a subprogram.
if (DI_GV.isDefinition() && !GVContext.isCompileUnit() &&
- !GVContext.isFile() && !GVContext.isSubprogram()) {
+ !GVContext.isFile() &&
+ !isSubprogramContext(GVContext.getNode())) {
// Create specification DIE.
DIE *VariableSpecDIE = new DIE(dwarf::DW_TAG_variable);
addDIEEntry(VariableSpecDIE, dwarf::DW_AT_specification,
/// content. Create global DIEs and emit initial debug info sections.
/// This is inovked by the target AsmPrinter.
void DwarfDebug::beginModule(Module *M) {
- if (!Asm->MAI->doesSupportDebugInformation())
- return;
+ NamedRegionTimer T(DbgTimerName, DWARFGroupName);
- TimeRegion Timer(DebugTimer);
-
DebugInfoFinder DbgFinder;
DbgFinder.processModule(*M);
+ bool HasDebugInfo = false;
+
+ // Scan all the compile-units to see if there are any marked as the main unit.
+ // if not, we do not generate debug info.
+ for (DebugInfoFinder::iterator I = DbgFinder.compile_unit_begin(),
+ E = DbgFinder.compile_unit_end(); I != E; ++I) {
+ if (DICompileUnit(*I).isMain()) {
+ HasDebugInfo = true;
+ break;
+ }
+ }
+
+ if (!HasDebugInfo) return;
+
+ // Tell MMI that we have debug info.
+ MMI->setDebugInfoAvailability(true);
+
// Emit initial sections.
- if (DbgFinder.compile_unit_begin() != DbgFinder.compile_unit_end())
- EmitSectionLabels();
+ EmitSectionLabels();
// Create all the compile unit DIEs.
for (DebugInfoFinder::iterator I = DbgFinder.compile_unit_begin(),
E = DbgFinder.compile_unit_end(); I != E; ++I)
constructCompileUnit(*I);
- if (!ModuleCU)
- return;
-
// Create DIEs for each subprogram.
for (DebugInfoFinder::iterator I = DbgFinder.subprogram_begin(),
E = DbgFinder.subprogram_end(); I != E; ++I)
E = DbgFinder.global_variable_end(); I != E; ++I)
constructGlobalVariableDIE(*I);
- MMI = Asm->MMI;
- shouldEmit = true;
- MMI->setDebugInfoAvailability(true);
-
// Prime section data.
SectionMap.insert(Asm->getObjFileLowering().getTextSection());
/// endModule - Emit all Dwarf sections that should come after the content.
///
void DwarfDebug::endModule() {
- if (!ModuleCU)
- return;
-
- TimeRegion Timer(DebugTimer);
+ NamedRegionTimer T(DbgTimerName, DWARFGroupName);
+ if (!ModuleCU) return;
// Attach DW_AT_inline attribute with inlined subprogram DIEs.
for (SmallPtrSet<DIE *, 4>::iterator AI = InlinedSubprogramDIEs.begin(),
/// collectVariableInfo - Populate DbgScope entries with variables' info.
void DwarfDebug::collectVariableInfo() {
- if (!MMI) return;
-
const LLVMContext &Ctx = Asm->MF->getFunction()->getContext();
MachineModuleInfo::VariableDbgInfoMapTy &VMap = MMI->getVariableDbgInfo();
/// beginFunction - Gather pre-function debug information. Assumes being
/// emitted immediately after the function entry point.
void DwarfDebug::beginFunction(const MachineFunction *MF) {
- if (!ShouldEmitDwarfDebug()) return;
-
- TimeRegion Timer(DebugTimer);
- if (!extractScopeInformation())
- return;
+ NamedRegionTimer T(DbgTimerName, DWARFGroupName);
+
+ if (!MMI->hasDebugInfo()) return;
+ if (!extractScopeInformation()) return;
collectVariableInfo();
/// endFunction - Gather and emit post-function debug information.
///
void DwarfDebug::endFunction(const MachineFunction *MF) {
- if (!ShouldEmitDwarfDebug()) return;
- if (DbgScopeMap.empty()) return;
-
- TimeRegion Timer(DebugTimer);
+ NamedRegionTimer T(DbgTimerName, DWARFGroupName);
+
+ if (!MMI->hasDebugInfo() || DbgScopeMap.empty()) return;
if (CurrentFnDbgScope) {
// Define end label for subprogram.
/// unique label that was emitted and which provides correspondence to
/// the source line list.
MCSymbol *DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, MDNode *S) {
- if (!MMI)
- return 0;
-
- TimeRegion Timer(DebugTimer);
+ NamedRegionTimer T(DbgTimerName, DWARFGroupName);
StringRef Dir;
StringRef Fn;
/// well.
unsigned DwarfDebug::getOrCreateSourceID(const std::string &DirName,
const std::string &FileName) {
- TimeRegion Timer(DebugTimer);
+ NamedRegionTimer T(DbgTimerName, DWARFGroupName);
return GetOrCreateSourceID(DirName.c_str(), FileName.c_str());
}
// Size the DIE attribute values.
for (unsigned i = 0, N = Values.size(); i < N; ++i)
// Size attribute value.
- Offset += Values[i]->SizeOf(&Asm->getTargetData(), AbbrevData[i].getForm());
+ Offset += Values[i]->SizeOf(Asm, AbbrevData[i].getForm());
// Size the DIE children if any.
if (!Children.empty()) {