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/MC/MCAsmInfo.h" 16#include "llvm/MC/MCContext.h" 17#include "llvm/MC/MCDisassembler.h" 18#include "llvm/MC/MCInst.h" 19#include "llvm/MC/MCInstPrinter.h" 20#include "llvm/MC/MCInstrAnalysis.h" 21#include "llvm/MC/MCInstrInfo.h" 22#include "llvm/MC/MCObjectFileInfo.h" 23#include "llvm/MC/MCRegisterInfo.h" 24#include "llvm/MC/MCSubtargetInfo.h" 25#include "llvm/Object/Archive.h" 26#include "llvm/Object/Binary.h" 27#include "llvm/Object/ObjectFile.h" 28#include "llvm/Support/CommandLine.h" 29#include "llvm/Support/Errc.h" 30#include "llvm/Support/ErrorOr.h" 31#include "llvm/Support/FileSystem.h" 32#include "llvm/Support/LineIterator.h" 33#include "llvm/Support/ManagedStatic.h" 34#include "llvm/Support/MemoryBuffer.h" 35#include "llvm/Support/Path.h" 36#include "llvm/Support/PrettyStackTrace.h" 37#include "llvm/Support/Signals.h" 38#include "llvm/Support/SpecialCaseList.h" 39#include "llvm/Support/TargetRegistry.h" 40#include "llvm/Support/TargetSelect.h" 41#include "llvm/Support/ToolOutputFile.h" 42#include "llvm/Support/raw_ostream.h" 43 44#include <set> 45#include <stdio.h> 46#include <string> 47#include <vector> 48 49using namespace llvm; 50 51namespace { 52 53// --------- COMMAND LINE FLAGS --------- 54 55enum ActionType { 56 PrintAction, 57 CoveredFunctionsAction, 58 NotCoveredFunctionsAction 59}; 60 61cl::opt<ActionType> Action( 62 cl::desc("Action (required)"), cl::Required, 63 cl::values(clEnumValN(PrintAction, "print", "Print coverage addresses"), 64 clEnumValN(CoveredFunctionsAction, "covered-functions", 65 "Print all covered funcions."), 66 clEnumValN(NotCoveredFunctionsAction, "not-covered-functions", 67 "Print all not covered funcions."), 68 clEnumValEnd)); 69 70static cl::list<std::string> ClInputFiles(cl::Positional, cl::OneOrMore, 71 cl::desc("<filenames...>")); 72 73static cl::opt<std::string> 74 ClBinaryName("obj", cl::Required, 75 cl::desc("Path to object file to be symbolized")); 76 77static cl::opt<bool> 78 ClDemangle("demangle", cl::init(true), 79 cl::desc("Print demangled function name.")); 80 81static cl::opt<std::string> ClStripPathPrefix( 82 "strip_path_prefix", cl::init(""), 83 cl::desc("Strip this prefix from file paths in reports.")); 84 85static cl::opt<std::string> 86 ClBlacklist("blacklist", cl::init(""), 87 cl::desc("Blacklist file (sanitizer blacklist format).")); 88 89static cl::opt<bool> ClUseDefaultBlacklist( 90 "use_default_blacklist", cl::init(true), cl::Hidden, 91 cl::desc("Controls if default blacklist should be used.")); 92 93static const char *const DefaultBlacklist = "fun:__sanitizer_*"; 94 95// --------- FORMAT SPECIFICATION --------- 96 97struct FileHeader { 98 uint32_t Bitness; 99 uint32_t Magic; 100}; 101 102static const uint32_t BinCoverageMagic = 0xC0BFFFFF; 103static const uint32_t Bitness32 = 0xFFFFFF32; 104static const uint32_t Bitness64 = 0xFFFFFF64; 105 106// --------- 107 108static void FailIfError(std::error_code Error) { 109 if (!Error) 110 return; 111 errs() << "Error: " << Error.message() << "(" << Error.value() << ")\n"; 112 exit(1); 113} 114 115template <typename T> static void FailIfError(const ErrorOr<T> &E) { 116 FailIfError(E.getError()); 117} 118 119static void FailIfNotEmpty(const std::string &E) { 120 if (E.empty()) 121 return; 122 errs() << "Error: " << E << "\n"; 123 exit(1); 124} 125 126template <typename T> 127static void FailIfEmpty(const std::unique_ptr<T> &Ptr, 128 const std::string &Message) { 129 if (Ptr.get()) 130 return; 131 errs() << "Error: " << Message << "\n"; 132 exit(1); 133} 134 135template <typename T> 136static void readInts(const char *Start, const char *End, 137 std::set<uint64_t> *Ints) { 138 const T *S = reinterpret_cast<const T *>(Start); 139 const T *E = reinterpret_cast<const T *>(End); 140 std::copy(S, E, std::inserter(*Ints, Ints->end())); 141} 142 143struct FileLoc { 144 bool operator<(const FileLoc &RHS) const { 145 return std::tie(FileName, Line) < std::tie(RHS.FileName, RHS.Line); 146 } 147 148 std::string FileName; 149 uint32_t Line; 150}; 151 152struct FunctionLoc { 153 bool operator<(const FunctionLoc &RHS) const { 154 return std::tie(Loc, FunctionName) < std::tie(RHS.Loc, RHS.FunctionName); 155 } 156 157 FileLoc Loc; 158 std::string FunctionName; 159}; 160 161std::string stripPathPrefix(std::string Path) { 162 if (ClStripPathPrefix.empty()) 163 return Path; 164 size_t Pos = Path.find(ClStripPathPrefix); 165 if (Pos == std::string::npos) 166 return Path; 167 return Path.substr(Pos + ClStripPathPrefix.size()); 168} 169 170// Compute [FileLoc -> FunctionName] map for given addresses. 171static std::map<FileLoc, std::string> 172computeFunctionsMap(const std::set<uint64_t> &Addrs) { 173 std::map<FileLoc, std::string> Fns; 174 175 symbolize::LLVMSymbolizer::Options SymbolizerOptions; 176 SymbolizerOptions.Demangle = ClDemangle; 177 SymbolizerOptions.UseSymbolTable = true; 178 symbolize::LLVMSymbolizer Symbolizer(SymbolizerOptions); 179 180 // Fill in Fns map. 181 for (auto Addr : Addrs) { 182 auto InliningInfo = Symbolizer.symbolizeInlinedCode(ClBinaryName, Addr); 183 FailIfError(InliningInfo); 184 for (uint32_t I = 0; I < InliningInfo->getNumberOfFrames(); ++I) { 185 auto FrameInfo = InliningInfo->getFrame(I); 186 SmallString<256> FileName(FrameInfo.FileName); 187 sys::path::remove_dots(FileName, /* remove_dot_dot */ true); 188 FileLoc Loc = {FileName.str(), FrameInfo.Line}; 189 Fns[Loc] = FrameInfo.FunctionName; 190 } 191 } 192 193 return Fns; 194} 195 196// Compute functions for given addresses. It keeps only the first 197// occurence of a function within a file. 198std::set<FunctionLoc> computeFunctionLocs(const std::set<uint64_t> &Addrs) { 199 std::map<FileLoc, std::string> Fns = computeFunctionsMap(Addrs); 200 201 std::set<FunctionLoc> Result; 202 std::string LastFileName; 203 std::set<std::string> ProcessedFunctions; 204 205 for (const auto &P : Fns) { 206 std::string FileName = P.first.FileName; 207 std::string FunctionName = P.second; 208 209 if (LastFileName != FileName) 210 ProcessedFunctions.clear(); 211 LastFileName = FileName; 212 213 if (!ProcessedFunctions.insert(FunctionName).second) 214 continue; 215 216 Result.insert(FunctionLoc{P.first, P.second}); 217 } 218 219 return Result; 220} 221 222// Locate __sanitizer_cov* function addresses that are used for coverage 223// reporting. 224static std::set<uint64_t> 225findSanitizerCovFunctions(const object::ObjectFile &O) { 226 std::set<uint64_t> Result; 227 228 for (const object::SymbolRef &Symbol : O.symbols()) { 229 ErrorOr<uint64_t> AddressOrErr = Symbol.getAddress(); 230 FailIfError(AddressOrErr); 231 232 ErrorOr<StringRef> NameOrErr = Symbol.getName(); 233 FailIfError(NameOrErr); 234 StringRef Name = NameOrErr.get(); 235 236 if (Name == "__sanitizer_cov" || Name == "__sanitizer_cov_with_check" || 237 Name == "__sanitizer_cov_trace_func_enter") { 238 Result.insert(AddressOrErr.get()); 239 } 240 } 241 242 if (Result.empty()) 243 FailIfNotEmpty("__sanitizer_cov* functions not found"); 244 245 return Result; 246} 247 248// Locate addresses of all coverage points in a file. Coverage point 249// is defined as the 'address of instruction following __sanitizer_cov 250// call - 1'. 251static void getObjectCoveragePoints(const object::ObjectFile &O, 252 std::set<uint64_t> *Addrs) { 253 Triple TheTriple("unknown-unknown-unknown"); 254 TheTriple.setArch(Triple::ArchType(O.getArch())); 255 auto TripleName = TheTriple.getTriple(); 256 257 std::string Error; 258 const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error); 259 FailIfNotEmpty(Error); 260 261 std::unique_ptr<const MCSubtargetInfo> STI( 262 TheTarget->createMCSubtargetInfo(TripleName, "", "")); 263 FailIfEmpty(STI, "no subtarget info for target " + TripleName); 264 265 std::unique_ptr<const MCRegisterInfo> MRI( 266 TheTarget->createMCRegInfo(TripleName)); 267 FailIfEmpty(MRI, "no register info for target " + TripleName); 268 269 std::unique_ptr<const MCAsmInfo> AsmInfo( 270 TheTarget->createMCAsmInfo(*MRI, TripleName)); 271 FailIfEmpty(AsmInfo, "no asm info for target " + TripleName); 272 273 std::unique_ptr<const MCObjectFileInfo> MOFI(new MCObjectFileInfo); 274 MCContext Ctx(AsmInfo.get(), MRI.get(), MOFI.get()); 275 std::unique_ptr<MCDisassembler> DisAsm( 276 TheTarget->createMCDisassembler(*STI, Ctx)); 277 FailIfEmpty(DisAsm, "no disassembler info for target " + TripleName); 278 279 std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo()); 280 FailIfEmpty(MII, "no instruction info for target " + TripleName); 281 282 std::unique_ptr<const MCInstrAnalysis> MIA( 283 TheTarget->createMCInstrAnalysis(MII.get())); 284 FailIfEmpty(MIA, "no instruction analysis info for target " + TripleName); 285 286 auto SanCovAddrs = findSanitizerCovFunctions(O); 287 288 for (const auto Section : O.sections()) { 289 if (Section.isVirtual() || !Section.isText()) // llvm-objdump does the same. 290 continue; 291 uint64_t SectionAddr = Section.getAddress(); 292 uint64_t SectSize = Section.getSize(); 293 if (!SectSize) 294 continue; 295 296 StringRef SectionName; 297 FailIfError(Section.getName(SectionName)); 298 299 StringRef BytesStr; 300 FailIfError(Section.getContents(BytesStr)); 301 ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()), 302 BytesStr.size()); 303 304 for (uint64_t Index = 0, Size = 0; Index < Section.getSize(); 305 Index += Size) { 306 MCInst Inst; 307 if (!DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), 308 SectionAddr + Index, nulls(), nulls())) { 309 if (Size == 0) 310 Size = 1; 311 continue; 312 } 313 uint64_t Target; 314 if (MIA->isCall(Inst) && 315 MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target)) { 316 if (SanCovAddrs.find(Target) != SanCovAddrs.end()) { 317 // Sanitizer coverage uses the address of the next instruction - 1. 318 Addrs->insert(Index + SectionAddr + Size - 1); 319 } 320 } 321 } 322 } 323} 324 325static void getArchiveCoveragePoints(const object::Archive &A, 326 std::set<uint64_t> *Addrs) { 327 for (auto &ErrorOrChild : A.children()) { 328 FailIfError(ErrorOrChild); 329 const object::Archive::Child &C = *ErrorOrChild; 330 ErrorOr<std::unique_ptr<object::Binary>> ChildOrErr = C.getAsBinary(); 331 FailIfError(ChildOrErr); 332 if (object::ObjectFile *O = 333 dyn_cast<object::ObjectFile>(&*ChildOrErr.get())) 334 getObjectCoveragePoints(*O, Addrs); 335 else 336 FailIfError(object::object_error::invalid_file_type); 337 } 338} 339 340// Locate addresses of all coverage points in a file. Coverage point 341// is defined as the 'address of instruction following __sanitizer_cov 342// call - 1'. 343std::set<uint64_t> getCoveragePoints(std::string FileName) { 344 std::set<uint64_t> Result; 345 346 ErrorOr<object::OwningBinary<object::Binary>> BinaryOrErr = 347 object::createBinary(FileName); 348 FailIfError(BinaryOrErr); 349 350 object::Binary &Binary = *BinaryOrErr.get().getBinary(); 351 if (object::Archive *A = dyn_cast<object::Archive>(&Binary)) 352 getArchiveCoveragePoints(*A, &Result); 353 else if (object::ObjectFile *O = dyn_cast<object::ObjectFile>(&Binary)) 354 getObjectCoveragePoints(*O, &Result); 355 else 356 FailIfError(object::object_error::invalid_file_type); 357 358 return Result; 359} 360 361static std::unique_ptr<SpecialCaseList> createDefaultBlacklist() { 362 if (!ClUseDefaultBlacklist) 363 return std::unique_ptr<SpecialCaseList>(); 364 std::unique_ptr<MemoryBuffer> MB = 365 MemoryBuffer::getMemBuffer(DefaultBlacklist); 366 std::string Error; 367 auto Blacklist = SpecialCaseList::create(MB.get(), Error); 368 FailIfNotEmpty(Error); 369 return Blacklist; 370} 371 372static std::unique_ptr<SpecialCaseList> createUserBlacklist() { 373 if (ClBlacklist.empty()) 374 return std::unique_ptr<SpecialCaseList>(); 375 376 return SpecialCaseList::createOrDie({{ClBlacklist}}); 377} 378 379static void printFunctionLocs(const std::set<FunctionLoc> &FnLocs, 380 raw_ostream &OS) { 381 std::unique_ptr<SpecialCaseList> DefaultBlacklist = createDefaultBlacklist(); 382 std::unique_ptr<SpecialCaseList> UserBlacklist = createUserBlacklist(); 383 384 for (const FunctionLoc &FnLoc : FnLocs) { 385 if (DefaultBlacklist && 386 DefaultBlacklist->inSection("fun", FnLoc.FunctionName)) 387 continue; 388 if (DefaultBlacklist && 389 DefaultBlacklist->inSection("src", FnLoc.Loc.FileName)) 390 continue; 391 if (UserBlacklist && UserBlacklist->inSection("fun", FnLoc.FunctionName)) 392 continue; 393 if (UserBlacklist && UserBlacklist->inSection("src", FnLoc.Loc.FileName)) 394 continue; 395 396 OS << stripPathPrefix(FnLoc.Loc.FileName) << ":" << FnLoc.Loc.Line << " " 397 << FnLoc.FunctionName << "\n"; 398 } 399} 400 401class CoverageData { 402 public: 403 // Read single file coverage data. 404 static ErrorOr<std::unique_ptr<CoverageData>> read(std::string FileName) { 405 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = 406 MemoryBuffer::getFile(FileName); 407 if (!BufOrErr) 408 return BufOrErr.getError(); 409 std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get()); 410 if (Buf->getBufferSize() < 8) { 411 errs() << "File too small (<8): " << Buf->getBufferSize(); 412 return make_error_code(errc::illegal_byte_sequence); 413 } 414 const FileHeader *Header = 415 reinterpret_cast<const FileHeader *>(Buf->getBufferStart()); 416 417 if (Header->Magic != BinCoverageMagic) { 418 errs() << "Wrong magic: " << Header->Magic; 419 return make_error_code(errc::illegal_byte_sequence); 420 } 421 422 auto Addrs = llvm::make_unique<std::set<uint64_t>>(); 423 424 switch (Header->Bitness) { 425 case Bitness64: 426 readInts<uint64_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(), 427 Addrs.get()); 428 break; 429 case Bitness32: 430 readInts<uint32_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(), 431 Addrs.get()); 432 break; 433 default: 434 errs() << "Unsupported bitness: " << Header->Bitness; 435 return make_error_code(errc::illegal_byte_sequence); 436 } 437 438 return std::unique_ptr<CoverageData>(new CoverageData(std::move(Addrs))); 439 } 440 441 // Merge multiple coverage data together. 442 static std::unique_ptr<CoverageData> 443 merge(const std::vector<std::unique_ptr<CoverageData>> &Covs) { 444 auto Addrs = llvm::make_unique<std::set<uint64_t>>(); 445 446 for (const auto &Cov : Covs) 447 Addrs->insert(Cov->Addrs->begin(), Cov->Addrs->end()); 448 449 return std::unique_ptr<CoverageData>(new CoverageData(std::move(Addrs))); 450 } 451 452 // Read list of files and merges their coverage info. 453 static ErrorOr<std::unique_ptr<CoverageData>> 454 readAndMerge(const std::vector<std::string> &FileNames) { 455 std::vector<std::unique_ptr<CoverageData>> Covs; 456 for (const auto &FileName : FileNames) { 457 auto Cov = read(FileName); 458 if (!Cov) 459 return Cov.getError(); 460 Covs.push_back(std::move(Cov.get())); 461 } 462 return merge(Covs); 463 } 464 465 // Print coverage addresses. 466 void printAddrs(raw_ostream &OS) { 467 for (auto Addr : *Addrs) { 468 OS << "0x"; 469 OS.write_hex(Addr); 470 OS << "\n"; 471 } 472 } 473 474 // Print list of covered functions. 475 // Line format: <file_name>:<line> <function_name> 476 void printCoveredFunctions(raw_ostream &OS) { 477 printFunctionLocs(computeFunctionLocs(*Addrs), OS); 478 } 479 480 // Print list of not covered functions. 481 // Line format: <file_name>:<line> <function_name> 482 void printNotCoveredFunctions(raw_ostream &OS) { 483 std::set<FunctionLoc> AllFns = 484 computeFunctionLocs(getCoveragePoints(ClBinaryName)); 485 std::set<FunctionLoc> CoveredFns = computeFunctionLocs(*Addrs); 486 487 std::set<FunctionLoc> NotCoveredFns; 488 std::set_difference(AllFns.begin(), AllFns.end(), CoveredFns.begin(), 489 CoveredFns.end(), 490 std::inserter(NotCoveredFns, NotCoveredFns.end())); 491 printFunctionLocs(NotCoveredFns, OS); 492 } 493 494private: 495 explicit CoverageData(std::unique_ptr<std::set<uint64_t>> Addrs) 496 : Addrs(std::move(Addrs)) {} 497 498 std::unique_ptr<std::set<uint64_t>> Addrs; 499}; 500} // namespace 501 502int main(int argc, char **argv) { 503 // Print stack trace if we signal out. 504 sys::PrintStackTraceOnErrorSignal(); 505 PrettyStackTraceProgram X(argc, argv); 506 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 507 508 llvm::InitializeAllTargetInfos(); 509 llvm::InitializeAllTargetMCs(); 510 llvm::InitializeAllDisassemblers(); 511 512 cl::ParseCommandLineOptions(argc, argv, "Sanitizer Coverage Processing Tool"); 513 514 auto CovData = CoverageData::readAndMerge(ClInputFiles); 515 FailIfError(CovData); 516 517 switch (Action) { 518 case PrintAction: { 519 CovData.get()->printAddrs(outs()); 520 return 0; 521 } 522 case CoveredFunctionsAction: { 523 CovData.get()->printCoveredFunctions(outs()); 524 return 0; 525 } 526 case NotCoveredFunctionsAction: { 527 CovData.get()->printNotCoveredFunctions(outs()); 528 return 0; 529 } 530 } 531 532 llvm_unreachable("unsupported action"); 533} 534