1 //===- TestingSupport.cpp - Convert objects files into test files --------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Object/COFF.h" 10 #include "llvm/Object/ObjectFile.h" 11 #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" 12 #include "llvm/ProfileData/InstrProf.h" 13 #include "llvm/Support/Alignment.h" 14 #include "llvm/Support/CommandLine.h" 15 #include "llvm/Support/FileSystem.h" 16 #include "llvm/Support/LEB128.h" 17 #include "llvm/Support/MemoryBuffer.h" 18 #include "llvm/Support/raw_ostream.h" 19 #include <functional> 20 #include <system_error> 21 22 using namespace llvm; 23 using namespace object; 24 25 int convertForTestingMain(int argc, const char *argv[]) { 26 cl::opt<std::string> InputSourceFile(cl::Positional, cl::Required, 27 cl::desc("<Source file>")); 28 29 cl::opt<std::string> OutputFilename( 30 "o", cl::Required, 31 cl::desc( 32 "File with the profile data obtained after an instrumented run")); 33 34 cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); 35 36 auto ObjErr = llvm::object::ObjectFile::createObjectFile(InputSourceFile); 37 if (!ObjErr) { 38 std::string Buf; 39 raw_string_ostream OS(Buf); 40 logAllUnhandledErrors(ObjErr.takeError(), OS); 41 OS.flush(); 42 errs() << "error: " << Buf; 43 return 1; 44 } 45 ObjectFile *OF = ObjErr.get().getBinary(); 46 auto BytesInAddress = OF->getBytesInAddress(); 47 if (BytesInAddress != 8) { 48 errs() << "error: 64 bit binary expected\n"; 49 return 1; 50 } 51 52 // Look for the sections that we are interested in. 53 int FoundSectionCount = 0; 54 SectionRef ProfileNames, CoverageMapping, CoverageRecords; 55 auto ObjFormat = OF->getTripleObjectFormat(); 56 57 auto ProfileNamesSection = getInstrProfSectionName(IPSK_name, ObjFormat, 58 /*AddSegmentInfo=*/false); 59 auto CoverageMappingSection = 60 getInstrProfSectionName(IPSK_covmap, ObjFormat, /*AddSegmentInfo=*/false); 61 auto CoverageRecordsSection = 62 getInstrProfSectionName(IPSK_covfun, ObjFormat, /*AddSegmentInfo=*/false); 63 if (isa<object::COFFObjectFile>(OF)) { 64 // On COFF, the object file section name may end in "$M". This tells the 65 // linker to sort these sections between "$A" and "$Z". The linker removes 66 // the dollar and everything after it in the final binary. Do the same to 67 // match. 68 auto Strip = [](std::string &Str) { 69 auto Pos = Str.find('$'); 70 if (Pos != std::string::npos) 71 Str.resize(Pos); 72 }; 73 Strip(ProfileNamesSection); 74 Strip(CoverageMappingSection); 75 Strip(CoverageRecordsSection); 76 } 77 78 for (const auto &Section : OF->sections()) { 79 StringRef Name; 80 if (Expected<StringRef> NameOrErr = Section.getName()) { 81 Name = *NameOrErr; 82 } else { 83 consumeError(NameOrErr.takeError()); 84 return 1; 85 } 86 87 if (Name == ProfileNamesSection) 88 ProfileNames = Section; 89 else if (Name == CoverageMappingSection) 90 CoverageMapping = Section; 91 else if (Name == CoverageRecordsSection) 92 CoverageRecords = Section; 93 else 94 continue; 95 ++FoundSectionCount; 96 } 97 if (FoundSectionCount != 3) 98 return 1; 99 100 // Get the contents of the given sections. 101 uint64_t ProfileNamesAddress = ProfileNames.getAddress(); 102 StringRef CoverageMappingData; 103 StringRef CoverageRecordsData; 104 StringRef ProfileNamesData; 105 if (Expected<StringRef> E = CoverageMapping.getContents()) 106 CoverageMappingData = *E; 107 else { 108 consumeError(E.takeError()); 109 return 1; 110 } 111 if (Expected<StringRef> E = CoverageRecords.getContents()) 112 CoverageRecordsData = *E; 113 else { 114 consumeError(E.takeError()); 115 return 1; 116 } 117 if (Expected<StringRef> E = ProfileNames.getContents()) 118 ProfileNamesData = *E; 119 else { 120 consumeError(E.takeError()); 121 return 1; 122 } 123 124 // If this is a linked PE/COFF file, then we have to skip over the null byte 125 // that is allocated in the .lprfn$A section in the LLVM profiling runtime. 126 if (isa<COFFObjectFile>(OF) && !OF->isRelocatableObject()) 127 ProfileNamesData = ProfileNamesData.drop_front(1); 128 129 int FD; 130 if (auto Err = sys::fs::openFileForWrite(OutputFilename, FD)) { 131 errs() << "error: " << Err.message() << "\n"; 132 return 1; 133 } 134 135 coverage::TestingFormatWriter Writer(ProfileNamesAddress, ProfileNamesData, 136 CoverageMappingData, 137 CoverageRecordsData); 138 raw_fd_ostream OS(FD, true); 139 Writer.write(OS); 140 141 return 0; 142 } 143