summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Support/GCOV.h15
-rw-r--r--lib/IR/GCOV.cpp7
-rw-r--r--lib/Transforms/Instrumentation/GCOVProfiling.cpp122
-rw-r--r--test/Transforms/GCOVProfiling/version.ll4
-rw-r--r--test/tools/llvm-cov/Inputs/test.gcdabin824 -> 824 bytes
-rw-r--r--test/tools/llvm-cov/Inputs/test.gcnobin3112 -> 3112 bytes
-rw-r--r--test/tools/llvm-cov/Inputs/test_checksum_mismatch.gcdabin0 -> 825 bytes
-rw-r--r--test/tools/llvm-cov/Inputs/test_read_fail.gcnobin111 -> 72 bytes
-rw-r--r--test/tools/llvm-cov/llvm-cov.test2
9 files changed, 101 insertions, 49 deletions
diff --git a/include/llvm/Support/GCOV.h b/include/llvm/Support/GCOV.h
index 0fbe86c3c5..7ba4acb1ae 100644
--- a/include/llvm/Support/GCOV.h
+++ b/include/llvm/Support/GCOV.h
@@ -45,15 +45,15 @@ public:
/// readGCOVFormat - Read GCOV signature at the beginning of buffer.
GCOV::GCOVFormat readGCOVFormat() {
- StringRef Magic = Buffer->getBuffer().slice(0, 12);
- Cursor = 12;
- if (Magic == "oncg*404MVLL")
+ StringRef Magic = Buffer->getBuffer().slice(0, 8);
+ Cursor = 8;
+ if (Magic == "oncg*404")
return GCOV::GCNO_404;
- else if (Magic == "oncg*204MVLL")
+ else if (Magic == "oncg*204")
return GCOV::GCNO_402;
- else if (Magic == "adcg*404MVLL")
+ else if (Magic == "adcg*404")
return GCOV::GCDA_404;
- else if (Magic == "adcg*204MVLL")
+ else if (Magic == "adcg*204")
return GCOV::GCDA_402;
Cursor = 0;
@@ -193,12 +193,13 @@ private:
/// (.gcno and .gcda).
class GCOVFile {
public:
- GCOVFile() : Functions(), RunCount(0), ProgramCount(0) {}
+ GCOVFile() : Checksum(0), Functions(), RunCount(0), ProgramCount(0) {}
~GCOVFile();
bool read(GCOVBuffer &Buffer);
void dump() const;
void collectLineCounts(FileInfo &FI);
private:
+ uint32_t Checksum;
SmallVector<GCOVFunction *, 16> Functions;
uint32_t RunCount;
uint32_t ProgramCount;
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 =
diff --git a/test/Transforms/GCOVProfiling/version.ll b/test/Transforms/GCOVProfiling/version.ll
index 15bcb052ac..409954c0d9 100644
--- a/test/Transforms/GCOVProfiling/version.ll
+++ b/test/Transforms/GCOVProfiling/version.ll
@@ -1,11 +1,11 @@
; RUN: echo '!9 = metadata !{metadata !"%T/version.ll", metadata !0}' > %t1
; RUN: cat %s %t1 > %t2
; RUN: opt -insert-gcov-profiling -disable-output < %t2
-; RUN: head -c12 %T/version.gcno | grep '^oncg\*204MVLL$'
+; RUN: head -c8 %T/version.gcno | grep '^oncg\*204'
; RUN: rm %T/version.gcno
; RUN: not opt -insert-gcov-profiling -default-gcov-version=asdfasdf -disable-output < %t2
; RUN: opt -insert-gcov-profiling -default-gcov-version=407* -disable-output < %t2
-; RUN: head -c12 %T/version.gcno | grep '^oncg\*704MVLL$'
+; RUN: head -c8 %T/version.gcno | grep '^oncg\*704'
; RUN: rm %T/version.gcno
define void @test() {
diff --git a/test/tools/llvm-cov/Inputs/test.gcda b/test/tools/llvm-cov/Inputs/test.gcda
index 23d03bdd1f..a62c069c9a 100644
--- a/test/tools/llvm-cov/Inputs/test.gcda
+++ b/test/tools/llvm-cov/Inputs/test.gcda
Binary files differ
diff --git a/test/tools/llvm-cov/Inputs/test.gcno b/test/tools/llvm-cov/Inputs/test.gcno
index 6162604e74..218398548e 100644
--- a/test/tools/llvm-cov/Inputs/test.gcno
+++ b/test/tools/llvm-cov/Inputs/test.gcno
Binary files differ
diff --git a/test/tools/llvm-cov/Inputs/test_checksum_mismatch.gcda b/test/tools/llvm-cov/Inputs/test_checksum_mismatch.gcda
new file mode 100644
index 0000000000..2fcf33dd21
--- /dev/null
+++ b/test/tools/llvm-cov/Inputs/test_checksum_mismatch.gcda
Binary files differ
diff --git a/test/tools/llvm-cov/Inputs/test_read_fail.gcno b/test/tools/llvm-cov/Inputs/test_read_fail.gcno
index 63b5d71e69..bcc20a65ee 100644
--- a/test/tools/llvm-cov/Inputs/test_read_fail.gcno
+++ b/test/tools/llvm-cov/Inputs/test_read_fail.gcno
Binary files differ
diff --git a/test/tools/llvm-cov/llvm-cov.test b/test/tools/llvm-cov/llvm-cov.test
index 28738a78d1..d95af9b40f 100644
--- a/test/tools/llvm-cov/llvm-cov.test
+++ b/test/tools/llvm-cov/llvm-cov.test
@@ -7,4 +7,6 @@ RUN: | diff -aub test.cpp.gcov -
RUN: not llvm-cov -gcno=test_read_fail.gcno -gcda=test.gcda
+RUN: not llvm-cov -gcno=test.gcno -gcda=test_checksum_mismatch.gcda
+
XFAIL: powerpc64, s390x