143 lines · cpp
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-exception6//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, "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 the65 // linker to sort these sections between "$A" and "$Z". The linker removes66 // the dollar and everything after it in the final binary. Do the same to67 // 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 else94 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 byte125 // 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