X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FProfileData%2FCoverageMappingReader.cpp;h=af6c616fa0311bf0bb0f6d67e6df32f0d066d6f0;hb=913815ec023daa5a912c2685a76e155ed6c888e7;hp=42c0f2b02249671a0b7bff57382afba3fe9a99df;hpb=bf67bfe6bbe485cc90b74674cb3752c171bb3e4c;p=oota-llvm.git diff --git a/lib/ProfileData/CoverageMappingReader.cpp b/lib/ProfileData/CoverageMappingReader.cpp index 42c0f2b0224..af6c616fa03 100644 --- a/lib/ProfileData/CoverageMappingReader.cpp +++ b/lib/ProfileData/CoverageMappingReader.cpp @@ -14,9 +14,13 @@ #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; @@ -33,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, @@ -47,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) { @@ -56,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) { @@ -66,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() { @@ -79,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, @@ -88,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; } @@ -101,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) { @@ -119,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 @@ -156,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) { @@ -167,7 +171,7 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray( Kind = CounterMappingRegion::SkippedRegion; break; default: - return error(instrprof_error::malformed); + return coveragemap_error::malformed; } } } @@ -180,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())) @@ -214,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() { @@ -283,251 +287,247 @@ std::error_code RawCoverageMappingReader::read() { } } - 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; - Address = Section.getAddress(); - return instrprof_error::success; - } - - 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 = + 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; - Records.push_back(ObjectFileCoverageMappingReader::ProfileMappingRecord( - Version, FunctionName, MappingRecord.FunctionHash, Mapping, + + // 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( + 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 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() { - const ObjectFile *OF = Object.getBinary(); - 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(); @@ -547,5 +547,5 @@ ObjectFileCoverageMappingReader::readNextRecord(CoverageMappingRecord &Record) { Record.MappingRegions = MappingRegions; ++CurrentRecord; - return success(); + return std::error_code(); }