1 //===-- sancov.cc --------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is a command-line tool for reading and analyzing sanitizer
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"
36 // --------- COMMAND LINE FLAGS ---------
38 enum ActionType { PrintAction, CoveredFunctionsAction };
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."),
47 static cl::list<std::string> ClInputFiles(cl::Positional, cl::OneOrMore,
48 cl::desc("<filenames...>"));
50 static cl::opt<std::string>
51 ClBinaryName("obj", cl::Required,
52 cl::desc("Path to object file to be symbolized"));
55 ClDemangle("demangle", cl::init(true),
56 cl::desc("Print demangled function name."));
58 // --------- FORMAT SPECIFICATION ---------
65 static const uint32_t BinCoverageMagic = 0xC0BFFFFF;
66 static const uint32_t Bitness32 = 0xFFFFFF32;
67 static const uint32_t Bitness64 = 0xFFFFFF64;
71 template <typename T> static void FailIfError(const ErrorOr<T> &E) {
75 auto Error = E.getError();
76 errs() << "Error: " << Error.message() << "(" << Error.value() << ")\n";
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);
86 std::copy(S, E, std::back_inserter(*V));
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);
94 return std::string(A.begin(),
95 std::mismatch(A.begin(), A.end(), B.begin()).first);
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);
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);
111 const FileHeader *Header =
112 reinterpret_cast<const FileHeader *>(Buf->getBufferStart());
114 if (Header->Magic != BinCoverageMagic) {
115 errs() << "Wrong magic: " << Header->Magic;
116 return make_error_code(errc::illegal_byte_sequence);
119 auto Addrs = llvm::make_unique<std::vector<uint64_t>>();
121 switch (Header->Bitness) {
123 readInts<uint64_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),
127 readInts<uint32_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),
131 errs() << "Unsupported bitness: " << Header->Bitness;
132 return make_error_code(errc::illegal_byte_sequence);
135 return std::unique_ptr<CoverageData>(new CoverageData(std::move(Addrs)));
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;
143 for (const auto &Cov : Covs)
144 Addrs.insert(Cov->Addrs->begin(), Cov->Addrs->end());
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)));
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);
159 return Cov.getError();
160 Covs.push_back(std::move(Cov.get()));
165 // Print coverage addresses.
166 void printAddrs(raw_ostream &out) {
167 for (auto Addr : *Addrs) {
174 // Print list of covered functions.
175 // Line format: <file_name>:<line> <function_name>
176 void printCoveredFunctions(raw_ostream &out) {
179 symbolize::LLVMSymbolizer::Options SymbolizerOptions;
180 SymbolizerOptions.Demangle = ClDemangle;
181 symbolize::LLVMSymbolizer Symbolizer(SymbolizerOptions);
184 std::string FileName;
186 bool operator<(const FileLoc &Rhs) const {
187 return std::tie(FileName, Line) < std::tie(Rhs.FileName, Rhs.Line);
191 // FileLoc -> FunctionName
192 std::map<FileLoc, std::string> Fns;
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;
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);
212 // Print first function occurence in a file.
214 std::string LastFileName;
215 std::set<std::string> ProcessedFunctions;
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;
222 if (LastFileName != FileName)
223 ProcessedFunctions.clear();
224 LastFileName = FileName;
226 if (!ProcessedFunctions.insert(FunctionName).second)
229 // Don't strip prefix if we only have a single file.
230 if (FileName.size() > FilePrefix.size())
231 FileName = FileName.substr(FilePrefix.size());
233 out << FileName << ":" << Line << " " << FunctionName << "\n";
239 explicit CoverageData(std::unique_ptr<std::vector<uint64_t>> Addrs)
240 : Addrs(std::move(Addrs)) {}
242 std::unique_ptr<std::vector<uint64_t>> Addrs;
246 int main(int argc, char **argv) {
247 // Print stack trace if we signal out.
248 sys::PrintStackTraceOnErrorSignal();
249 PrettyStackTraceProgram X(argc, argv);
250 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
252 cl::ParseCommandLineOptions(argc, argv, "Sanitizer Coverage Processing Tool");
254 auto CovData = CoverageData::readAndMerge(ClInputFiles);
255 FailIfError(CovData);
259 CovData.get()->printAddrs(outs());
262 case CoveredFunctionsAction: {
263 CovData.get()->printCoveredFunctions(outs());