[llvm] [Coverage] Use the proper endianness for reading profile data fields (PR #136427)

Roman Beliaev via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 19 05:36:48 PDT 2025


https://github.com/belyaevrd created https://github.com/llvm/llvm-project/pull/136427

After running the program compiled with option `--profile-correlate` for big-endian target in qemu, profraw file will be generated in big-endian format. Then when llvm-profdata processes this profraw file on little-endian host, an error occurs due to "malformed instrumentation profile data".

The following happens. When using llvm-profdata to create profdata file, elements for each function are pushed into a vector of per-function profile data structures called `Data`. The elements of `Data` contain profile metadata for the corresponding functions. To complete the elements in correlation mode, the tool refers to debug info or a binary file to obtain the necessary metadata of the corresponding function and then writes this metadata to the element structure in the host endianness. After this, llvm-profdata attempts to read fields of the structure considering the host and profraw file endianness difference. It suggests that this structure was mapped to memory from the profraw file. So, it swaps bytes of the structure's fields and reads it in the wrong endianness.

To fix this, read the `Data` element fields without swapping bytes in correlation mode.

>From 04da5071cb5b54ea5da50b2c23340882d9043e52 Mon Sep 17 00:00:00 2001
From: Roman Beliaev <r.beliaev at ispras.ru>
Date: Sat, 22 Mar 2025 13:10:19 +0300
Subject: [PATCH] [Coverage] Use the proper endianness for reading profile data
 fields

After running the program compiled with option `--profile-correlate` for
big-endian target in qemu, profraw file will be generated in big-endian format.
Then when llvm-profdata processes this profraw file on little-endian host, an
error occurs due to "malformed instrumentation profile data".

The following happens. When using llvm-profdata to create profdata file,
elements for each function are pushed into a vector of per-function profile data
structures called `Data`. The elements of `Data` contain profile metadata for
the corresponding functions. To complete the elements in correlation mode, the
tool refers to debug info or a binary file to obtain the necessary metadata of
the corresponding function and then writes this metadata to the element
structure in the host endianness. After this, llvm-profdata attempts to read
fields of the structure considering the host and profraw file endianness
difference. It suggests that this structure was mapped to memory from the
profraw file. So, it swaps bytes of the structure's fields and reads it in the
wrong endianness.

To fix this, read the `Data` element fields without swapping bytes in
correlation mode.
---
 .../llvm/ProfileData/InstrProfReader.h        |  2 +-
 llvm/lib/ProfileData/InstrProfCorrelator.cpp  |  2 +-
 llvm/lib/ProfileData/InstrProfReader.cpp      | 23 +++++++++++--------
 3 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index f1010b312ee56..2ad27b9925038 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -490,7 +490,7 @@ class RawInstrProfReader : public InstrProfReader {
   }
 
   StringRef getName(uint64_t NameRef) const {
-    return Symtab->getFuncOrVarName(swap(NameRef));
+    return Symtab->getFuncOrVarName(Correlator ? NameRef : swap(NameRef));
   }
 
   int getCounterTypeSize() const {
diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp
index d92107f93dc56..8034cab5bd3f5 100644
--- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp
+++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp
@@ -291,7 +291,7 @@ void InstrProfCorrelatorImpl<IntPtrT>::addDataProbe(uint64_t NameRef,
       maybeSwap<uint64_t>(CFGHash),
       // In this mode, CounterPtr actually stores the section relative address
       // of the counter.
-      maybeSwap<IntPtrT>(CounterOffset),
+      CounterOffset,
       // TODO: MC/DC is not yet supported.
       /*BitmapOffset=*/maybeSwap<IntPtrT>(0),
       maybeSwap<IntPtrT>(FunctionPtr),
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index 4075b513c218d..b2cf592ee69d2 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -553,10 +553,11 @@ Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
                               StringRef(VNamesStart, VNamesEnd - VNamesStart)))
     return error(std::move(E));
   for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
-    const IntPtrT FPtr = swap(I->FunctionPointer);
+    const IntPtrT FPtr =
+        Correlator ? I->FunctionPointer : swap(I->FunctionPointer);
     if (!FPtr)
       continue;
-    Symtab.mapAddress(FPtr, swap(I->NameRef));
+    Symtab.mapAddress(FPtr, Correlator ? I->NameRef : swap(I->NameRef));
   }
 
   if (VTableBegin != nullptr && VTableEnd != nullptr) {
@@ -711,18 +712,20 @@ Error RawInstrProfReader<IntPtrT>::readName(NamedInstrProfRecord &Record) {
 
 template <class IntPtrT>
 Error RawInstrProfReader<IntPtrT>::readFuncHash(NamedInstrProfRecord &Record) {
-  Record.Hash = swap(Data->FuncHash);
+  Record.Hash = Correlator ? Data->FuncHash : swap(Data->FuncHash);
   return success();
 }
 
 template <class IntPtrT>
 Error RawInstrProfReader<IntPtrT>::readRawCounts(
     InstrProfRecord &Record) {
-  uint32_t NumCounters = swap(Data->NumCounters);
+  uint32_t NumCounters =
+      Correlator ? Data->NumCounters : swap(Data->NumCounters);
   if (NumCounters == 0)
     return error(instrprof_error::malformed, "number of counters is zero");
 
-  ptrdiff_t CounterBaseOffset = swap(Data->CounterPtr) - CountersDelta;
+  ptrdiff_t CounterBaseOffset =
+      Correlator ? Data->CounterPtr : swap(Data->CounterPtr) - CountersDelta;
   if (CounterBaseOffset < 0)
     return error(
         instrprof_error::malformed,
@@ -754,8 +757,8 @@ Error RawInstrProfReader<IntPtrT>::readRawCounts(
       uint64_t TimestampValue = swap(*reinterpret_cast<const uint64_t *>(Ptr));
       if (TimestampValue != 0 &&
           TimestampValue != std::numeric_limits<uint64_t>::max()) {
-        TemporalProfTimestamps.emplace_back(TimestampValue,
-                                            swap(Data->NameRef));
+        TemporalProfTimestamps.emplace_back(
+            TimestampValue, Correlator ? Data->NameRef : swap(Data->NameRef));
         TemporalProfTraceStreamSize = 1;
       }
       if (hasSingleByteCoverage()) {
@@ -785,7 +788,8 @@ Error RawInstrProfReader<IntPtrT>::readRawCounts(
 
 template <class IntPtrT>
 Error RawInstrProfReader<IntPtrT>::readRawBitmapBytes(InstrProfRecord &Record) {
-  uint32_t NumBitmapBytes = swap(Data->NumBitmapBytes);
+  uint32_t NumBitmapBytes =
+      Correlator ? Data->NumBitmapBytes : swap(Data->NumBitmapBytes);
 
   Record.BitmapBytes.clear();
   Record.BitmapBytes.reserve(NumBitmapBytes);
@@ -796,7 +800,8 @@ Error RawInstrProfReader<IntPtrT>::readRawBitmapBytes(InstrProfRecord &Record) {
     return success();
 
   // BitmapDelta decreases as we advance to the next data record.
-  ptrdiff_t BitmapOffset = swap(Data->BitmapPtr) - BitmapDelta;
+  ptrdiff_t BitmapOffset =
+      Correlator ? Data->BitmapPtr : swap(Data->BitmapPtr) - BitmapDelta;
   if (BitmapOffset < 0)
     return error(
         instrprof_error::malformed,



More information about the llvm-commits mailing list