зеркало из https://github.com/microsoft/clang.git
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:
Родитель
56cf96b3ea
Коммит
e8b9f5b8ea
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче