diff --git a/compiler-rt/include/profile/InstrProfData.inc b/compiler-rt/include/profile/InstrProfData.inc --- a/compiler-rt/include/profile/InstrProfData.inc +++ b/compiler-rt/include/profile/InstrProfData.inc @@ -129,6 +129,7 @@ #endif INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic()) INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version()) +INSTR_PROF_RAW_HEADER(uint64_t, HasBinaryId, 0) // TODO: Can use a bool? INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize) INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesBeforeCounters, PaddingBytesBeforeCounters) INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize) diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h --- a/compiler-rt/lib/profile/InstrProfiling.h +++ b/compiler-rt/lib/profile/InstrProfiling.h @@ -92,6 +92,14 @@ ValueProfNode *__llvm_profile_end_vnodes(); uint32_t *__llvm_profile_begin_orderfile(); +/*! + * \brief Reads binary id. + * + * If binary id exists, returns it and sets its size. + * Othwerwise, returns null. + */ +const uint8_t *__llvm_read_binary_id(uint32_t *Size); + /*! * \brief Clear profile counters to zero. * diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c --- a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c +++ b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c @@ -9,6 +9,8 @@ #if defined(__linux__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ (defined(__sun__) && defined(__svr4__)) || defined(__NetBSD__) +#include +#include #include #include "InstrProfiling.h" @@ -72,4 +74,48 @@ COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &PROF_VNODES_START; COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &PROF_VNODES_STOP; +static size_t RoundUp(size_t size, size_t align) { + return (size + align - 1) & ~(align - 1); +} + +/* Returns build id and sets it size. + * ELF file format has optional unique build id that can be used as binary id + */ +COMPILER_RT_VISIBILITY const uint8_t *__llvm_read_binary_id(uint32_t *Size) { + extern const ElfW(Ehdr) __ehdr_start __attribute__((visibility("hidden"))); + const ElfW(Ehdr) *ElfHeader = &__ehdr_start; + const ElfW(Phdr) *ProgramHeader = + (const ElfW(Phdr) *)((uintptr_t)ElfHeader + ElfHeader->e_phoff); + + uint32_t i; + /* Iterate through entries in the program header. */ + for (i = 0; i < ElfHeader->e_phnum; i++) { + /* Look for the note section in program header entries. */ + if (ProgramHeader[i].p_type != PT_NOTE) + continue; + + const ElfW(Nhdr) *Note = + (const ElfW(Nhdr) *)((uintptr_t)ElfHeader + ProgramHeader[i].p_offset); + const ElfW(Nhdr) *NotesEnd = Note + ProgramHeader[i].p_filesz; + + while (Note < NotesEnd) { + /* Look for the NT_GNU_BUILD_ID type in note section. */ + if (Note->n_type != NT_GNU_BUILD_ID) { + Note = Note + sizeof(ElfW(Nhdr)) + RoundUp(Note->n_namesz, 4) + + RoundUp(Note->n_descsz, 4); + continue; + } + *Size = Note->n_descsz; + uint8_t *Data = + (uint8_t *)((uintptr_t)Note + sizeof(ElfW(Nhdr)) + Note->n_namesz); + return Data; + } + + /* If build id does not exist, stop reading entries in program header. */ + break; + } + + return NULL; +} + #endif diff --git a/compiler-rt/lib/profile/InstrProfilingWriter.c b/compiler-rt/lib/profile/InstrProfilingWriter.c --- a/compiler-rt/lib/profile/InstrProfilingWriter.c +++ b/compiler-rt/lib/profile/InstrProfilingWriter.c @@ -283,6 +283,13 @@ #define INSTR_PROF_RAW_HEADER(Type, Name, Init) Header.Name = Init; #include "profile/InstrProfData.inc" + uint32_t BinaryIdSize = 0; + uint32_t *BinaryIdSizePtr = &BinaryIdSize; + const uint8_t *BinaryId = __llvm_read_binary_id(BinaryIdSizePtr); + + if (BinaryId) + Header.HasBinaryId = 1; + /* Write the data. */ ProfDataIOVec IOVec[] = { {&Header, sizeof(__llvm_profile_header), 1, 0}, @@ -299,5 +306,16 @@ if (__llvm_profile_is_continuous_mode_enabled()) return 0; - return writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd); + if (writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd)) + return -1; + + if (!BinaryId) + return 0; + + /* Write binary id size and data. */ + ProfDataIOVec BinaryIdIOVec[] = { + {BinaryIdSizePtr, sizeof(uint32_t), 1, 0}, + {BinaryId, sizeof(uint8_t), *BinaryIdSizePtr, 0}}; + return Writer->Write(Writer, BinaryIdIOVec, + sizeof(BinaryIdIOVec) / sizeof(*BinaryIdIOVec)); } diff --git a/llvm/include/llvm/ProfileData/InstrProfData.inc b/llvm/include/llvm/ProfileData/InstrProfData.inc --- a/llvm/include/llvm/ProfileData/InstrProfData.inc +++ b/llvm/include/llvm/ProfileData/InstrProfData.inc @@ -129,6 +129,7 @@ #endif INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic()) INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version()) +INSTR_PROF_RAW_HEADER(uint64_t, HasBinaryId, 0) // TODO: Can use a bool? INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize) INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesBeforeCounters, PaddingBytesBeforeCounters) INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize) diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h --- a/llvm/include/llvm/ProfileData/InstrProfReader.h +++ b/llvm/include/llvm/ProfileData/InstrProfReader.h @@ -82,6 +82,14 @@ /// Read a single record. virtual Error readNextRecord(NamedInstrProfRecord &Record) = 0; + /// Read binary id. + /// TODO: Consider implementing it as a pure virtual function, + /// and override it every subclass. + virtual Error readBinaryId() { return success(); } + + /// Print binary id on stream OS. + virtual void printBinaryId(raw_ostream &OS){}; + /// Iterator over profile data. InstrProfIterator begin() { return InstrProfIterator(this); } InstrProfIterator end() { return InstrProfIterator(); } @@ -222,6 +230,10 @@ uint32_t ValueKindLast; uint32_t CurValueDataSize; + uint64_t HasBinaryId; // TODO: Can use a bool? + uint32_t BinaryIdSize; + const uint8_t *BinaryId; + public: RawInstrProfReader(std::unique_ptr DataBuffer) : DataBuffer(std::move(DataBuffer)) {} @@ -231,6 +243,8 @@ static bool hasFormat(const MemoryBuffer &DataBuffer); Error readHeader() override; Error readNextRecord(NamedInstrProfRecord &Record) override; + Error readBinaryId() override; + void printBinaryId(raw_ostream &OS) override; bool isIRLevelProfile() const override { return (Version & VARIANT_MASK_IR_PROF) != 0; diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp --- a/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/llvm/lib/ProfileData/InstrProfReader.cpp @@ -24,8 +24,8 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/SymbolRemappingReader.h" #include "llvm/Support/SwapByteOrder.h" +#include "llvm/Support/SymbolRemappingReader.h" #include #include #include @@ -366,6 +366,7 @@ if (GET_VERSION(Version) != RawInstrProf::Version) return error(instrprof_error::unsupported_version); + HasBinaryId = swap(Header.HasBinaryId); CountersDelta = swap(Header.CountersDelta); NamesDelta = swap(Header.NamesDelta); auto DataSize = swap(Header.DataSize); @@ -480,10 +481,16 @@ template Error RawInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) { - if (atEnd()) + if (atEnd()) { + // Read binary id that starts after record. + // TODO: In which cases there are multiple headers? + if (Error E = readBinaryId()) + return error(std::move(E)); + // At this point, ValueDataStart field points to the next header. if (Error E = readNextHeader(getNextHeaderPos())) return error(std::move(E)); + } // Read name ad set it in Record. if (Error E = readName(Record)) @@ -506,6 +513,36 @@ return success(); } +template Error RawInstrProfReader::readBinaryId() { + if (HasBinaryId == 0) + return success(); + + // Read binary id size. + const uint32_t *BinaryIdBuffer = + reinterpret_cast(ValueDataStart); + BinaryIdSize = *BinaryIdBuffer; + BinaryIdBuffer++; + + // Read binary id data. + BinaryId = reinterpret_cast(BinaryIdBuffer); + // Increment next profile start by binary id size and data. + ValueDataStart += sizeof(BinaryIdSize); + ValueDataStart += BinaryIdSize; + + return success(); +} + +template +void RawInstrProfReader::printBinaryId(raw_ostream &OS) { + if (HasBinaryId == 0) + return; + + OS << "Binary ID: "; + for (uint32_t I = 0; I < BinaryIdSize; I++) + OS.write_hex(BinaryId[I]); + OS << "\n"; +} + namespace llvm { template class RawInstrProfReader; diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -2222,6 +2222,9 @@ OS << "Total count: " << PS->getTotalCount() << "\n"; PS->printDetailedSummary(OS); } + + // This is only for testing binary id prototype. + Reader->printBinaryId(OS); return 0; }