xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-cov/TestingSupport.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- TestingSupport.cpp - Convert objects files into test files --------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
9*5f757f3fSDimitry Andric #include "llvm/Object/COFF.h"
100b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h"
11*5f757f3fSDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
120b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProf.h"
138bcb0991SDimitry Andric #include "llvm/Support/Alignment.h"
140b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
15fe6060f1SDimitry Andric #include "llvm/Support/FileSystem.h"
160b57cec5SDimitry Andric #include "llvm/Support/LEB128.h"
1781ad6265SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
180b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
190b57cec5SDimitry Andric #include <functional>
200b57cec5SDimitry Andric #include <system_error>
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric using namespace object;
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric int convertForTestingMain(int argc, const char *argv[]) {
260b57cec5SDimitry Andric   cl::opt<std::string> InputSourceFile(cl::Positional, cl::Required,
270b57cec5SDimitry Andric                                        cl::desc("<Source file>"));
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric   cl::opt<std::string> OutputFilename(
300b57cec5SDimitry Andric       "o", cl::Required,
310b57cec5SDimitry Andric       cl::desc(
320b57cec5SDimitry Andric           "File with the profile data obtained after an instrumented run"));
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric   cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   auto ObjErr = llvm::object::ObjectFile::createObjectFile(InputSourceFile);
370b57cec5SDimitry Andric   if (!ObjErr) {
380b57cec5SDimitry Andric     std::string Buf;
390b57cec5SDimitry Andric     raw_string_ostream OS(Buf);
400b57cec5SDimitry Andric     logAllUnhandledErrors(ObjErr.takeError(), OS);
410b57cec5SDimitry Andric     OS.flush();
420b57cec5SDimitry Andric     errs() << "error: " << Buf;
430b57cec5SDimitry Andric     return 1;
440b57cec5SDimitry Andric   }
450b57cec5SDimitry Andric   ObjectFile *OF = ObjErr.get().getBinary();
460b57cec5SDimitry Andric   auto BytesInAddress = OF->getBytesInAddress();
470b57cec5SDimitry Andric   if (BytesInAddress != 8) {
480b57cec5SDimitry Andric     errs() << "error: 64 bit binary expected\n";
490b57cec5SDimitry Andric     return 1;
500b57cec5SDimitry Andric   }
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   // Look for the sections that we are interested in.
530b57cec5SDimitry Andric   int FoundSectionCount = 0;
54fe6060f1SDimitry Andric   SectionRef ProfileNames, CoverageMapping, CoverageRecords;
550b57cec5SDimitry Andric   auto ObjFormat = OF->getTripleObjectFormat();
56*5f757f3fSDimitry Andric 
57*5f757f3fSDimitry Andric   auto ProfileNamesSection = getInstrProfSectionName(IPSK_name, ObjFormat,
58*5f757f3fSDimitry Andric                                                      /*AddSegmentInfo=*/false);
59*5f757f3fSDimitry Andric   auto CoverageMappingSection =
60*5f757f3fSDimitry Andric       getInstrProfSectionName(IPSK_covmap, ObjFormat, /*AddSegmentInfo=*/false);
61*5f757f3fSDimitry Andric   auto CoverageRecordsSection =
62*5f757f3fSDimitry Andric       getInstrProfSectionName(IPSK_covfun, ObjFormat, /*AddSegmentInfo=*/false);
63*5f757f3fSDimitry Andric   if (isa<object::COFFObjectFile>(OF)) {
64*5f757f3fSDimitry Andric     // On COFF, the object file section name may end in "$M". This tells the
65*5f757f3fSDimitry Andric     // linker to sort these sections between "$A" and "$Z". The linker removes
66*5f757f3fSDimitry Andric     // the dollar and everything after it in the final binary. Do the same to
67*5f757f3fSDimitry Andric     // match.
68*5f757f3fSDimitry Andric     auto Strip = [](std::string &Str) {
69*5f757f3fSDimitry Andric       auto Pos = Str.find('$');
70*5f757f3fSDimitry Andric       if (Pos != std::string::npos)
71*5f757f3fSDimitry Andric         Str.resize(Pos);
72*5f757f3fSDimitry Andric     };
73*5f757f3fSDimitry Andric     Strip(ProfileNamesSection);
74*5f757f3fSDimitry Andric     Strip(CoverageMappingSection);
75*5f757f3fSDimitry Andric     Strip(CoverageRecordsSection);
76*5f757f3fSDimitry Andric   }
77*5f757f3fSDimitry Andric 
780b57cec5SDimitry Andric   for (const auto &Section : OF->sections()) {
790b57cec5SDimitry Andric     StringRef Name;
808bcb0991SDimitry Andric     if (Expected<StringRef> NameOrErr = Section.getName()) {
818bcb0991SDimitry Andric       Name = *NameOrErr;
828bcb0991SDimitry Andric     } else {
838bcb0991SDimitry Andric       consumeError(NameOrErr.takeError());
840b57cec5SDimitry Andric       return 1;
858bcb0991SDimitry Andric     }
868bcb0991SDimitry Andric 
87*5f757f3fSDimitry Andric     if (Name == ProfileNamesSection)
880b57cec5SDimitry Andric       ProfileNames = Section;
89*5f757f3fSDimitry Andric     else if (Name == CoverageMappingSection)
900b57cec5SDimitry Andric       CoverageMapping = Section;
91*5f757f3fSDimitry Andric     else if (Name == CoverageRecordsSection)
92fe6060f1SDimitry Andric       CoverageRecords = Section;
93*5f757f3fSDimitry Andric     else
940b57cec5SDimitry Andric       continue;
950b57cec5SDimitry Andric     ++FoundSectionCount;
960b57cec5SDimitry Andric   }
97fe6060f1SDimitry Andric   if (FoundSectionCount != 3)
980b57cec5SDimitry Andric     return 1;
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   // Get the contents of the given sections.
1010b57cec5SDimitry Andric   uint64_t ProfileNamesAddress = ProfileNames.getAddress();
1020b57cec5SDimitry Andric   StringRef CoverageMappingData;
103fe6060f1SDimitry Andric   StringRef CoverageRecordsData;
1040b57cec5SDimitry Andric   StringRef ProfileNamesData;
1050b57cec5SDimitry Andric   if (Expected<StringRef> E = CoverageMapping.getContents())
1060b57cec5SDimitry Andric     CoverageMappingData = *E;
1070b57cec5SDimitry Andric   else {
1080b57cec5SDimitry Andric     consumeError(E.takeError());
1090b57cec5SDimitry Andric     return 1;
1100b57cec5SDimitry Andric   }
111fe6060f1SDimitry Andric   if (Expected<StringRef> E = CoverageRecords.getContents())
112fe6060f1SDimitry Andric     CoverageRecordsData = *E;
113fe6060f1SDimitry Andric   else {
114fe6060f1SDimitry Andric     consumeError(E.takeError());
115fe6060f1SDimitry Andric     return 1;
116fe6060f1SDimitry Andric   }
1170b57cec5SDimitry Andric   if (Expected<StringRef> E = ProfileNames.getContents())
1180b57cec5SDimitry Andric     ProfileNamesData = *E;
1190b57cec5SDimitry Andric   else {
1200b57cec5SDimitry Andric     consumeError(E.takeError());
1210b57cec5SDimitry Andric     return 1;
1220b57cec5SDimitry Andric   }
1230b57cec5SDimitry Andric 
124*5f757f3fSDimitry Andric   // If this is a linked PE/COFF file, then we have to skip over the null byte
125*5f757f3fSDimitry Andric   // that is allocated in the .lprfn$A section in the LLVM profiling runtime.
126*5f757f3fSDimitry Andric   if (isa<COFFObjectFile>(OF) && !OF->isRelocatableObject())
127*5f757f3fSDimitry Andric     ProfileNamesData = ProfileNamesData.drop_front(1);
128*5f757f3fSDimitry Andric 
1290b57cec5SDimitry Andric   int FD;
1300b57cec5SDimitry Andric   if (auto Err = sys::fs::openFileForWrite(OutputFilename, FD)) {
1310b57cec5SDimitry Andric     errs() << "error: " << Err.message() << "\n";
1320b57cec5SDimitry Andric     return 1;
1330b57cec5SDimitry Andric   }
1340b57cec5SDimitry Andric 
135*5f757f3fSDimitry Andric   coverage::TestingFormatWriter Writer(ProfileNamesAddress, ProfileNamesData,
136*5f757f3fSDimitry Andric                                        CoverageMappingData,
137*5f757f3fSDimitry Andric                                        CoverageRecordsData);
1380b57cec5SDimitry Andric   raw_fd_ostream OS(FD, true);
139*5f757f3fSDimitry Andric   Writer.write(OS);
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   return 0;
1420b57cec5SDimitry Andric }
143