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
22using namespace llvm;
23using namespace object;
24
25int 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, Overview: "LLVM code coverage tool\n");
35
36 auto ObjErr = llvm::object::ObjectFile::createObjectFile(ObjectPath: InputSourceFile);
37 if (!ObjErr) {
38 std::string Buf;
39 raw_string_ostream OS(Buf);
40 logAllUnhandledErrors(E: ObjErr.takeError(), OS);
41 errs() << "error: " << Buf;
42 return 1;
43 }
44 ObjectFile *OF = ObjErr.get().getBinary();
45 auto BytesInAddress = OF->getBytesInAddress();
46 if (BytesInAddress != 8) {
47 errs() << "error: 64 bit binary expected\n";
48 return 1;
49 }
50
51 // Look for the sections that we are interested in.
52 int FoundSectionCount = 0;
53 SectionRef ProfileNames, CoverageMapping, CoverageRecords;
54 auto ObjFormat = OF->getTripleObjectFormat();
55
56 auto ProfileNamesSection = getInstrProfSectionName(IPSK: IPSK_name, OF: ObjFormat,
57 /*AddSegmentInfo=*/false);
58 auto CoverageMappingSection =
59 getInstrProfSectionName(IPSK: IPSK_covmap, OF: ObjFormat, /*AddSegmentInfo=*/false);
60 auto CoverageRecordsSection =
61 getInstrProfSectionName(IPSK: IPSK_covfun, OF: ObjFormat, /*AddSegmentInfo=*/false);
62 if (isa<object::COFFObjectFile>(Val: OF)) {
63 // On COFF, the object file section name may end in "$M". This tells the
64 // linker to sort these sections between "$A" and "$Z". The linker removes
65 // the dollar and everything after it in the final binary. Do the same to
66 // match.
67 auto Strip = [](std::string &Str) {
68 auto Pos = Str.find(c: '$');
69 if (Pos != std::string::npos)
70 Str.resize(n: Pos);
71 };
72 Strip(ProfileNamesSection);
73 Strip(CoverageMappingSection);
74 Strip(CoverageRecordsSection);
75 }
76
77 for (const auto &Section : OF->sections()) {
78 StringRef Name;
79 if (Expected<StringRef> NameOrErr = Section.getName()) {
80 Name = *NameOrErr;
81 } else {
82 consumeError(Err: NameOrErr.takeError());
83 return 1;
84 }
85
86 if (Name == ProfileNamesSection)
87 ProfileNames = Section;
88 else if (Name == CoverageMappingSection)
89 CoverageMapping = Section;
90 else if (Name == CoverageRecordsSection)
91 CoverageRecords = Section;
92 else
93 continue;
94 ++FoundSectionCount;
95 }
96 if (FoundSectionCount != 3)
97 return 1;
98
99 // Get the contents of the given sections.
100 uint64_t ProfileNamesAddress = ProfileNames.getAddress();
101 StringRef CoverageMappingData;
102 StringRef CoverageRecordsData;
103 StringRef ProfileNamesData;
104 if (Expected<StringRef> E = CoverageMapping.getContents())
105 CoverageMappingData = *E;
106 else {
107 consumeError(Err: E.takeError());
108 return 1;
109 }
110 if (Expected<StringRef> E = CoverageRecords.getContents())
111 CoverageRecordsData = *E;
112 else {
113 consumeError(Err: E.takeError());
114 return 1;
115 }
116 if (Expected<StringRef> E = ProfileNames.getContents())
117 ProfileNamesData = *E;
118 else {
119 consumeError(Err: E.takeError());
120 return 1;
121 }
122
123 // If this is a linked PE/COFF file, then we have to skip over the null byte
124 // that is allocated in the .lprfn$A section in the LLVM profiling runtime.
125 if (isa<COFFObjectFile>(Val: OF) && !OF->isRelocatableObject())
126 ProfileNamesData = ProfileNamesData.drop_front(N: 1);
127
128 int FD;
129 if (auto Err = sys::fs::openFileForWrite(Name: OutputFilename, ResultFD&: FD)) {
130 errs() << "error: " << Err.message() << "\n";
131 return 1;
132 }
133
134 coverage::TestingFormatWriter Writer(ProfileNamesAddress, ProfileNamesData,
135 CoverageMappingData,
136 CoverageRecordsData);
137 raw_fd_ostream OS(FD, true);
138 Writer.write(OS);
139
140 return 0;
141}
142