X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FProfileData%2FCoverageMappingReader.cpp;h=af6c616fa0311bf0bb0f6d67e6df32f0d066d6f0;hp=3f8f76f60949975a305333cae35c596c7c96e018;hb=dcf208db214fb7f88af9717445280de39bc28637;hpb=d39109de0964809f8c7ccfdad49901efb66bfba2 diff --git a/lib/ProfileData/CoverageMappingReader.cpp b/lib/ProfileData/CoverageMappingReader.cpp index 3f8f76f6094..af6c616fa03 100644 --- a/lib/ProfileData/CoverageMappingReader.cpp +++ b/lib/ProfileData/CoverageMappingReader.cpp @@ -17,7 +17,10 @@ #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; @@ -34,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, @@ -48,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) { @@ -57,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) { @@ -67,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() { @@ -80,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, @@ -89,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; } @@ -102,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) { @@ -120,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 @@ -157,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) { @@ -168,7 +171,7 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray( Kind = CounterMappingRegion::SkippedRegion; break; default: - return error(instrprof_error::malformed); + return coveragemap_error::malformed; } } } @@ -181,7 +184,7 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray( if (auto Err = readULEB128(ColumnStart)) return Err; 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())) @@ -215,7 +218,7 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray( C, InferredFileID, ExpandedFileID, LineStart, ColumnStart, LineStart + NumLines, ColumnEnd, Kind)); } - return success(); + return std::error_code(); } std::error_code RawCoverageMappingReader::read() { @@ -284,169 +287,159 @@ std::error_code RawCoverageMappingReader::read() { } } - return success(); + 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; - Address = Section.getAddress(); - return instrprof_error::success; - } +std::error_code InstrProfSymtab::create(SectionRef &Section) { + if (auto Err = Section.getContents(Data)) + return Err; + Address = Section.getAddress(); + return std::error_code(); +} - 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, +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 = + endian::byte_swap(CovHeader->NRecords); + uint32_t FilenamesSize = + endian::byte_swap(CovHeader->FilenamesSize); + uint32_t CoverageSize = + endian::byte_swap(CovHeader->CoverageSize); + uint32_t Version = endian::byte_swap(CovHeader->Version); + 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 + T NamePtr = endian::byte_swap(CFR->NamePtr); + uint32_t NameSize = endian::byte_swap(CFR->NameSize); + uint32_t DataSize = endian::byte_swap(CFR->DataSize); + uint64_t FuncHash = endian::byte_swap(CFR->FuncHash); + CFR++; + + // 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.insert(MappingRecord.FunctionNamePtr) - .second) + // function name. This is useful to ignore the redundant records for the + // functions with ODR linkage. + if (!UniqueFunctionMappingData.insert(NamePtr).second) continue; - StringRef FunctionName; - if (auto Err = - ProfileNames.get(MappingRecord.FunctionNamePtr, - MappingRecord.FunctionNameSize, FunctionName)) - return Err; + + // Finally, grab the name and create a record. + StringRef FuncName = ProfileNames.getFuncName(NamePtr, NameSize); + if (NameSize && FuncName.empty()) + return coveragemap_error::malformed; Records.push_back(BinaryCoverageReader::ProfileMappingRecord( - Version, FunctionName, MappingRecord.FunctionHash, Mapping, + CoverageMappingVersion(Version), FuncName, FuncHash, Mapping, FilenamesBegin, Filenames.size() - FilenamesBegin)); } } - return instrprof_error::success; + return std::error_code(); } static const char *TestingFormatMagic = "llvmcovmtestdata"; static std::error_code loadTestingFormat(StringRef Data, - SectionData &ProfileNames, + InstrProfSymtab &ProfileNames, StringRef &CoverageMapping, - uint8_t &BytesInAddress) { + 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(); } -static std::error_code loadBinaryFormat(MemoryBufferRef ObjectBuffer, - SectionData &ProfileNames, - StringRef &CoverageMapping, - uint8_t &BytesInAddress, - Triple::ArchType Arch) { +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; + } + return coveragemap_error::no_data_found; +} + +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; @@ -463,37 +456,30 @@ static std::error_code loadBinaryFormat(MemoryBufferRef ObjectBuffer, // 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 != Triple::ArchType::UnknownArch && OF->getArch() != Arch) + if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch()) return object_error::arch_not_found; } else // We can only handle object files. - return instrprof_error::malformed; + 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 NamesSection, CoverageSection; - for (const auto &Section : OF->sections()) { - StringRef Name; - if (auto Err = Section.getName(Name)) - return Err; - if (Name == "__llvm_prf_names") { - NamesSection = Section; - } else if (Name == "__llvm_covmap") { - CoverageSection = Section; - } else - continue; - ++FoundSectionCount; - } - if (FoundSectionCount != 2) - return 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. - if (std::error_code EC = CoverageSection.getContents(CoverageMapping)) + if (std::error_code EC = CoverageSection->getContents(CoverageMapping)) return EC; - if (std::error_code EC = ProfileNames.load(NamesSection)) + if (std::error_code EC = ProfileNames.create(*NamesSection)) return EC; return std::error_code(); @@ -501,31 +487,38 @@ static std::error_code loadBinaryFormat(MemoryBufferRef ObjectBuffer, ErrorOr> BinaryCoverageReader::create(std::unique_ptr &ObjectBuffer, - Triple::ArchType Arch) { + StringRef Arch) { std::unique_ptr Reader(new BinaryCoverageReader()); - SectionData Profile; + 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(), Profile, Coverage, - BytesInAddress); + EC = loadTestingFormat(ObjectBuffer->getBuffer(), ProfileNames, Coverage, + BytesInAddress, Endian); else - EC = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), Profile, Coverage, - BytesInAddress, Arch); + EC = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), ProfileNames, + Coverage, BytesInAddress, Endian, Arch); if (EC) return EC; - if (BytesInAddress == 4) - EC = readCoverageMappingData( - Profile, Coverage, Reader->MappingRecords, Reader->Filenames); - else if (BytesInAddress == 8) - EC = readCoverageMappingData( - Profile, Coverage, Reader->MappingRecords, Reader->Filenames); + 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 instrprof_error::malformed; + return coveragemap_error::malformed; if (EC) return EC; return std::move(Reader); @@ -534,7 +527,7 @@ BinaryCoverageReader::create(std::unique_ptr &ObjectBuffer, std::error_code BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) { if (CurrentRecord >= MappingRecords.size()) - return instrprof_error::eof; + return coveragemap_error::eof; FunctionsFilenames.clear(); Expressions.clear();