diff options
Diffstat (limited to 'contrib/llvm/lib/IR/GCOV.cpp')
-rw-r--r-- | contrib/llvm/lib/IR/GCOV.cpp | 297 |
1 files changed, 164 insertions, 133 deletions
diff --git a/contrib/llvm/lib/IR/GCOV.cpp b/contrib/llvm/lib/IR/GCOV.cpp index ea2f0a6..f0f8c7d 100644 --- a/contrib/llvm/lib/IR/GCOV.cpp +++ b/contrib/llvm/lib/IR/GCOV.cpp @@ -7,14 +7,16 @@ // //===----------------------------------------------------------------------===// // -// GCOV implements the interface to read and write coverage files that use +// GCOV implements the interface to read and write coverage files that use // 'gcov' format. // //===----------------------------------------------------------------------===// +#include "llvm/Support/Debug.h" #include "llvm/Support/GCOV.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Format.h" #include "llvm/Support/MemoryObject.h" #include "llvm/Support/system_error.h" using namespace llvm; @@ -43,27 +45,47 @@ bool GCOVFile::read(GCOVBuffer &Buffer) { if (Format == GCOV::InvalidGCOV) return false; - unsigned i = 0; - while (1) { - GCOVFunction *GFun = NULL; - if (isGCDAFile(Format)) { - // Use existing function while reading .gcda file. - assert(i < Functions.size() && ".gcda data does not match .gcno data"); - GFun = Functions[i]; - } else if (isGCNOFile(Format)){ - GFun = new GCOVFunction(); + if (isGCNOFile(Format)) { + while (true) { + if (!Buffer.readFunctionTag()) break; + GCOVFunction *GFun = new GCOVFunction(); + if (!GFun->read(Buffer, Format)) + return false; Functions.push_back(GFun); } - if (!GFun || !GFun->read(Buffer, Format)) - break; - ++i; } + else if (isGCDAFile(Format)) { + for (size_t i = 0, e = Functions.size(); i < e; ++i) { + if (!Buffer.readFunctionTag()) { + errs() << "Unexpected number of functions.\n"; + return false; + } + if (!Functions[i]->read(Buffer, Format)) + return false; + } + if (Buffer.readObjectTag()) { + uint32_t Length; + uint32_t Dummy; + if (!Buffer.readInt(Length)) return false; + if (!Buffer.readInt(Dummy)) return false; // checksum + if (!Buffer.readInt(Dummy)) return false; // num + if (!Buffer.readInt(RunCount)) return false;; + Buffer.advanceCursor(Length-3); + } + while (Buffer.readProgramTag()) { + uint32_t Length; + if (!Buffer.readInt(Length)) return false; + Buffer.advanceCursor(Length); + ++ProgramCount; + } + } + return true; } -/// dump - Dump GCOVFile content on standard out for debugging purposes. +/// dump - Dump GCOVFile content to dbgs() for debugging purposes. void GCOVFile::dump() { - for (SmallVector<GCOVFunction *, 16>::iterator I = Functions.begin(), + for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(), E = Functions.end(); I != E; ++I) (*I)->dump(); } @@ -71,10 +93,11 @@ void GCOVFile::dump() { /// collectLineCounts - Collect line counts. This must be used after /// reading .gcno and .gcda files. void GCOVFile::collectLineCounts(FileInfo &FI) { - for (SmallVector<GCOVFunction *, 16>::iterator I = Functions.begin(), - E = Functions.end(); I != E; ++I) + for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(), + E = Functions.end(); I != E; ++I) (*I)->collectLineCounts(FI); - FI.print(); + FI.setRunCount(RunCount); + FI.setProgramCount(ProgramCount); } //===----------------------------------------------------------------------===// @@ -85,77 +108,122 @@ GCOVFunction::~GCOVFunction() { DeleteContainerPointers(Blocks); } -/// read - Read a aunction from the buffer. Return false if buffer cursor +/// read - Read a function from the buffer. Return false if buffer cursor /// does not point to a function tag. bool GCOVFunction::read(GCOVBuffer &Buff, GCOV::GCOVFormat Format) { - if (!Buff.readFunctionTag()) - return false; + uint32_t Dummy; + if (!Buff.readInt(Dummy)) return false; // Function header length + if (!Buff.readInt(Ident)) return false; + if (!Buff.readInt(Dummy)) return false; // Checksum #1 + if (Format != GCOV::GCNO_402 && Format != GCOV::GCDA_402) + if (!Buff.readInt(Dummy)) return false; // Checksum #2 - Buff.readInt(); // Function header length - Ident = Buff.readInt(); - Buff.readInt(); // Checksum #1 - if (Format != GCOV::GCNO_402) - Buff.readInt(); // Checksum #2 + if (!Buff.readString(Name)) return false; - Name = Buff.readString(); if (Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404) - Filename = Buff.readString(); + if (!Buff.readString(Filename)) return false; if (Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404) { - Buff.readArcTag(); - uint32_t Count = Buff.readInt() / 2; - for (unsigned i = 0, e = Count; i != e; ++i) { - Blocks[i]->addCount(Buff.readInt64()); + if (!Buff.readArcTag()) { + errs() << "Arc tag not found.\n"; + return false; + } + uint32_t Count; + if (!Buff.readInt(Count)) return false; + Count /= 2; + + // This for loop adds the counts for each block. A second nested loop is + // required to combine the edge counts that are contained in the GCDA file. + for (uint32_t Line = 0; Count > 0; ++Line) { + if (Line >= Blocks.size()) { + errs() << "Unexpected number of edges.\n"; + return false; + } + GCOVBlock &Block = *Blocks[Line]; + for (size_t Edge = 0, End = Block.getNumEdges(); Edge < End; ++Edge) { + if (Count == 0) { + errs() << "Unexpected number of edges.\n"; + return false; + } + uint64_t ArcCount; + if (!Buff.readInt64(ArcCount)) return false; + Block.addCount(ArcCount); + --Count; + } } return true; } - LineNumber = Buff.readInt(); + if (!Buff.readInt(LineNumber)) return false; // read blocks. - bool BlockTagFound = Buff.readBlockTag(); - (void)BlockTagFound; - assert(BlockTagFound && "Block Tag not found!"); - uint32_t BlockCount = Buff.readInt(); - for (int i = 0, e = BlockCount; i != e; ++i) { - Buff.readInt(); // Block flags; - Blocks.push_back(new GCOVBlock(i)); + if (!Buff.readBlockTag()) { + errs() << "Block tag not found.\n"; + return false; + } + uint32_t BlockCount; + if (!Buff.readInt(BlockCount)) return false; + for (uint32_t i = 0, e = BlockCount; i != e; ++i) { + if (!Buff.readInt(Dummy)) return false; // Block flags; + Blocks.push_back(new GCOVBlock(*this, i)); } // read edges. while (Buff.readEdgeTag()) { - uint32_t EdgeCount = (Buff.readInt() - 1) / 2; - uint32_t BlockNo = Buff.readInt(); - assert(BlockNo < BlockCount && "Unexpected Block number!"); - for (int i = 0, e = EdgeCount; i != e; ++i) { - Blocks[BlockNo]->addEdge(Buff.readInt()); - Buff.readInt(); // Edge flag + uint32_t EdgeCount; + if (!Buff.readInt(EdgeCount)) return false; + EdgeCount = (EdgeCount - 1) / 2; + uint32_t BlockNo; + if (!Buff.readInt(BlockNo)) return false; + if (BlockNo >= BlockCount) { + errs() << "Unexpected block number.\n"; + return false; + } + for (uint32_t i = 0, e = EdgeCount; i != e; ++i) { + uint32_t Dst; + if (!Buff.readInt(Dst)) return false; + Blocks[BlockNo]->addEdge(Dst); + if (!Buff.readInt(Dummy)) return false; // Edge flag } } // read line table. while (Buff.readLineTag()) { - uint32_t LineTableLength = Buff.readInt(); - uint32_t Size = Buff.getCursor() + LineTableLength*4; - uint32_t BlockNo = Buff.readInt(); - assert(BlockNo < BlockCount && "Unexpected Block number!"); + uint32_t LineTableLength; + if (!Buff.readInt(LineTableLength)) return false; + uint32_t EndPos = Buff.getCursor() + LineTableLength*4; + uint32_t BlockNo; + if (!Buff.readInt(BlockNo)) return false; + if (BlockNo >= BlockCount) { + errs() << "Unexpected block number.\n"; + return false; + } GCOVBlock *Block = Blocks[BlockNo]; - Buff.readInt(); // flag - while (Buff.getCursor() != (Size - 4)) { - StringRef Filename = Buff.readString(); - if (Buff.getCursor() == (Size - 4)) break; - while (uint32_t L = Buff.readInt()) - Block->addLine(Filename, L); + if (!Buff.readInt(Dummy)) return false; // flag + while (Buff.getCursor() != (EndPos - 4)) { + StringRef F; + if (!Buff.readString(F)) return false; + if (F != Filename) { + errs() << "Multiple sources for a single basic block.\n"; + return false; + } + if (Buff.getCursor() == (EndPos - 4)) break; + while (true) { + uint32_t Line; + if (!Buff.readInt(Line)) return false; + if (!Line) break; + Block->addLine(Line); + } } - Buff.readInt(); // flag + if (!Buff.readInt(Dummy)) return false; // flag } return true; } -/// dump - Dump GCOVFunction content on standard out for debugging purposes. +/// dump - Dump GCOVFunction content to dbgs() for debugging purposes. void GCOVFunction::dump() { - outs() << "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n"; - for (SmallVector<GCOVBlock *, 16>::iterator I = Blocks.begin(), + dbgs() << "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n"; + for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(), E = Blocks.end(); I != E; ++I) (*I)->dump(); } @@ -163,7 +231,7 @@ void GCOVFunction::dump() { /// collectLineCounts - Collect line counts. This must be used after /// reading .gcno and .gcda files. void GCOVFunction::collectLineCounts(FileInfo &FI) { - for (SmallVector<GCOVBlock *, 16>::iterator I = Blocks.begin(), + for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(), E = Blocks.end(); I != E; ++I) (*I)->collectLineCounts(FI); } @@ -174,110 +242,73 @@ void GCOVFunction::collectLineCounts(FileInfo &FI) { /// ~GCOVBlock - Delete GCOVBlock and its content. GCOVBlock::~GCOVBlock() { Edges.clear(); - DeleteContainerSeconds(Lines); -} - -void GCOVBlock::addLine(StringRef Filename, uint32_t LineNo) { - GCOVLines *&LinesForFile = Lines[Filename]; - if (!LinesForFile) - LinesForFile = new GCOVLines(); - LinesForFile->add(LineNo); + Lines.clear(); } /// collectLineCounts - Collect line counts. This must be used after /// reading .gcno and .gcda files. void GCOVBlock::collectLineCounts(FileInfo &FI) { - for (StringMap<GCOVLines *>::iterator I = Lines.begin(), + for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(), E = Lines.end(); I != E; ++I) - I->second->collectLineCounts(FI, I->first(), Counter); + FI.addLineCount(Parent.getFilename(), *I, Counter); } -/// dump - Dump GCOVBlock content on standard out for debugging purposes. +/// dump - Dump GCOVBlock content to dbgs() for debugging purposes. void GCOVBlock::dump() { - outs() << "Block : " << Number << " Counter : " << Counter << "\n"; + dbgs() << "Block : " << Number << " Counter : " << Counter << "\n"; if (!Edges.empty()) { - outs() << "\tEdges : "; - for (SmallVector<uint32_t, 16>::iterator I = Edges.begin(), E = Edges.end(); + dbgs() << "\tEdges : "; + for (SmallVectorImpl<uint32_t>::iterator I = Edges.begin(), E = Edges.end(); I != E; ++I) - outs() << (*I) << ","; - outs() << "\n"; + dbgs() << (*I) << ","; + dbgs() << "\n"; } if (!Lines.empty()) { - outs() << "\tLines : "; - for (StringMap<GCOVLines *>::iterator LI = Lines.begin(), - LE = Lines.end(); LI != LE; ++LI) { - outs() << LI->first() << " -> "; - LI->second->dump(); - outs() << "\n"; - } + dbgs() << "\tLines : "; + for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(), + E = Lines.end(); I != E; ++I) + dbgs() << (*I) << ","; + dbgs() << "\n"; } } //===----------------------------------------------------------------------===// -// GCOVLines implementation. - -/// collectLineCounts - Collect line counts. This must be used after -/// reading .gcno and .gcda files. -void GCOVLines::collectLineCounts(FileInfo &FI, StringRef Filename, - uint32_t Count) { - for (SmallVector<uint32_t, 16>::iterator I = Lines.begin(), - E = Lines.end(); I != E; ++I) - FI.addLineCount(Filename, *I, Count); -} - -/// dump - Dump GCOVLines content on standard out for debugging purposes. -void GCOVLines::dump() { - for (SmallVector<uint32_t, 16>::iterator I = Lines.begin(), - E = Lines.end(); I != E; ++I) - outs() << (*I) << ","; -} - -//===----------------------------------------------------------------------===// // FileInfo implementation. -/// addLineCount - Add line count for the given line number in a file. -void FileInfo::addLineCount(StringRef Filename, uint32_t Line, uint32_t Count) { - if (LineInfo.find(Filename) == LineInfo.end()) { - OwningPtr<MemoryBuffer> Buff; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { - errs() << Filename << ": " << ec.message() << "\n"; - return; - } - StringRef AllLines = Buff.take()->getBuffer(); - LineCounts L(AllLines.count('\n')+2); - L[Line-1] = Count; - LineInfo[Filename] = L; - return; - } - LineCounts &L = LineInfo[Filename]; - L[Line-1] = Count; -} - /// print - Print source files with collected line count information. -void FileInfo::print() { +void FileInfo::print(raw_fd_ostream &OS, StringRef gcnoFile, + StringRef gcdaFile) { for (StringMap<LineCounts>::iterator I = LineInfo.begin(), E = LineInfo.end(); I != E; ++I) { StringRef Filename = I->first(); - outs() << Filename << "\n"; + OS << " -: 0:Source:" << Filename << "\n"; + OS << " -: 0:Graph:" << gcnoFile << "\n"; + OS << " -: 0:Data:" << gcdaFile << "\n"; + OS << " -: 0:Runs:" << RunCount << "\n"; + OS << " -: 0:Programs:" << ProgramCount << "\n"; LineCounts &L = LineInfo[Filename]; OwningPtr<MemoryBuffer> Buff; if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { errs() << Filename << ": " << ec.message() << "\n"; return; } - StringRef AllLines = Buff.take()->getBuffer(); - for (unsigned i = 0, e = L.size(); i != e; ++i) { - if (L[i]) - outs() << L[i] << ":\t"; - else - outs() << " :\t"; + StringRef AllLines = Buff->getBuffer(); + uint32_t i = 0; + while (!AllLines.empty()) { + if (L.find(i) != L.end()) { + if (L[i] == 0) + OS << " #####:"; + else + OS << format("%9" PRIu64 ":", L[i]); + } else { + OS << " -:"; + } std::pair<StringRef, StringRef> P = AllLines.split('\n'); if (AllLines != P.first) - outs() << P.first; - outs() << "\n"; + OS << format("%5u:", i+1) << P.first; + OS << "\n"; AllLines = P.second; + ++i; } } } - - |