From 6d81fc75c495e8ed20f1508042bcd2edba1a8058 Mon Sep 17 00:00:00 2001 From: Justin Bogner Date: Fri, 16 May 2014 00:38:00 +0000 Subject: ProfileData: Allow multiple profiles in RawInstrProfReader Allow multiple raw profiles to coexist in a single .profraw file, given the following conditions: - Zero padding at the end of or between profiles will be skipped. - Each profile must start with a valid header. - Mixing endianness or pointer sizes in concatenated profiles files is not allowed. This is needed to handle cases where a program's shared libraries are profiled as well as the main executable itself, as we'll need to emit each executable's counters. Combining the tables in the runtime would be expensive for the instrumented program. rdar://16918688 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208938 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ProfileData/InstrProfReader.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'lib/ProfileData') diff --git a/lib/ProfileData/InstrProfReader.cpp b/lib/ProfileData/InstrProfReader.cpp index 2ab0eb9449..7014f5e5cc 100644 --- a/lib/ProfileData/InstrProfReader.cpp +++ b/lib/ProfileData/InstrProfReader.cpp @@ -172,6 +172,29 @@ error_code RawInstrProfReader::readHeader() { return readHeader(*Header); } +template +error_code RawInstrProfReader::readNextHeader(const char *CurrentPos) { + const char *End = DataBuffer->getBufferEnd(); + // Skip zero padding between profiles. + while (CurrentPos != End && *CurrentPos == 0) + ++CurrentPos; + // If there's nothing left, we're done. + if (CurrentPos == End) + return instrprof_error::eof; + // If there isn't enough space for another header, this is probably just + // garbage at the end of the file. + if (CurrentPos + sizeof(RawHeader) > End) + return instrprof_error::malformed; + // The magic should have the same byte order as in the previous header. + uint64_t Magic = *reinterpret_cast(CurrentPos); + if (Magic != swap(getRawMagic())) + return instrprof_error::bad_magic; + + // There's another profile to read, so we need to process the header. + auto *Header = reinterpret_cast(CurrentPos); + return readHeader(*Header); +} + static uint64_t getRawVersion() { return 1; } @@ -190,16 +213,17 @@ error_code RawInstrProfReader::readHeader(const RawHeader &Header) { ptrdiff_t DataOffset = sizeof(RawHeader); ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize; ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize; - size_t FileSize = NamesOffset + sizeof(char) * NamesSize; + size_t ProfileSize = NamesOffset + sizeof(char) * NamesSize; - if (FileSize != DataBuffer->getBufferSize()) + auto *Start = reinterpret_cast(&Header); + if (Start + ProfileSize > DataBuffer->getBufferEnd()) return error(instrprof_error::bad_header); - const char *Start = DataBuffer->getBufferStart(); Data = reinterpret_cast(Start + DataOffset); DataEnd = Data + DataSize; CountersStart = reinterpret_cast(Start + CountersOffset); NamesStart = Start + NamesOffset; + ProfileEnd = Start + ProfileSize; return success(); } @@ -208,7 +232,8 @@ template error_code RawInstrProfReader::readNextRecord(InstrProfRecord &Record) { if (Data == DataEnd) - return error(instrprof_error::eof); + if (error_code EC = readNextHeader(ProfileEnd)) + return EC; // Get the raw data. StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize)); -- cgit v1.2.3