1 //===- TestingSupport.cpp - Convert objects files into test files --------===//
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
7 //===----------------------------------------------------------------------===//
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"
20 #include <system_error>
23 using namespace object
;
25 int convertForTestingMain(int argc
, const char *argv
[]) {
26 cl::opt
<std::string
> InputSourceFile(cl::Positional
, cl::Required
,
27 cl::desc("<Source file>"));
29 cl::opt
<std::string
> OutputFilename(
32 "File with the profile data obtained after an instrumented run"));
34 cl::ParseCommandLineOptions(argc
, argv
, "LLVM code coverage tool\n");
36 auto ObjErr
= llvm::object::ObjectFile::createObjectFile(InputSourceFile
);
39 raw_string_ostream
OS(Buf
);
40 logAllUnhandledErrors(ObjErr
.takeError(), OS
);
42 errs() << "error: " << Buf
;
45 ObjectFile
*OF
= ObjErr
.get().getBinary();
46 auto BytesInAddress
= OF
->getBytesInAddress();
47 if (BytesInAddress
!= 8) {
48 errs() << "error: 64 bit binary expected\n";
52 // Look for the sections that we are interested in.
53 int FoundSectionCount
= 0;
54 SectionRef ProfileNames
, CoverageMapping
, CoverageRecords
;
55 auto ObjFormat
= OF
->getTripleObjectFormat();
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
68 auto Strip
= [](std::string
&Str
) {
69 auto Pos
= Str
.find('$');
70 if (Pos
!= std::string::npos
)
73 Strip(ProfileNamesSection
);
74 Strip(CoverageMappingSection
);
75 Strip(CoverageRecordsSection
);
78 for (const auto &Section
: OF
->sections()) {
80 if (Expected
<StringRef
> NameOrErr
= Section
.getName()) {
83 consumeError(NameOrErr
.takeError());
87 if (Name
== ProfileNamesSection
)
88 ProfileNames
= Section
;
89 else if (Name
== CoverageMappingSection
)
90 CoverageMapping
= Section
;
91 else if (Name
== CoverageRecordsSection
)
92 CoverageRecords
= Section
;
97 if (FoundSectionCount
!= 3)
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
;
108 consumeError(E
.takeError());
111 if (Expected
<StringRef
> E
= CoverageRecords
.getContents())
112 CoverageRecordsData
= *E
;
114 consumeError(E
.takeError());
117 if (Expected
<StringRef
> E
= ProfileNames
.getContents())
118 ProfileNamesData
= *E
;
120 consumeError(E
.takeError());
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);
130 if (auto Err
= sys::fs::openFileForWrite(OutputFilename
, FD
)) {
131 errs() << "error: " << Err
.message() << "\n";
135 coverage::TestingFormatWriter
Writer(ProfileNamesAddress
, ProfileNamesData
,
137 CoverageRecordsData
);
138 raw_fd_ostream
OS(FD
, true);