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