Added -g command line options to clang for generating source level debug information. This patch currently enables generation of line number debug information (stoppoints) and region begin/end debug information. The new files CGDebugInfo.h and CGDebugInfo.cpp implements the debug info manager class CGDebugInfo.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50848 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sanjiv Gupta 2008-05-08 08:54:20 +00:00
Родитель 56cf96b3ea
Коммит e8b9f5b8ea
9 изменённых файлов: 320 добавлений и 14 удалений

Просмотреть файл

@ -6,7 +6,7 @@ TOOLNAME = clang
USEDLIBS = clangCodeGen.a clangAnalysis.a clangRewrite.a clangSEMA.a \
clangAST.a clangParse.a clangLex.a clangBasic.a \
LLVMCore.a LLVMSupport.a LLVMSystem.a \
LLVMBitWriter.a LLVMBitReader.a LLVMTarget.a
LLVMBitWriter.a LLVMBitReader.a LLVMCodeGen.a LLVMTarget.a

Просмотреть файл

@ -148,6 +148,13 @@ OutputFile("o",
llvm::cl::value_desc("path"),
llvm::cl::desc("Specify output file (for --serialize, this is a directory)"));
//===----------------------------------------------------------------------===//
// Code Generator Options
//===----------------------------------------------------------------------===//
static llvm::cl::opt<bool>
GenerateDebugInfo("g",
llvm::cl::desc("Generate source level debug information"));
//===----------------------------------------------------------------------===//
// Diagnostic Options
//===----------------------------------------------------------------------===//
@ -1161,7 +1168,7 @@ static ASTConsumer* CreateASTConsumer(const std::string& InFile,
case EmitLLVM:
case EmitBC:
DestModule = new llvm::Module(InFile);
return CreateLLVMCodeGen(Diag, LangOpts, DestModule);
return CreateLLVMCodeGen(Diag, LangOpts, DestModule, GenerateDebugInfo);
case SerializeAST:
// FIXME: Allow user to tailor where the file is written.

Просмотреть файл

@ -24,7 +24,8 @@ namespace clang {
class ASTConsumer;
ASTConsumer *CreateLLVMCodeGen(Diagnostic &Diags, const LangOptions &Features,
llvm::Module *&DestModule);
llvm::Module *&DestModule,
bool GenerateDebugInfo);
}
#endif

171
lib/CodeGen/CGDebugInfo.cpp Normal file
Просмотреть файл

