7a3d7f171c593f14065084b95fb9ba91ef285e56
[oota-llvm.git] / tools / sancov / sancov.cc
1 //===-- sancov.cc --------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file is a command-line tool for reading and analyzing sanitizer
11 // coverage.
12 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
15 #include "llvm/Support/CommandLine.h"
16 #include "llvm/Support/Errc.h"
17 #include "llvm/Support/ErrorOr.h"
18 #include "llvm/Support/FileSystem.h"
19 #include "llvm/Support/LineIterator.h"
20 #include "llvm/Support/ManagedStatic.h"
21 #include "llvm/Support/MemoryBuffer.h"
22 #include "llvm/Support/Path.h"
23 #include "llvm/Support/PrettyStackTrace.h"
24 #include "llvm/Support/Signals.h"
25 #include "llvm/Support/ToolOutputFile.h"
26 #include "llvm/Support/raw_ostream.h"
27
28 #include <set>
29 #include <stdio.h>
30 #include <vector>
31
32 using namespace llvm;
33
34 namespace {
35
36 // --------- COMMAND LINE FLAGS ---------
37
38 enum ActionType { PrintAction, CoveredFunctionsAction };
39
40 cl::opt<ActionType> Action(
41     cl::desc("Action (required)"), cl::Required,
42     cl::values(clEnumValN(PrintAction, "print", "Print coverage addresses"),
43                clEnumValN(CoveredFunctionsAction, "covered_functions",
44                           "Print all covered funcions."),
45                clEnumValEnd));
46
47 static cl::list<std::string> ClInputFiles(cl::Positional, cl::OneOrMore,
48                                           cl::desc("<filenames...>"));
49
50 static cl::opt<std::string>
51     ClBinaryName("obj", cl::Required,
52                  cl::desc("Path to object file to be symbolized"));
53
54 static cl::opt<bool>
55     ClDemangle("demangle", cl::init(true),
56         cl::desc("Print demangled function name."));
57
58 // --------- FORMAT SPECIFICATION ---------
59
60 struct FileHeader {
61   uint32_t Bitness;
62   uint32_t Magic;
63 };
64
65 static const uint32_t BinCoverageMagic = 0xC0BFFFFF;
66 static const uint32_t Bitness32 = 0xFFFFFF32;
67 static const uint32_t Bitness64 = 0xFFFFFF64;
68
69 // ---------
70
71 template <typename T> static void FailIfError(const ErrorOr<T> &E) {
72   if (E)
73     return;
74
75   auto Error = E.getError();
76   errs() << "Error: " << Error.message() << "(" << Error.value() << ")\n";
77   exit(-2);
78 }
79
80 template <typename T>
81 static void readInts(const char *Start, const char *End,
82                      std::vector<uint64_t> *V) {
83   const T *S = reinterpret_cast<const T *>(Start);
84   const T *E = reinterpret_cast<const T *>(End);
85   V->reserve(E - S);
86   std::copy(S, E, std::back_inserter(*V));
87 }
88
89 static std::string CommonPrefix(std::string A, std::string B) {
90   if (A.size() > B.size())
91     return std::string(B.begin(),
92                        std::mismatch(B.begin(), B.end(), A.begin()).first);
93   else
94     return std::string(A.begin(),
95                        std::mismatch(A.begin(), A.end(), B.begin()).first);
96 }
97
98 class CoverageData {
99  public:
100   // Read single file coverage data.
101   static ErrorOr<std::unique_ptr<CoverageData>> read(std::string FileName) {
102     ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
103         MemoryBuffer::getFile(FileName);
104     if (!BufOrErr)
105       return BufOrErr.getError();
106     std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
107     if (Buf->getBufferSize() < 8) {
108       errs() << "File too small (<8): " << Buf->getBufferSize();
109       return make_error_code(errc::illegal_byte_sequence);
110     }
111     const FileHeader *Header =
112         reinterpret_cast<const FileHeader *>(Buf->getBufferStart());
113
114     if (Header->Magic != BinCoverageMagic) {
115       errs() << "Wrong magic: " << Header->Magic;
116       return make_error_code(errc::illegal_byte_sequence);
117     }
118
119     auto Addrs = llvm::make_unique<std::vector<uint64_t>>();
120
121     switch (Header->Bitness) {
122     case Bitness64:
123       readInts<uint64_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),
124                          Addrs.get());
125       break;
126     case Bitness32:
127       readInts<uint32_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),
128                          Addrs.get());
129       break;
130     default:
131       errs() << "Unsupported bitness: " << Header->Bitness;
132       return make_error_code(errc::illegal_byte_sequence);
133     }
134
135     return std::unique_ptr<CoverageData>(new CoverageData(std::move(Addrs)));
136   }
137
138   // Merge multiple coverage data together.
139   static std::unique_ptr<CoverageData>
140   merge(const std::vector<std::unique_ptr<CoverageData>> &Covs) {
141     std::set<uint64_t> Addrs;
142
143     for (const auto &Cov : Covs)
144       Addrs.insert(Cov->Addrs->begin(), Cov->Addrs->end());
145
146     auto AddrsVector = llvm::make_unique<std::vector<uint64_t>>(
147         Addrs.begin(), Addrs.end());
148     return std::unique_ptr<CoverageData>(
149         new CoverageData(std::move(AddrsVector)));
150   }
151
152   // Read list of files and merges their coverage info.
153   static ErrorOr<std::unique_ptr<CoverageData>>
154   readAndMerge(const std::vector<std::string> &FileNames) {
155     std::vector<std::unique_ptr<CoverageData>> Covs;
156     for (const auto &FileName : FileNames) {
157       auto Cov = read(FileName);
158       if (!Cov)
159         return Cov.getError();
160       Covs.push_back(std::move(Cov.get()));
161     }
162     return merge(Covs);
163   }
164
165   // Print coverage addresses.
166   void printAddrs(raw_ostream &out) {
167     for (auto Addr : *Addrs) {
168       out << "0x";
169       out.write_hex(Addr);
170       out << "\n";
171     }
172   }
173
174   // Print list of covered functions.
175   // Line format: <file_name>:<line> <function_name>
176   void printCoveredFunctions(raw_ostream &out) {
177     if (Addrs->empty())
178       return;
179     symbolize::LLVMSymbolizer::Options SymbolizerOptions;
180     SymbolizerOptions.Demangle = ClDemangle;
181     symbolize::LLVMSymbolizer Symbolizer;
182
183     struct FileLoc {
184       std::string FileName;
185       uint32_t Line;
186       bool operator<(const FileLoc &Rhs) const {
187         return std::tie(FileName, Line) < std::tie(Rhs.FileName, Rhs.Line);
188       }
189     };
190
191     // FileLoc -> FunctionName
192     std::map<FileLoc, std::string> Fns;
193
194     // Fill in Fns map.
195     for (auto Addr : *Addrs) {
196       auto InliningInfo = Symbolizer.symbolizeInlinedCode(ClBinaryName, Addr);
197       FailIfError(InliningInfo);
198       for (uint32_t i = 0; i < InliningInfo->getNumberOfFrames(); ++i) {
199         auto FrameInfo = InliningInfo->getFrame(i);
200         SmallString<256> FileName(FrameInfo.FileName);
201         sys::path::remove_dots(FileName, /* remove_dot_dot */ true);
202         FileLoc Loc = { FileName.str(), FrameInfo.Line };
203         Fns[Loc] = FrameInfo.FunctionName;
204       }
205     }
206
207     // Compute file names common prefix.
208     std::string FilePrefix = Fns.begin()->first.FileName;
209     for (const auto &P : Fns)
210       FilePrefix = CommonPrefix(FilePrefix, P.first.FileName);
211
212     // Print first function occurence in a file.
213     {
214       std::string LastFileName;
215       std::set<std::string> ProcessedFunctions;
216
217       for (const auto &P : Fns) {
218         std::string FileName = P.first.FileName;
219         std::string FunctionName = P.second;
220         uint32_t Line = P.first.Line;
221
222         if (LastFileName != FileName)
223           ProcessedFunctions.clear();
224         LastFileName = FileName;
225
226         if (!ProcessedFunctions.insert(FunctionName).second)
227           continue;
228
229         out << FileName.substr(FilePrefix.size()) << ":" << Line << " "
230             << FunctionName << "\n";
231       }
232     }
233   }
234
235  private:
236   explicit CoverageData(std::unique_ptr<std::vector<uint64_t>> Addrs)
237       : Addrs(std::move(Addrs)) {}
238
239   std::unique_ptr<std::vector<uint64_t>> Addrs;
240 };
241 } // namespace
242
243 int main(int argc, char **argv) {
244   // Print stack trace if we signal out.
245   sys::PrintStackTraceOnErrorSignal();
246   PrettyStackTraceProgram X(argc, argv);
247   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
248
249   cl::ParseCommandLineOptions(argc, argv, "Sanitizer Coverage Processing Tool");
250
251   auto CovData = CoverageData::readAndMerge(ClInputFiles);
252   FailIfError(CovData);
253
254   switch (Action) {
255   case PrintAction: {
256     CovData.get()->printAddrs(outs());
257     return 0;
258   }
259   case CoveredFunctionsAction: {
260     CovData.get()->printCoveredFunctions(outs());
261     return 0;
262   }
263   }
264 }