summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorYuchen Wu <yuchenericwu@hotmail.com>2013-11-20 04:15:05 +0000
committerYuchen Wu <yuchenericwu@hotmail.com>2013-11-20 04:15:05 +0000
commitd23c759c0fa10b7fb244b4d2911b49b95138a7e1 (patch)
tree4346b143320207b2cc677a34902d7e0ddc697eb8 /lib
parent523d929368829b5157748f46f85b4577b7fd6ca1 (diff)
downloadllvm-d23c759c0fa10b7fb244b4d2911b49b95138a7e1.tar.gz
llvm-d23c759c0fa10b7fb244b4d2911b49b95138a7e1.tar.bz2
llvm-d23c759c0fa10b7fb244b4d2911b49b95138a7e1.tar.xz
llvm-cov: Added file checksum to gcno and gcda files.
Instead of permanently outputting "MVLL" as the file checksum, clang will create gcno and gcda checksums by hashing the destination block numbers of every arc. This allows for llvm-cov to check if the two gcov files are synchronized. Regenerated the test files so they contain the checksum. Also added negative test to ensure error when the checksums don't match. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@195191 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/IR/GCOV.cpp7
-rw-r--r--lib/Transforms/Instrumentation/GCOVProfiling.cpp122
2 files changed, 89 insertions, 40 deletions
diff --git a/lib/IR/GCOV.cpp b/lib/IR/GCOV.cpp
index 25a4ff669d..622c4f7851 100644
--- a/lib/IR/GCOV.cpp
+++ b/lib/IR/GCOV.cpp
@@ -46,6 +46,7 @@ bool GCOVFile::read(GCOVBuffer &Buffer) {
return false;
if (isGCNOFile(Format)) {
+ if (!Buffer.readInt(Checksum)) return false;
while (true) {
if (!Buffer.readFunctionTag()) break;
GCOVFunction *GFun = new GCOVFunction();
@@ -55,6 +56,12 @@ bool GCOVFile::read(GCOVBuffer &Buffer) {
}
}
else if (isGCDAFile(Format)) {
+ uint32_t Checksum2;
+ if (!Buffer.readInt(Checksum2)) return false;
+ if (Checksum != Checksum2) {
+ errs() << "File checksum does not match.\n";
+ return false;
+ }
for (size_t i = 0, e = Functions.size(); i < e; ++i) {
if (!Buffer.readFunctionTag()) {
errs() << "Unexpected number of functions.\n";
diff --git a/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/lib/Transforms/Instrumentation/GCOVProfiling.cpp
index 206bffbb27..03c63557bc 100644
--- a/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+++ b/lib/Transforms/Instrumentation/GCOVProfiling.cpp
@@ -18,6 +18,7 @@
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
@@ -62,20 +63,28 @@ GCOVOptions GCOVOptions::getDefault() {
}
namespace {
+ class GCOVFunction;
+
class GCOVProfiler : public ModulePass {
public:
static char ID;
GCOVProfiler() : ModulePass(ID), Options(GCOVOptions::getDefault()) {
- ReversedVersion[0] = Options.Version[3];
- ReversedVersion[1] = Options.Version[2];
- ReversedVersion[2] = Options.Version[1];
- ReversedVersion[3] = Options.Version[0];
- ReversedVersion[4] = '\0';
- initializeGCOVProfilerPass(*PassRegistry::getPassRegistry());
+ init();
}
GCOVProfiler(const GCOVOptions &Options) : ModulePass(ID), Options(Options){
assert((Options.EmitNotes || Options.EmitData) &&
"GCOVProfiler asked to do nothing?");
+ init();
+ }
+ ~GCOVProfiler() {
+ DeleteContainerPointers(Funcs);
+ }
+ virtual const char *getPassName() const {
+ return "GCOV Profiler";
+ }
+
+ private:
+ void init() {
ReversedVersion[0] = Options.Version[3];
ReversedVersion[1] = Options.Version[2];
ReversedVersion[2] = Options.Version[1];
@@ -83,11 +92,6 @@ namespace {
ReversedVersion[4] = '\0';
initializeGCOVProfilerPass(*PassRegistry::getPassRegistry());
}
- virtual const char *getPassName() const {
- return "GCOV Profiler";
- }
-
- private:
bool runOnModule(Module &M);
// Create the .gcno files for the Module based on DebugInfo.
@@ -131,9 +135,12 @@ namespace {
// Reversed, NUL-terminated copy of Options.Version.
char ReversedVersion[5];
+ // Checksum, produced by hash of EdgeDestinations
+ uint32_t FileChecksum;
Module *M;
LLVMContext *Ctx;
+ SmallVector<GCOVFunction *, 16> Funcs;
};
}
@@ -145,7 +152,7 @@ ModulePass *llvm::createGCOVProfilerPass(const GCOVOptions &Options) {
return new GCOVProfiler(Options);
}
-static std::string getFunctionName(DISubprogram SP) {
+static StringRef getFunctionName(DISubprogram SP) {
if (!SP.getLinkageName().empty())
return SP.getLinkageName();
return SP.getName();
@@ -302,7 +309,8 @@ namespace {
class GCOVFunction : public GCOVRecord {
public:
GCOVFunction(DISubprogram SP, raw_ostream *os, uint32_t Ident,
- bool UseCfgChecksum) {
+ bool UseCfgChecksum) :
+ SP(SP), Ident(Ident), UseCfgChecksum(UseCfgChecksum), CfgChecksum(0) {
this->os = os;
Function *F = SP.getFunction();
@@ -312,20 +320,6 @@ namespace {
Blocks[BB] = new GCOVBlock(i++, os);
}
ReturnBlock = new GCOVBlock(i++, os);
-
- writeBytes(FunctionTag, 4);
- uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(getFunctionName(SP)) +
- 1 + lengthOfGCOVString(SP.getFilename()) + 1;
- if (UseCfgChecksum)
- ++BlockLen;
- write(BlockLen);
- write(Ident);
- write(0); // lineno checksum
- if (UseCfgChecksum)
- write(0); // cfg checksum
- writeGCOVString(getFunctionName(SP));
- writeGCOVString(SP.getFilename());
- write(SP.getLineNumber());
}
~GCOVFunction() {
@@ -341,7 +335,37 @@ namespace {
return *ReturnBlock;
}
+ std::string getEdgeDestinations() {
+ std::string EdgeDestinations;
+ raw_string_ostream EDOS(EdgeDestinations);
+ Function *F = Blocks.begin()->first->getParent();
+ for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
+ GCOVBlock &Block = *Blocks[I];
+ for (int i = 0, e = Block.OutEdges.size(); i != e; ++i)
+ EDOS << Block.OutEdges[i]->Number;
+ }
+ return EdgeDestinations;
+ }
+
+ void setCfgChecksum(uint32_t Checksum) {
+ CfgChecksum = Checksum;
+ }
+
void writeOut() {
+ writeBytes(FunctionTag, 4);
+ uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(getFunctionName(SP)) +
+ 1 + lengthOfGCOVString(SP.getFilename()) + 1;
+ if (UseCfgChecksum)
+ ++BlockLen;
+ write(BlockLen);
+ write(Ident);
+ write(0); // lineno checksum
+ if (UseCfgChecksum)
+ write(CfgChecksum);
+ writeGCOVString(getFunctionName(SP));
+ writeGCOVString(SP.getFilename());
+ write(SP.getLineNumber());
+
// Emit count of blocks.
writeBytes(BlockTag, 4);
write(Blocks.size() + 1);
@@ -375,6 +399,10 @@ namespace {
}
private:
+ DISubprogram SP;
+ uint32_t Ident;
+ bool UseCfgChecksum;
+ uint32_t CfgChecksum;
DenseMap<BasicBlock *, GCOVBlock *> Blocks;
GCOVBlock *ReturnBlock;
};
@@ -427,9 +455,7 @@ void GCOVProfiler::emitProfileNotes() {
std::string ErrorInfo;
raw_fd_ostream out(mangleName(CU, "gcno").c_str(), ErrorInfo,
sys::fs::F_Binary);
- out.write("oncg", 4);
- out.write(ReversedVersion, 4);
- out.write("MVLL", 4);
+ std::string EdgeDestinations;
DIArray SPs = CU.getSubprograms();
for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i) {
@@ -441,17 +467,19 @@ void GCOVProfiler::emitProfileNotes() {
Function *F = SP.getFunction();
if (!F) continue;
- GCOVFunction Func(SP, &out, i, Options.UseCfgChecksum);
+ GCOVFunction *Func =
+ new GCOVFunction(SP, &out, i, Options.UseCfgChecksum);
+ Funcs.push_back(Func);
for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
- GCOVBlock &Block = Func.getBlock(BB);
+ GCOVBlock &Block = Func->getBlock(BB);
TerminatorInst *TI = BB->getTerminator();
if (int successors = TI->getNumSuccessors()) {
for (int i = 0; i != successors; ++i) {
- Block.addEdge(Func.getBlock(TI->getSuccessor(i)));
+ Block.addEdge(Func->getBlock(TI->getSuccessor(i)));
}
} else if (isa<ReturnInst>(TI)) {
- Block.addEdge(Func.getReturnBlock());
+ Block.addEdge(Func->getReturnBlock());
}
uint32_t Line = 0;
@@ -467,8 +495,18 @@ void GCOVProfiler::emitProfileNotes() {
Lines.addLine(Loc.getLine());
}
}
- Func.writeOut();
+ EdgeDestinations += Func->getEdgeDestinations();
}
+
+ FileChecksum = hash_value(EdgeDestinations);
+ out.write("oncg", 4);
+ out.write(ReversedVersion, 4);
+ out.write(reinterpret_cast<char*>(&FileChecksum), 4);
+
+ for (SmallVectorImpl<GCOVFunction *>::iterator I = Funcs.begin(),
+ E = Funcs.end(); I != E; ++I)
+ (*I)->writeOut();
+
out.write("\0\0\0\0\0\0\0\0", 8); // EOF
out.close();
}
@@ -666,6 +704,7 @@ Constant *GCOVProfiler::getStartFileFunc() {
Type *Args[] = {
Type::getInt8PtrTy(*Ctx), // const char *orig_filename
Type::getInt8PtrTy(*Ctx), // const char version[4]
+ Type::getInt32Ty(*Ctx), // uint32_t checksum
};
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false);
return M->getOrInsertFunction("llvm_gcda_start_file", FTy);
@@ -683,10 +722,11 @@ Constant *GCOVProfiler::getIncrementIndirectCounterFunc() {
}
Constant *GCOVProfiler::getEmitFunctionFunc() {
- Type *Args[3] = {
+ Type *Args[] = {
Type::getInt32Ty(*Ctx), // uint32_t ident
Type::getInt8PtrTy(*Ctx), // const char *function_name
Type::getInt8Ty(*Ctx), // uint8_t use_extra_checksum
+ Type::getInt32Ty(*Ctx), // uint32_t cfg_checksum
};
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false);
return M->getOrInsertFunction("llvm_gcda_emit_function", FTy);
@@ -760,17 +800,19 @@ Function *GCOVProfiler::insertCounterWriteout(
for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) {
DICompileUnit CU(CU_Nodes->getOperand(i));
std::string FilenameGcda = mangleName(CU, "gcda");
- Builder.CreateCall2(StartFile,
+ Builder.CreateCall3(StartFile,
Builder.CreateGlobalStringPtr(FilenameGcda),
- Builder.CreateGlobalStringPtr(ReversedVersion));
+ Builder.CreateGlobalStringPtr(ReversedVersion),
+ Builder.getInt32(FileChecksum));
for (unsigned j = 0, e = CountersBySP.size(); j != e; ++j) {
DISubprogram SP(CountersBySP[j].second);
- Builder.CreateCall3(
+ Builder.CreateCall4(
EmitFunction, Builder.getInt32(j),
Options.FunctionNamesInData ?
Builder.CreateGlobalStringPtr(getFunctionName(SP)) :
Constant::getNullValue(Builder.getInt8PtrTy()),
- Builder.getInt8(Options.UseCfgChecksum));
+ Builder.getInt8(Options.UseCfgChecksum),
+ Builder.getInt32(FileChecksum));
GlobalVariable *GV = CountersBySP[j].first;
unsigned Arcs =