@ -0,0 +1,171 @@
//===--- CGDebugInfo.cpp - Emit Debug Information for a Module ------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This coordinates the debug information generation while generating code.
//
//===----------------------------------------------------------------------===//
#include "CGDebugInfo.h"
#include "CodeGenModule.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/AST/ASTContext.h"
using namespace clang;
using namespace clang::CodeGen;
CGDebugInfo::CGDebugInfo(CodeGenModule *m)
: M(m)
, CurLoc()
, PrevLoc()
, CompileUnitCache()
, StopPointFn(NULL)
, RegionStartFn(NULL)
, RegionEndFn(NULL)
, RegionStack()
{
SR = new llvm::DISerializer();
SR->setModule (&M->getModule());
}
CGDebugInfo::~CGDebugInfo()
{
delete SR;
}
/// getCastValueFor - Return a llvm representation for a given debug information
/// descriptor cast to an empty struct pointer.
llvm::Value *CGDebugInfo::getCastValueFor(llvm::DebugInfoDesc *DD) {
return llvm::ConstantExpr::getBitCast(SR->Serialize(DD),
SR->getEmptyStructPtrType());
}
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new
/// one if necessary.
llvm::CompileUnitDesc
*CGDebugInfo::getOrCreateCompileUnit(const SourceLocation Loc) {
// See if this compile unit has been used before.
llvm::CompileUnitDesc *&Slot = CompileUnitCache[Loc.getFileID()];
if (Slot) return Slot;
// Create new compile unit.
// FIXME: Where to free these?
// One way is to iterate over the CompileUnitCache in ~CGDebugInfo.
llvm::CompileUnitDesc *Unit = new llvm::CompileUnitDesc();
// Make sure we have an anchor.
if (!CompileUnitAnchor) {
CompileUnitAnchor = new llvm::AnchorDesc(Unit);
}
// Get source file information.
SourceManager &SM = M->getContext().getSourceManager();
const FileEntry *FE = SM.getFileEntryForLoc(Loc);
const char *FileName = FE->getName();
const char *DirName = FE->getDir()->getName();
Unit->setAnchor(CompileUnitAnchor);
Unit->setFileName(FileName);
Unit->setDirectory(DirName);
// Set up producer name.
// FIXME: Do not know how to get clang version yet.
Unit->setProducer("clang");
// Set up Language number.
// FIXME: Handle other languages as well.
Unit->setLanguage(llvm::dwarf::DW_LANG_C89);
// Update cache.
Slot = Unit;
return Unit;
}
void
CGDebugInfo::EmitStopPoint(llvm::Function *Fn, llvm::IRBuilder &Builder) {
// Don't bother if things are the same as last time.
SourceManager &SM = M->getContext().getSourceManager();
if (CurLoc == PrevLoc
|| (SM.getLineNumber(CurLoc) == SM.getLineNumber(PrevLoc)
&& SM.isFromSameFile(CurLoc, PrevLoc)))
return;
if (CurLoc.isInvalid()) return;
// Update last state.
PrevLoc = CurLoc;
// Get the appropriate compile unit.
llvm::CompileUnitDesc *Unit = getOrCreateCompileUnit(CurLoc);
// Lazily construct llvm.dbg.stoppoint function.
if (!StopPointFn)
StopPointFn = llvm::Intrinsic::getDeclaration(&M->getModule(),
llvm::Intrinsic::dbg_stoppoint);
uint64_t CurLineNo = SM.getLogicalLineNumber(CurLoc);
uint64_t ColumnNo = SM.getLogicalColumnNumber(CurLoc);
// Invoke llvm.dbg.stoppoint
Builder.CreateCall3(StopPointFn,
llvm::ConstantInt::get(llvm::Type::Int32Ty, CurLineNo),
llvm::ConstantInt::get(llvm::Type::Int32Ty, ColumnNo),
getCastValueFor(Unit), "");
}
/// EmitRegionStart- Constructs the debug code for entering a declarative
/// region - "llvm.dbg.region.start.".
void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, llvm::IRBuilder &Builder)
{
llvm::BlockDesc *Block = new llvm::BlockDesc();
if (RegionStack.size() > 0)
Block->setContext(RegionStack.back());
RegionStack.push_back(Block);
// Lazily construct llvm.dbg.region.start function.
if (!RegionStartFn)
RegionStartFn = llvm::Intrinsic::getDeclaration(&M->getModule(),
llvm::Intrinsic::dbg_region_start);
// Call llvm.dbg.func.start.
Builder.CreateCall(RegionStartFn, getCastValueFor(Block), "");
}
/// EmitRegionEnd - Constructs the debug code for exiting a declarative
/// region - "llvm.dbg.region.end."
void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, llvm::IRBuilder &Builder)
{
// Lazily construct llvm.dbg.region.end function.
if (!RegionEndFn)
RegionEndFn =llvm::Intrinsic::getDeclaration(&M->getModule(),
llvm::Intrinsic::dbg_region_end);
// Provide an region stop point.
EmitStopPoint(Fn, Builder);
// Call llvm.dbg.func.end.
Builder.CreateCall(RegionEndFn, getCastValueFor(RegionStack.back()), "");
RegionStack.pop_back();
// FIXME: Free here the memory created for BlockDesc in RegionStart?
}

84
lib/CodeGen/CGDebugInfo.h Normal file
Просмотреть файл

