X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FProfileData%2FCoverageMappingReader.cpp;h=89e1cf42c5773e5ad2a2a5a953ed91e716a96122;hb=44fb5881d8edf448d6231a5b8df583aecd6bcd42;hp=8d1508b03706347809e28cf406d37a82687eaab1;hpb=6c7a6a1ba2ba93a7d7e96d88c39c3cd48ff082e5;p=oota-llvm.git diff --git a/lib/ProfileData/CoverageMappingReader.cpp b/lib/ProfileData/CoverageMappingReader.cpp index 8d1508b0370..89e1cf42c57 100644 --- a/lib/ProfileData/CoverageMappingReader.cpp +++ b/lib/ProfileData/CoverageMappingReader.cpp @@ -14,13 +14,20 @@ #include "llvm/ProfileData/CoverageMappingReader.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/LEB128.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace coverage; using namespace object; +#define DEBUG_TYPE "coverage-mapping" + void CoverageMappingIterator::increment() { // Check if all the records were read or if an error occurred while reading // the next record. @@ -30,13 +37,13 @@ void CoverageMappingIterator::increment() { std::error_code RawCoverageReader::readULEB128(uint64_t &Result) { if (Data.size() < 1) - return error(instrprof_error::truncated); + return coveragemap_error::truncated; unsigned N = 0; Result = decodeULEB128(reinterpret_cast(Data.data()), &N); if (N > Data.size()) - return error(instrprof_error::malformed); + return coveragemap_error::malformed; Data = Data.substr(N); - return success(); + return std::error_code(); } std::error_code RawCoverageReader::readIntMax(uint64_t &Result, @@ -44,8 +51,8 @@ std::error_code RawCoverageReader::readIntMax(uint64_t &Result, if (auto Err = readULEB128(Result)) return Err; if (Result >= MaxPlus1) - return error(instrprof_error::malformed); - return success(); + return coveragemap_error::malformed; + return std::error_code(); } std::error_code RawCoverageReader::readSize(uint64_t &Result) { @@ -53,8 +60,8 @@ std::error_code RawCoverageReader::readSize(uint64_t &Result) { return Err; // Sanity check the number. if (Result > Data.size()) - return error(instrprof_error::malformed); - return success(); + return coveragemap_error::malformed; + return std::error_code(); } std::error_code RawCoverageReader::readString(StringRef &Result) { @@ -63,7 +70,7 @@ std::error_code RawCoverageReader::readString(StringRef &Result) { return Err; Result = Data.substr(0, Length); Data = Data.substr(Length); - return success(); + return std::error_code(); } std::error_code RawCoverageFilenamesReader::read() { @@ -76,7 +83,7 @@ std::error_code RawCoverageFilenamesReader::read() { return Err; Filenames.push_back(Filename); } - return success(); + return std::error_code(); } std::error_code RawCoverageMappingReader::decodeCounter(unsigned Value, @@ -85,10 +92,10 @@ std::error_code RawCoverageMappingReader::decodeCounter(unsigned Value, switch (Tag) { case Counter::Zero: C = Counter::getZero(); - return success(); + return std::error_code(); case Counter::CounterValueReference: C = Counter::getCounter(Value >> Counter::EncodingTagBits); - return success(); + return std::error_code(); default: break; } @@ -98,15 +105,15 @@ std::error_code RawCoverageMappingReader::decodeCounter(unsigned Value, case CounterExpression::Add: { auto ID = Value >> Counter::EncodingTagBits; if (ID >= Expressions.size()) - return error(instrprof_error::malformed); + return coveragemap_error::malformed; Expressions[ID].Kind = CounterExpression::ExprKind(Tag); C = Counter::getExpression(ID); break; } default: - return error(instrprof_error::malformed); + return coveragemap_error::malformed; } - return success(); + return std::error_code(); } std::error_code RawCoverageMappingReader::readCounter(Counter &C) { @@ -116,7 +123,7 @@ std::error_code RawCoverageMappingReader::readCounter(Counter &C) { return Err; if (auto Err = decodeCounter(EncodedCounter, C)) return Err; - return success(); + return std::error_code(); } static const unsigned EncodingExpansionRegionBit = 1 @@ -153,7 +160,7 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray( ExpandedFileID = EncodedCounterAndRegion >> Counter::EncodingCounterTagAndExpansionRegionTagBits; if (ExpandedFileID >= NumFileIDs) - return error(instrprof_error::malformed); + return coveragemap_error::malformed; } else { switch (EncodedCounterAndRegion >> Counter::EncodingCounterTagAndExpansionRegionTagBits) { @@ -164,23 +171,20 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray( Kind = CounterMappingRegion::SkippedRegion; break; default: - return error(instrprof_error::malformed); + return coveragemap_error::malformed; } } } // Read the source range. - uint64_t LineStartDelta, CodeBeforeColumnStart, NumLines, ColumnEnd; + uint64_t LineStartDelta, ColumnStart, NumLines, ColumnEnd; if (auto Err = readIntMax(LineStartDelta, std::numeric_limits::max())) return Err; - if (auto Err = readULEB128(CodeBeforeColumnStart)) + if (auto Err = readULEB128(ColumnStart)) return Err; - bool HasCodeBefore = CodeBeforeColumnStart & 1; - uint64_t ColumnStart = CodeBeforeColumnStart >> - CounterMappingRegion::EncodingHasCodeBeforeBits; if (ColumnStart > std::numeric_limits::max()) - return error(instrprof_error::malformed); + return coveragemap_error::malformed; if (auto Err = readIntMax(NumLines, std::numeric_limits::max())) return Err; if (auto Err = readIntMax(ColumnEnd, std::numeric_limits::max())) @@ -198,15 +202,26 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray( ColumnStart = 1; ColumnEnd = std::numeric_limits::max(); } + + DEBUG({ + dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" + << ColumnStart << " -> " << (LineStart + NumLines) << ":" + << ColumnEnd << ", "; + if (Kind == CounterMappingRegion::ExpansionRegion) + dbgs() << "Expands to file " << ExpandedFileID; + else + CounterMappingContext(Expressions).dump(C, dbgs()); + dbgs() << "\n"; + }); + MappingRegions.push_back(CounterMappingRegion( - C, InferredFileID, LineStart, ColumnStart, LineStart + NumLines, - ColumnEnd, HasCodeBefore, Kind)); - MappingRegions.back().ExpandedFileID = ExpandedFileID; + C, InferredFileID, ExpandedFileID, LineStart, ColumnStart, + LineStart + NumLines, ColumnEnd, Kind)); } - return success(); + return std::error_code(); } -std::error_code RawCoverageMappingReader::read(CoverageMappingRecord &Record) { +std::error_code RawCoverageMappingReader::read() { // Read the virtual file mapping. llvm::SmallVector VirtualFileMapping; @@ -272,266 +287,261 @@ std::error_code RawCoverageMappingReader::read(CoverageMappingRecord &Record) { } } - Record.FunctionName = FunctionName; - Record.Filenames = Filenames; - Record.Expressions = Expressions; - Record.MappingRegions = MappingRegions; - return success(); + return std::error_code(); } -ObjectFileCoverageMappingReader::ObjectFileCoverageMappingReader( - StringRef FileName) - : CurrentRecord(0) { - auto File = llvm::object::ObjectFile::createObjectFile(FileName); - if (!File) - error(File.getError()); - else - Object = std::move(File.get()); +std::error_code InstrProfSymtab::create(SectionRef &Section) { + if (auto Err = Section.getContents(Data)) + return Err; + Address = Section.getAddress(); + return std::error_code(); } -namespace { -/// \brief The coverage mapping data for a single function. -/// It points to the function's name. -template struct CoverageMappingFunctionRecord { - IntPtrT FunctionNamePtr; - uint32_t FunctionNameSize; - uint32_t CoverageMappingSize; - uint64_t FunctionHash; -}; - -/// \brief The coverage mapping data for a single translation unit. -/// It points to the array of function coverage mapping records and the encoded -/// filenames array. -template struct CoverageMappingTURecord { - uint32_t FunctionRecordsSize; - uint32_t FilenamesSize; - uint32_t CoverageMappingsSize; - uint32_t Version; -}; - -/// \brief A helper structure to access the data from a section -/// in an object file. -struct SectionData { - StringRef Data; - uint64_t Address; - - std::error_code load(SectionRef &Section) { - if (auto Err = Section.getContents(Data)) - return Err; - return Section.getAddress(Address); - } - - std::error_code get(uint64_t Pointer, size_t Size, StringRef &Result) { - if (Pointer < Address) - return instrprof_error::malformed; - auto Offset = Pointer - Address; - if (Offset + Size > Data.size()) - return instrprof_error::malformed; - Result = Data.substr(Pointer - Address, Size); - return instrprof_error::success; - } -}; +StringRef InstrProfSymtab::getFuncName(uint64_t Pointer, size_t Size) { + if (Pointer < Address) + return StringRef(); + auto Offset = Pointer - Address; + if (Offset + Size > Data.size()) + return StringRef(); + return Data.substr(Pointer - Address, Size); } -template -std::error_code readCoverageMappingData( - SectionData &ProfileNames, StringRef Data, - std::vector &Records, +template +static std::error_code readCoverageMappingData( + InstrProfSymtab &ProfileNames, StringRef Data, + std::vector &Records, std::vector &Filenames) { + using namespace support; llvm::DenseSet UniqueFunctionMappingData; // Read the records in the coverage data section. - while (!Data.empty()) { - if (Data.size() < sizeof(CoverageMappingTURecord)) - return instrprof_error::malformed; - auto TU = reinterpret_cast *>(Data.data()); - Data = Data.substr(sizeof(CoverageMappingTURecord)); - switch (TU->Version) { - case CoverageMappingVersion1: - break; - default: - return instrprof_error::unsupported_version; - } - auto Version = CoverageMappingVersion(TU->Version); - - // Get the function records. - auto FunctionRecords = - reinterpret_cast *>(Data.data()); - if (Data.size() < - sizeof(CoverageMappingFunctionRecord) * TU->FunctionRecordsSize) - return instrprof_error::malformed; - Data = Data.substr(sizeof(CoverageMappingFunctionRecord) * - TU->FunctionRecordsSize); + for (const char *Buf = Data.data(), *End = Buf + Data.size(); Buf < End;) { + if (Buf + sizeof(CovMapHeader) > End) + return coveragemap_error::malformed; + auto CovHeader = reinterpret_cast(Buf); + uint32_t NRecords = CovHeader->getNRecords(); + uint32_t FilenamesSize = CovHeader->getFilenamesSize(); + uint32_t CoverageSize = CovHeader->getCoverageSize(); + uint32_t Version = CovHeader->getVersion(); + Buf = reinterpret_cast(++CovHeader); + + if (Version > coverage::CoverageMappingCurrentVersion) + return coveragemap_error::unsupported_version; + + // Skip past the function records, saving the start and end for later. + const char *FunBuf = Buf; + Buf += NRecords * sizeof(coverage::CovMapFunctionRecord); + const char *FunEnd = Buf; // Get the filenames. - if (Data.size() < TU->FilenamesSize) - return instrprof_error::malformed; - auto RawFilenames = Data.substr(0, TU->FilenamesSize); - Data = Data.substr(TU->FilenamesSize); + if (Buf + FilenamesSize > End) + return coveragemap_error::malformed; size_t FilenamesBegin = Filenames.size(); - RawCoverageFilenamesReader Reader(RawFilenames, Filenames); + RawCoverageFilenamesReader Reader(StringRef(Buf, FilenamesSize), Filenames); if (auto Err = Reader.read()) return Err; - - // Get the coverage mappings. - if (Data.size() < TU->CoverageMappingsSize) - return instrprof_error::malformed; - auto CoverageMappings = Data.substr(0, TU->CoverageMappingsSize); - Data = Data.substr(TU->CoverageMappingsSize); - - for (unsigned I = 0; I < TU->FunctionRecordsSize; ++I) { - auto &MappingRecord = FunctionRecords[I]; - - // Get the coverage mapping. - if (CoverageMappings.size() < MappingRecord.CoverageMappingSize) - return instrprof_error::malformed; - auto Mapping = - CoverageMappings.substr(0, MappingRecord.CoverageMappingSize); - CoverageMappings = - CoverageMappings.substr(MappingRecord.CoverageMappingSize); + Buf += FilenamesSize; + + // We'll read the coverage mapping records in the loop below. + const char *CovBuf = Buf; + Buf += CoverageSize; + const char *CovEnd = Buf; + + if (Buf > End) + return coveragemap_error::malformed; + // Each coverage map has an alignment of 8, so we need to adjust alignment + // before reading the next map. + Buf += alignmentAdjustment(Buf, 8); + + auto CFR = + reinterpret_cast *>(FunBuf); + while ((const char *)CFR < FunEnd) { + // Read the function information + uint32_t DataSize = CFR->template getDataSize(); + uint64_t FuncHash = CFR->template getFuncHash(); + + // Now use that to read the coverage data. + if (CovBuf + DataSize > CovEnd) + return coveragemap_error::malformed; + auto Mapping = StringRef(CovBuf, DataSize); + CovBuf += DataSize; // Ignore this record if we already have a record that points to the same - // function name. - // This is useful to ignore the redundant records for the functions - // with ODR linkage. - if (UniqueFunctionMappingData.count(MappingRecord.FunctionNamePtr)) + // function name. This is useful to ignore the redundant records for the + // functions with ODR linkage. + T NameRef = CFR->template getFuncNameRef(); + if (!UniqueFunctionMappingData.insert(NameRef).second) continue; - UniqueFunctionMappingData.insert(MappingRecord.FunctionNamePtr); - StringRef FunctionName; - if (auto Err = - ProfileNames.get(MappingRecord.FunctionNamePtr, - MappingRecord.FunctionNameSize, FunctionName)) - return Err; - Records.push_back(ObjectFileCoverageMappingReader::ProfileMappingRecord( - Version, FunctionName, MappingRecord.FunctionHash, Mapping, + + StringRef FuncName; + if (std::error_code EC = + CFR->template getFuncName(ProfileNames, FuncName)) + return EC; + Records.push_back(BinaryCoverageReader::ProfileMappingRecord( + CoverageMappingVersion(Version), FuncName, FuncHash, Mapping, FilenamesBegin, Filenames.size() - FilenamesBegin)); + CFR++; } } - return instrprof_error::success; + return std::error_code(); } static const char *TestingFormatMagic = "llvmcovmtestdata"; -static std::error_code decodeTestingFormat(StringRef Data, - SectionData &ProfileNames, - StringRef &CoverageMapping) { +static std::error_code loadTestingFormat(StringRef Data, + InstrProfSymtab &ProfileNames, + StringRef &CoverageMapping, + uint8_t &BytesInAddress, + support::endianness &Endian) { + BytesInAddress = 8; + Endian = support::endianness::little; + Data = Data.substr(StringRef(TestingFormatMagic).size()); if (Data.size() < 1) - return instrprof_error::truncated; + return coveragemap_error::truncated; unsigned N = 0; auto ProfileNamesSize = decodeULEB128(reinterpret_cast(Data.data()), &N); if (N > Data.size()) - return instrprof_error::malformed; + return coveragemap_error::malformed; Data = Data.substr(N); if (Data.size() < 1) - return instrprof_error::truncated; + return coveragemap_error::truncated; N = 0; - ProfileNames.Address = + uint64_t Address = decodeULEB128(reinterpret_cast(Data.data()), &N); if (N > Data.size()) - return instrprof_error::malformed; + return coveragemap_error::malformed; Data = Data.substr(N); if (Data.size() < ProfileNamesSize) - return instrprof_error::malformed; - ProfileNames.Data = Data.substr(0, ProfileNamesSize); + return coveragemap_error::malformed; + ProfileNames.create(Data.substr(0, ProfileNamesSize), Address); CoverageMapping = Data.substr(ProfileNamesSize); - return instrprof_error::success; + return std::error_code(); } -ObjectFileCoverageMappingReader::ObjectFileCoverageMappingReader( - std::unique_ptr &ObjectBuffer, sys::fs::file_magic Type) - : CurrentRecord(0) { - if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic)) { - // This is a special format used for testing. - SectionData ProfileNames; - StringRef CoverageMapping; - if (auto Err = decodeTestingFormat(ObjectBuffer->getBuffer(), ProfileNames, - CoverageMapping)) { - error(Err); - return; - } - error(readCoverageMappingData(ProfileNames, CoverageMapping, - MappingRecords, Filenames)); - Object = OwningBinary(std::unique_ptr(), - std::move(ObjectBuffer)); - return; +static ErrorOr lookupSection(ObjectFile &OF, StringRef Name) { + StringRef FoundName; + for (const auto &Section : OF.sections()) { + if (auto EC = Section.getName(FoundName)) + return EC; + if (FoundName == Name) + return Section; } - - auto File = object::ObjectFile::createObjectFile( - ObjectBuffer->getMemBufferRef(), Type); - if (!File) - error(File.getError()); - else - Object = OwningBinary(std::move(File.get()), - std::move(ObjectBuffer)); + return coveragemap_error::no_data_found; } -std::error_code ObjectFileCoverageMappingReader::readHeader() { - ObjectFile *OF = Object.getBinary().get(); - if (!OF) - return getError(); - auto BytesInAddress = OF->getBytesInAddress(); - if (BytesInAddress != 4 && BytesInAddress != 8) - return error(instrprof_error::malformed); +static std::error_code +loadBinaryFormat(MemoryBufferRef ObjectBuffer, InstrProfSymtab &ProfileNames, + StringRef &CoverageMapping, uint8_t &BytesInAddress, + support::endianness &Endian, StringRef Arch) { + auto BinOrErr = object::createBinary(ObjectBuffer); + if (std::error_code EC = BinOrErr.getError()) + return EC; + auto Bin = std::move(BinOrErr.get()); + std::unique_ptr OF; + if (auto *Universal = dyn_cast(Bin.get())) { + // If we have a universal binary, try to look up the object for the + // appropriate architecture. + auto ObjectFileOrErr = Universal->getObjectForArch(Arch); + if (std::error_code EC = ObjectFileOrErr.getError()) + return EC; + OF = std::move(ObjectFileOrErr.get()); + } else if (isa(Bin.get())) { + // For any other object file, upcast and take ownership. + OF.reset(cast(Bin.release())); + // If we've asked for a particular arch, make sure they match. + if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch()) + return object_error::arch_not_found; + } else + // We can only handle object files. + return coveragemap_error::malformed; + + // The coverage uses native pointer sizes for the object it's written in. + BytesInAddress = OF->getBytesInAddress(); + Endian = OF->isLittleEndian() ? support::endianness::little + : support::endianness::big; // Look for the sections that we are interested in. - int FoundSectionCount = 0; - SectionRef ProfileNames, CoverageMapping; - for (const auto &Section : OF->sections()) { - StringRef Name; - if (auto Err = Section.getName(Name)) - return Err; - if (Name == "__llvm_prf_names") { - ProfileNames = Section; - } else if (Name == "__llvm_covmap") { - CoverageMapping = Section; - } else - continue; - ++FoundSectionCount; - } - if (FoundSectionCount != 2) - return error(instrprof_error::bad_header); + auto NamesSection = lookupSection(*OF, getInstrProfNameSectionName(false)); + if (auto EC = NamesSection.getError()) + return EC; + auto CoverageSection = + lookupSection(*OF, getInstrProfCoverageSectionName(false)); + if (auto EC = CoverageSection.getError()) + return EC; // Get the contents of the given sections. - StringRef Data; - if (auto Err = CoverageMapping.getContents(Data)) - return Err; - SectionData ProfileNamesData; - if (auto Err = ProfileNamesData.load(ProfileNames)) - return Err; + if (std::error_code EC = CoverageSection->getContents(CoverageMapping)) + return EC; + if (std::error_code EC = ProfileNames.create(*NamesSection)) + return EC; - // Load the data from the found sections. - std::error_code Err; - if (BytesInAddress == 4) - Err = readCoverageMappingData(ProfileNamesData, Data, - MappingRecords, Filenames); - else - Err = readCoverageMappingData(ProfileNamesData, Data, - MappingRecords, Filenames); - if (Err) - return error(Err); + return std::error_code(); +} - return success(); +ErrorOr> +BinaryCoverageReader::create(std::unique_ptr &ObjectBuffer, + StringRef Arch) { + std::unique_ptr Reader(new BinaryCoverageReader()); + + InstrProfSymtab ProfileNames; + StringRef Coverage; + uint8_t BytesInAddress; + support::endianness Endian; + std::error_code EC; + if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic)) + // This is a special format used for testing. + EC = loadTestingFormat(ObjectBuffer->getBuffer(), ProfileNames, Coverage, + BytesInAddress, Endian); + else + EC = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), ProfileNames, + Coverage, BytesInAddress, Endian, Arch); + if (EC) + return EC; + + if (BytesInAddress == 4 && Endian == support::endianness::little) + EC = readCoverageMappingData( + ProfileNames, Coverage, Reader->MappingRecords, Reader->Filenames); + else if (BytesInAddress == 4 && Endian == support::endianness::big) + EC = readCoverageMappingData( + ProfileNames, Coverage, Reader->MappingRecords, Reader->Filenames); + else if (BytesInAddress == 8 && Endian == support::endianness::little) + EC = readCoverageMappingData( + ProfileNames, Coverage, Reader->MappingRecords, Reader->Filenames); + else if (BytesInAddress == 8 && Endian == support::endianness::big) + EC = readCoverageMappingData( + ProfileNames, Coverage, Reader->MappingRecords, Reader->Filenames); + else + return coveragemap_error::malformed; + if (EC) + return EC; + return std::move(Reader); } std::error_code -ObjectFileCoverageMappingReader::readNextRecord(CoverageMappingRecord &Record) { +BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) { if (CurrentRecord >= MappingRecords.size()) - return error(instrprof_error::eof); + return coveragemap_error::eof; FunctionsFilenames.clear(); Expressions.clear(); MappingRegions.clear(); auto &R = MappingRecords[CurrentRecord]; RawCoverageMappingReader Reader( - R.FunctionName, R.CoverageMapping, - makeArrayRef(Filenames.data() + R.FilenamesBegin, R.FilenamesSize), + R.CoverageMapping, + makeArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize), FunctionsFilenames, Expressions, MappingRegions); - if (auto Err = Reader.read(Record)) + if (auto Err = Reader.read()) return Err; + + Record.FunctionName = R.FunctionName; Record.FunctionHash = R.FunctionHash; + Record.Filenames = FunctionsFilenames; + Record.Expressions = Expressions; + Record.MappingRegions = MappingRegions; + ++CurrentRecord; - return success(); + return std::error_code(); }