@ -0,0 +1,84 @@
//===--- CGDebugInfo.h - DebugInfo for LLVM CodeGen -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is the source level debug info generator for llvm translation.
//
//===----------------------------------------------------------------------===//
#ifndef CLANG_CODEGEN_CGDEBUGINFO_H
#define CLANG_CODEGEN_CGDEBUGINFO_H
#include "clang/Basic/SourceLocation.h"
#include <map>
#include <vector>
namespace llvm {
class Function;
class IRBuilder;
class DISerializer;
class CompileUnitDesc;
class BasicBlock;
class AnchorDesc;
class DebugInfoDesc;
class Value;
}
namespace clang {
namespace CodeGen {
class CodeGenModule;
/// DebugInfo - This class gathers all debug information during compilation and
/// is responsible for emitting to llvm globals or pass directly to the backend.
class CGDebugInfo {
private:
CodeGenModule *M;
llvm::DISerializer *SR;
SourceLocation CurLoc;
SourceLocation PrevLoc;
/// CompileUnitCache - Cache of previously constructed CompileUnits.
std::map<unsigned, llvm::CompileUnitDesc *> CompileUnitCache;
llvm::Function *StopPointFn;
llvm::AnchorDesc *CompileUnitAnchor;
llvm::Function *RegionStartFn;
llvm::Function *RegionEndFn;
std::vector<llvm::DebugInfoDesc *> RegionStack;
public:
CGDebugInfo(CodeGenModule *m);
~CGDebugInfo();
void setLocation(SourceLocation loc) { CurLoc = loc; };
/// EmitStopPoint - Emit a call to llvm.dbg.stoppoint to indicate a change of
/// source line.
void EmitStopPoint(llvm::Function *Fn, llvm::IRBuilder &Builder);
/// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start
/// of a new block.
void EmitRegionStart(llvm::Function *Fn, llvm::IRBuilder &Builder);
/// EmitRegionEnd - Emit call to llvm.dbg.region.end to indicate end of a
/// block.
void EmitRegionEnd(llvm::Function *Fn, llvm::IRBuilder &Builder);
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a
/// new one if necessary.
llvm::CompileUnitDesc *getOrCreateCompileUnit(SourceLocation loc);
/// getCastValueFor - Return a llvm representation for a given debug
/// information descriptor cast to an empty struct pointer.
llvm::Value *getCastValueFor(llvm::DebugInfoDesc *DD);
};
} // namespace CodeGen
} // namespace clang
#endif

Просмотреть файл

@ -11,6 +11,8 @@
//
//===----------------------------------------------------------------------===//
#include "CGDebugInfo.h"
#include "CodeGenModule.h"
#include "CodeGenFunction.h"
#include "clang/AST/AST.h"
#include "clang/Basic/TargetInfo.h"
@ -29,6 +31,18 @@ using namespace CodeGen;
void CodeGenFunction::EmitStmt(const Stmt *S) {
assert(S && "Null statement?");
// Generate stoppoints if we are emitting debug info.
// Beginning of a Compound Statement (e.g. an opening '{') does not produce
// executable code. So do not generate a stoppoint for that.
CGDebugInfo *DI = CGM.getDebugInfo();
if (DI && S->getStmtClass() != Stmt::CompoundStmtClass) {
if (S->getLocStart().isValid()) {
DI->setLocation(S->getLocStart());
}
DI->EmitStopPoint(CurFn, Builder);
}
switch (S->getStmtClass()) {
default:
// Must be an expression in a stmt context. Emit the value (to get
@ -74,11 +88,25 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
// FIXME: handle vla's etc.
if (S.body_empty() || !isa<Expr>(S.body_back())) GetLast = false;
CGDebugInfo *DI = CGM.getDebugInfo();
if (DI) {
if (S.getLBracLoc().isValid()) {
DI->setLocation(S.getLBracLoc());
}
DI->EmitRegionStart(CurFn, Builder);
}
for (CompoundStmt::const_body_iterator I = S.body_begin(),
E = S.body_end()-GetLast; I != E; ++I)
EmitStmt(*I);
if (DI) {
if (S.getRBracLoc().isValid()) {
DI->setLocation(S.getRBracLoc());
}
DI->EmitRegionEnd(CurFn, Builder);
}
if (!GetLast)
return RValue::get(0);

Просмотреть файл

@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "CGDebugInfo.h"
#include "CodeGenModule.h"
#include "CodeGenFunction.h"
#include "clang/AST/ASTContext.h"
@ -32,13 +33,19 @@ using namespace CodeGen;
CodeGenModule::CodeGenModule(ASTContext &C, const LangOptions &LO,
llvm::Module &M, const llvm::TargetData &TD,
Diagnostic &diags)
Diagnostic &diags, bool GenerateDebugInfo)
: Context(C), Features(LO), TheModule(M), TheTargetData(TD), Diags(diags),
Types(C, M, TD), MemCpyFn(0), MemSetFn(0), CFConstantStringClassRef(0) {
//TODO: Make this selectable at runtime
Runtime = CreateObjCRuntime(M,
getTypes().ConvertType(getContext().IntTy),
getTypes().ConvertType(getContext().LongTy));
// If debug info generation is enabled, create the CGDebugInfo object.
if (GenerateDebugInfo)
DebugInfo = new CGDebugInfo(this);
else
DebugInfo = NULL;
}
CodeGenModule::~CodeGenModule() {
@ -49,7 +56,7 @@ CodeGenModule::~CodeGenModule() {
EmitGlobalCtors();
EmitAnnotations();
delete Runtime;
delete DebugInfo;
// Run the verifier to check that the generated code is consistent.
assert(!verifyModule(TheModule));
}

Просмотреть файл

@ -43,7 +43,8 @@ namespace clang {
namespace CodeGen {
class CodeGenFunction;
class CGDebugInfo;
/// CodeGenModule - This class organizes the cross-module state that is used
/// while generating LLVM code.
class CodeGenModule {
@ -54,6 +55,7 @@ class CodeGenModule {
Diagnostic &Diags;
CodeGenTypes Types;
CGObjCRuntime *Runtime;
CGDebugInfo *DebugInfo;
llvm::Function *MemCpyFn;
llvm::Function *MemSetFn;
@ -70,10 +72,12 @@ class CodeGenModule {
std::vector<llvm::Function *> BuiltinFunctions;
public:
CodeGenModule(ASTContext &C, const LangOptions &Features, llvm::Module &M,
const llvm::TargetData &TD, Diagnostic &Diags);
const llvm::TargetData &TD, Diagnostic &Diags,
bool GenerateDebugInfo);
~CodeGenModule();
CGObjCRuntime *getObjCRuntime() { return Runtime; }
CGDebugInfo *getDebugInfo() { return DebugInfo; }
ASTContext &getContext() const { return Context; }
const LangOptions &getLangOptions() const { return Features; }
llvm::Module &getModule() const { return TheModule; }

Просмотреть файл

@ -34,13 +34,15 @@ namespace {
const llvm::TargetData *TD;
ASTContext *Ctx;
const LangOptions &Features;
bool GenerateDebugInfo;
protected:
llvm::Module *&M;
CodeGen::CodeGenModule *Builder;
public:
CodeGenerator(Diagnostic &diags, const LangOptions &LO,
llvm::Module *&DestModule)
: Diags(diags), Features(LO), M(DestModule) {}
llvm::Module *&DestModule, bool DebugInfoFlag)
: Diags(diags), Features(LO), GenerateDebugInfo(DebugInfoFlag),
M(DestModule) {}
~CodeGenerator() {
delete Builder;
@ -52,7 +54,8 @@ namespace {
M->setTargetTriple(Ctx->Target.getTargetTriple());
M->setDataLayout(Ctx->Target.getTargetDescription());
TD = new llvm::TargetData(Ctx->Target.getTargetDescription());
Builder = new CodeGen::CodeGenModule(Context, Features, *M, *TD, Diags);
Builder = new CodeGen::CodeGenModule(Context, Features, *M, *TD, Diags,
GenerateDebugInfo);
}
virtual void HandleTopLevelDecl(Decl *D) {
@ -103,7 +106,8 @@ namespace {
ASTConsumer *clang::CreateLLVMCodeGen(Diagnostic &Diags,
const LangOptions &Features,
llvm::Module *&DestModule) {
return new CodeGenerator(Diags, Features, DestModule);
llvm::Module *&DestModule,
bool GenerateDebugInfo) {
return new CodeGenerator(Diags, Features, DestModule, GenerateDebugInfo);
}