[compiler-rt] Add more diagnostic to InstrProfError

If profile data is malformed for any kind of reason, we generate
an error that only reports "malformed instrumentation profile data"
without any further information. This patch extends InstrProfError
class to receive an optional error message argument, so that we can
do better error reporting.

Differential Revision: https://reviews.llvm.org/D108942
This commit is contained in:
Gulfem Savrun Yeniceri 2021-08-30 19:12:16 +00:00
parent 1e78d5d008
commit ee88b8d63e
9 changed files with 241 additions and 60 deletions

View File

@ -308,7 +308,8 @@ inline std::error_code make_error_code(instrprof_error E) {
class InstrProfError : public ErrorInfo<InstrProfError> { class InstrProfError : public ErrorInfo<InstrProfError> {
public: public:
InstrProfError(instrprof_error Err) : Err(Err) { InstrProfError(instrprof_error Err, const Twine &ErrStr = Twine())
: Err(Err), Msg(ErrStr.str()) {
assert(Err != instrprof_error::success && "Not an error"); assert(Err != instrprof_error::success && "Not an error");
} }
@ -321,6 +322,7 @@ public:
} }
instrprof_error get() const { return Err; } instrprof_error get() const { return Err; }
const std::string &getMessage() const { return Msg; }
/// Consume an Error and return the raw enum value contained within it. The /// Consume an Error and return the raw enum value contained within it. The
/// Error must either be a success value, or contain a single InstrProfError. /// Error must either be a success value, or contain a single InstrProfError.
@ -337,6 +339,7 @@ public:
private: private:
instrprof_error Err; instrprof_error Err;
std::string Msg;
}; };
class SoftInstrProfErrors { class SoftInstrProfErrors {
@ -474,7 +477,8 @@ public:
/// is used by the raw and text profile readers. /// is used by the raw and text profile readers.
Error addFuncName(StringRef FuncName) { Error addFuncName(StringRef FuncName) {
if (FuncName.empty()) if (FuncName.empty())
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(instrprof_error::malformed,
"function name is empty");
auto Ins = NameTab.insert(FuncName); auto Ins = NameTab.insert(FuncName);
if (Ins.second) { if (Ins.second) {
MD5NameMap.push_back(std::make_pair( MD5NameMap.push_back(std::make_pair(

View File

@ -71,6 +71,7 @@ public:
/// format. Provides an iterator over NamedInstrProfRecords. /// format. Provides an iterator over NamedInstrProfRecords.
class InstrProfReader { class InstrProfReader {
instrprof_error LastError = instrprof_error::success; instrprof_error LastError = instrprof_error::success;
std::string LastErrorMsg;
public: public:
InstrProfReader() = default; InstrProfReader() = default;
@ -114,14 +115,21 @@ protected:
std::unique_ptr<InstrProfSymtab> Symtab; std::unique_ptr<InstrProfSymtab> Symtab;
/// Set the current error and return same. /// Set the current error and return same.
Error error(instrprof_error Err) { Error error(instrprof_error Err, const std::string &ErrMsg = "") {
LastError = Err; LastError = Err;
LastErrorMsg = ErrMsg;
if (Err == instrprof_error::success) if (Err == instrprof_error::success)
return Error::success(); return Error::success();
return make_error<InstrProfError>(Err); return make_error<InstrProfError>(Err, ErrMsg);
} }
Error error(Error &&E) { return error(InstrProfError::take(std::move(E))); } Error error(Error &&E) {
handleAllErrors(std::move(E), [&](const InstrProfError &IPE) {
LastError = IPE.get();
LastErrorMsg = IPE.getMessage();
});
return make_error<InstrProfError>(LastError, LastErrorMsg);
}
/// Clear the current error and return a successful one. /// Clear the current error and return a successful one.
Error success() { return error(instrprof_error::success); } Error success() { return error(instrprof_error::success); }
@ -136,7 +144,7 @@ public:
/// Get the current error. /// Get the current error.
Error getError() { Error getError() {
if (hasError()) if (hasError())
return make_error<InstrProfError>(LastError); return make_error<InstrProfError>(LastError, LastErrorMsg);
return Error::success(); return Error::success();
} }

View File

@ -567,7 +567,8 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName)) if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName))
return Err; return Err;
if (FuncName.empty()) if (FuncName.empty())
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(instrprof_error::malformed,
"function name is empty");
++CovMapNumUsedRecords; ++CovMapNumUsedRecords;
Records.emplace_back(Version, FuncName, FuncHash, Mapping, Records.emplace_back(Version, FuncName, FuncHash, Mapping,
FileRange.StartingIndex, FileRange.Length); FileRange.StartingIndex, FileRange.Length);

View File

@ -74,53 +74,85 @@ static cl::opt<unsigned> StaticFuncStripDirNamePrefix(
cl::desc("Strip specified level of directory name from source path in " cl::desc("Strip specified level of directory name from source path in "
"the profile counter name for static functions.")); "the profile counter name for static functions."));
static std::string getInstrProfErrString(instrprof_error Err) { static std::string getInstrProfErrString(instrprof_error Err,
const std::string &ErrMsg = "") {
std::string Msg;
raw_string_ostream OS(Msg);
switch (Err) { switch (Err) {
case instrprof_error::success: case instrprof_error::success:
return "success"; OS << "success";
break;
case instrprof_error::eof: case instrprof_error::eof:
return "end of File"; OS << "end of File";
break;
case instrprof_error::unrecognized_format: case instrprof_error::unrecognized_format:
return "unrecognized instrumentation profile encoding format"; OS << "unrecognized instrumentation profile encoding format";
break;
case instrprof_error::bad_magic: case instrprof_error::bad_magic:
return "invalid instrumentation profile data (bad magic)"; OS << "invalid instrumentation profile data (bad magic)";
break;
case instrprof_error::bad_header: case instrprof_error::bad_header:
return "invalid instrumentation profile data (file header is corrupt)"; OS << "invalid instrumentation profile data (file header is corrupt)";
break;
case instrprof_error::unsupported_version: case instrprof_error::unsupported_version:
return "unsupported instrumentation profile format version"; OS << "unsupported instrumentation profile format version";
break;
case instrprof_error::unsupported_hash_type: case instrprof_error::unsupported_hash_type:
return "unsupported instrumentation profile hash type"; OS << "unsupported instrumentation profile hash type";
break;
case instrprof_error::too_large: case instrprof_error::too_large:
return "too much profile data"; OS << "too much profile data";
break;
case instrprof_error::truncated: case instrprof_error::truncated:
return "truncated profile data"; OS << "truncated profile data";
break;
case instrprof_error::malformed: case instrprof_error::malformed:
return "malformed instrumentation profile data"; OS << "malformed instrumentation profile data";
break;
case instrprof_error::invalid_prof: case instrprof_error::invalid_prof:
return "invalid profile created. Please file a bug " OS << "invalid profile created. Please file a bug "
"at: " BUG_REPORT_URL "at: " BUG_REPORT_URL
" and include the profraw files that caused this error."; " and include the profraw files that caused this error.";
break;
case instrprof_error::unknown_function: case instrprof_error::unknown_function:
return "no profile data available for function"; OS << "no profile data available for function";
break;
case instrprof_error::hash_mismatch: case instrprof_error::hash_mismatch:
return "function control flow change detected (hash mismatch)"; OS << "function control flow change detected (hash mismatch)";
break;
case instrprof_error::count_mismatch: case instrprof_error::count_mismatch:
return "function basic block count change detected (counter mismatch)"; OS << "function basic block count change detected (counter mismatch)";
break;
case instrprof_error::counter_overflow: case instrprof_error::counter_overflow:
return "counter overflow"; OS << "counter overflow";
break;
case instrprof_error::value_site_count_mismatch: case instrprof_error::value_site_count_mismatch:
return "function value site count change detected (counter mismatch)"; OS << "function value site count change detected (counter mismatch)";
break;
case instrprof_error::compress_failed: case instrprof_error::compress_failed:
return "failed to compress data (zlib)"; OS << "failed to compress data (zlib)";
break;
case instrprof_error::uncompress_failed: case instrprof_error::uncompress_failed:
return "failed to uncompress data (zlib)"; OS << "failed to uncompress data (zlib)";
break;
case instrprof_error::empty_raw_profile: case instrprof_error::empty_raw_profile:
return "empty raw profile file"; OS << "empty raw profile file";
break;
case instrprof_error::zlib_unavailable: case instrprof_error::zlib_unavailable:
return "profile uses zlib compression but the profile reader was built " OS << "profile uses zlib compression but the profile reader was built "
"without zlib support"; "without zlib support";
break;
default:
llvm_unreachable("A value of instrprof_error has no message.");
break;
} }
llvm_unreachable("A value of instrprof_error has no message.");
// If optional error message is not empty, append it to the message.
if (!ErrMsg.empty())
OS << ": '" << ErrMsg << "'";
return OS.str();
} }
namespace { namespace {
@ -217,7 +249,7 @@ void SoftInstrProfErrors::addError(instrprof_error IE) {
} }
std::string InstrProfError::message() const { std::string InstrProfError::message() const {
return getInstrProfErrString(Err); return getInstrProfErrString(Err, Msg);
} }
char InstrProfError::ID = 0; char InstrProfError::ID = 0;
@ -878,18 +910,23 @@ static std::unique_ptr<ValueProfData> allocValueProfData(uint32_t TotalSize) {
Error ValueProfData::checkIntegrity() { Error ValueProfData::checkIntegrity() {
if (NumValueKinds > IPVK_Last + 1) if (NumValueKinds > IPVK_Last + 1)
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(
// Total size needs to be mulltiple of quadword size. instrprof_error::malformed, "number of value profile kinds is invalid");
// Total size needs to be multiple of quadword size.
if (TotalSize % sizeof(uint64_t)) if (TotalSize % sizeof(uint64_t))
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(
instrprof_error::malformed, "total size is not multiples of quardword");
ValueProfRecord *VR = getFirstValueProfRecord(this); ValueProfRecord *VR = getFirstValueProfRecord(this);
for (uint32_t K = 0; K < this->NumValueKinds; K++) { for (uint32_t K = 0; K < this->NumValueKinds; K++) {
if (VR->Kind > IPVK_Last) if (VR->Kind > IPVK_Last)
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(instrprof_error::malformed,
"value kind is invalid");
VR = getValueProfRecordNext(VR); VR = getValueProfRecordNext(VR);
if ((char *)VR - (char *)this > (ptrdiff_t)TotalSize) if ((char *)VR - (char *)this > (ptrdiff_t)TotalSize)
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(
instrprof_error::malformed,
"value profile address is greater than total size");
} }
return Error::success(); return Error::success();
} }

View File

@ -204,13 +204,15 @@ TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
return success(); return success();
} }
if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1) if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
return error(instrprof_error::malformed); return error(instrprof_error::malformed,
"number of value kinds is invalid");
Line++; Line++;
for (uint32_t VK = 0; VK < NumValueKinds; VK++) { for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
VP_READ_ADVANCE(ValueKind); VP_READ_ADVANCE(ValueKind);
if (ValueKind > IPVK_Last) if (ValueKind > IPVK_Last)
return error(instrprof_error::malformed); return error(instrprof_error::malformed, "value kind is invalid");
;
VP_READ_ADVANCE(NumValueSites); VP_READ_ADVANCE(NumValueSites);
if (!NumValueSites) if (!NumValueSites)
continue; continue;
@ -268,16 +270,18 @@ Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
if (Line.is_at_end()) if (Line.is_at_end())
return error(instrprof_error::truncated); return error(instrprof_error::truncated);
if ((Line++)->getAsInteger(0, Record.Hash)) if ((Line++)->getAsInteger(0, Record.Hash))
return error(instrprof_error::malformed); return error(instrprof_error::malformed,
"function hash is not a valid integer");
// Read the number of counters. // Read the number of counters.
uint64_t NumCounters; uint64_t NumCounters;
if (Line.is_at_end()) if (Line.is_at_end())
return error(instrprof_error::truncated); return error(instrprof_error::truncated);
if ((Line++)->getAsInteger(10, NumCounters)) if ((Line++)->getAsInteger(10, NumCounters))
return error(instrprof_error::malformed); return error(instrprof_error::malformed,
"number of counters is not a valid integer");
if (NumCounters == 0) if (NumCounters == 0)
return error(instrprof_error::malformed); return error(instrprof_error::malformed, "number of counters is zero");
// Read each counter and fill our internal storage with the values. // Read each counter and fill our internal storage with the values.
Record.Clear(); Record.Clear();
@ -287,7 +291,7 @@ Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
return error(instrprof_error::truncated); return error(instrprof_error::truncated);
uint64_t Count; uint64_t Count;
if ((Line++)->getAsInteger(10, Count)) if ((Line++)->getAsInteger(10, Count))
return error(instrprof_error::malformed); return error(instrprof_error::malformed, "count is invalid");
Record.Counts.push_back(Count); Record.Counts.push_back(Count);
} }
@ -332,10 +336,12 @@ Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
// If there isn't enough space for another header, this is probably just // If there isn't enough space for another header, this is probably just
// garbage at the end of the file. // garbage at the end of the file.
if (CurrentPos + sizeof(RawInstrProf::Header) > End) if (CurrentPos + sizeof(RawInstrProf::Header) > End)
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(instrprof_error::malformed,
"not enough space for another header");
// The writer ensures each profile is padded to start at an aligned address. // The writer ensures each profile is padded to start at an aligned address.
if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t)) if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t))
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(instrprof_error::malformed,
"insufficient padding");
// The magic should have the same byte order as in the previous header. // The magic should have the same byte order as in the previous header.
uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos); uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
if (Magic != swap(RawInstrProf::getMagic<IntPtrT>())) if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
@ -433,17 +439,18 @@ template <class IntPtrT>
Error RawInstrProfReader<IntPtrT>::readRawCounts( Error RawInstrProfReader<IntPtrT>::readRawCounts(
InstrProfRecord &Record) { InstrProfRecord &Record) {
uint32_t NumCounters = swap(Data->NumCounters); uint32_t NumCounters = swap(Data->NumCounters);
IntPtrT CounterPtr = Data->CounterPtr;
if (NumCounters == 0) if (NumCounters == 0)
return error(instrprof_error::malformed); return error(instrprof_error::malformed, "number of counters is zero");
IntPtrT CounterPtr = Data->CounterPtr;
auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart); auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
ptrdiff_t MaxNumCounters = NamesStartAsCounter - CountersStart; ptrdiff_t MaxNumCounters = NamesStartAsCounter - CountersStart;
// Check bounds. Note that the counter pointer embedded in the data record // Check bounds. Note that the counter pointer embedded in the data record
// may itself be corrupt. // may itself be corrupt.
if (MaxNumCounters < 0 || NumCounters > (uint32_t)MaxNumCounters) if (MaxNumCounters < 0 || NumCounters > (uint32_t)MaxNumCounters)
return error(instrprof_error::malformed); return error(instrprof_error::malformed,
"counter pointer is out of bounds");
// We need to compute the in-buffer counter offset from the in-memory address // We need to compute the in-buffer counter offset from the in-memory address
// distance. The initial CountersDelta is the in-memory address difference // distance. The initial CountersDelta is the in-memory address difference
@ -453,9 +460,26 @@ Error RawInstrProfReader<IntPtrT>::readRawCounts(
// CountersDelta decreases as we advance to the next data record. // CountersDelta decreases as we advance to the next data record.
ptrdiff_t CounterOffset = getCounterOffset(CounterPtr); ptrdiff_t CounterOffset = getCounterOffset(CounterPtr);
CountersDelta -= sizeof(*Data); CountersDelta -= sizeof(*Data);
if (CounterOffset < 0 || CounterOffset > MaxNumCounters || if (CounterOffset < 0)
((uint32_t)CounterOffset + NumCounters) > (uint32_t)MaxNumCounters) return error(
return error(instrprof_error::malformed); instrprof_error::malformed,
("counter offset(" + Twine(CounterOffset) + ")" + " is < 0").str());
if (CounterOffset > MaxNumCounters)
return error(instrprof_error::malformed,
("counter offset(" + Twine(CounterOffset) + ")" + " > " +
"max number of counters(" + Twine((uint32_t)MaxNumCounters) +
")")
.str());
if (((uint32_t)CounterOffset + NumCounters) > (uint32_t)MaxNumCounters)
return error(instrprof_error::malformed,
("number of counters is out of bounds(counter offset(" +
Twine((uint32_t)CounterOffset) + ") + " +
"number of counters(" + Twine(NumCounters) + ") > " +
"max number of counters(" + Twine((uint32_t)MaxNumCounters) +
"))")
.str());
auto RawCounts = makeArrayRef(getCounter(CounterOffset), NumCounters); auto RawCounts = makeArrayRef(getCounter(CounterOffset), NumCounters);
@ -544,19 +568,24 @@ Error RawInstrProfReader<IntPtrT>::printBinaryIds(raw_ostream &OS) {
// There should be enough left to read the binary ID size field. // There should be enough left to read the binary ID size field.
if (Remaining < sizeof(uint64_t)) if (Remaining < sizeof(uint64_t))
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(
instrprof_error::malformed,
"not enough data to read binary id length");
uint64_t BinaryIdLen = swap(*reinterpret_cast<const uint64_t *>(BI)); uint64_t BinaryIdLen = swap(*reinterpret_cast<const uint64_t *>(BI));
// There should be enough left to read the binary ID size field, and the // There should be enough left to read the binary ID size field, and the
// binary ID. // binary ID.
if (Remaining < sizeof(BinaryIdLen) + BinaryIdLen) if (Remaining < sizeof(BinaryIdLen) + BinaryIdLen)
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(
instrprof_error::malformed, "not enough data to read binary id data");
// Increment by binary id length data type size. // Increment by binary id length data type size.
BI += sizeof(BinaryIdLen); BI += sizeof(BinaryIdLen);
if (BI > (const uint8_t *)DataBuffer->getBufferEnd()) if (BI > (const uint8_t *)DataBuffer->getBufferEnd())
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(
instrprof_error::malformed,
"binary id that is read is bigger than buffer size");
for (uint64_t I = 0; I < BinaryIdLen; I++) for (uint64_t I = 0; I < BinaryIdLen; I++)
OS << format("%02x", BI[I]); OS << format("%02x", BI[I]);
@ -657,7 +686,8 @@ Error InstrProfReaderIndex<HashTableImpl>::getRecords(
Data = (*Iter); Data = (*Iter);
if (Data.empty()) if (Data.empty())
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(instrprof_error::malformed,
"profile data is empty");
return Error::success(); return Error::success();
} }
@ -671,7 +701,8 @@ Error InstrProfReaderIndex<HashTableImpl>::getRecords(
Data = *RecordIterator; Data = *RecordIterator;
if (Data.empty()) if (Data.empty())
return make_error<InstrProfError>(instrprof_error::malformed); return make_error<InstrProfError>(instrprof_error::malformed,
"profile data is empty");
return Error::success(); return Error::success();
} }
@ -702,7 +733,7 @@ public:
return Underlying.getRecords(FuncName, Data); return Underlying.getRecords(FuncName, Data);
} }
}; };
} } // namespace
/// A remapper that applies remappings based on a symbol remapping file. /// A remapper that applies remappings based on a symbol remapping file.
template <typename HashTableImpl> template <typename HashTableImpl>

View File

@ -17,4 +17,4 @@ RUN: printf '\0\1\2\3\4\5\6\7' >> %t.profraw
RUN: printf '\0\1\2\3\0\0\0\0' >> %t.profraw RUN: printf '\0\1\2\3\0\0\0\0' >> %t.profraw
// RUN: not llvm-profdata show --binary-ids %t.profraw 2>&1 | FileCheck %s // RUN: not llvm-profdata show --binary-ids %t.profraw 2>&1 | FileCheck %s
// CHECK: malformed instrumentation profile data // CHECK: malformed instrumentation profile data: 'not enough data to read binary id data'

View File

@ -0,0 +1,51 @@
// Header
//
// 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, BinaryIdsSize, __llvm_write_binary_ids(NULL))
// INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize)
// INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize)
// INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
// INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
RUN: printf '\201rforpl\377' > %t.profraw
RUN: printf '\x8\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\xe\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\xf8\xff\xff\xff\xff\xff\xff\xff' >> %t.profraw
RUN: printf '\x89\x7a\x40\x00\x00\x00\x00\x00' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
// Data Section
//
// struct ProfData {
// #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
// Type Name;
// #include "llvm/ProfileData/InstrProfData.inc"
// };
RUN: printf '\xfa\xd5\x8d\xe7\x36\x64\x95\xdb' >> %t.profraw // NameRef
RUN: printf '\x18\0\0\0\0\0\0\0' >> %t.profraw // FuncHash
RUN: printf '\xf8\xff\xff\xff\xff\xff\xff\xff' >> %t.profraw // RelativeCounterPtr
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw // FunctionPointer
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw // Values
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw // NumCounters and NumValueSites
// Counter section
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
// Name section (Name section is 14 bytes and 2 bytes padding is added)
RUN: printf '\x04\x0c\x78\xda\xcb\x4d\xcc\xcc' >> %t.profraw
RUN: printf '\x03\x00\x04\x1b\x01\xa6\x00\x00' >> %t.profraw
// Write some garbage data at the end so we get "not enough space for another header" message
RUN: printf '\x03\x00\' >> %t.profraw
RUN: not llvm-profdata show %t.profraw 2>&1 | FileCheck %s
CHECK: malformed instrumentation profile data: 'not enough space for another header'

View File

@ -0,0 +1,49 @@
// Header
//
// 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, BinaryIdsSize, __llvm_write_binary_ids(NULL))
// INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize)
// INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize)
// INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
// INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
// INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
RUN: printf '\201rforpl\377' > %t.profraw
RUN: printf '\x8\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\xe\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\xf8\xff\xff\xff\xff\xff\xff\xff' >> %t.profraw
RUN: printf '\x89\x7a\x40\x00\x00\x00\x00\x00' >> %t.profraw
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
// Data Section
//
// struct ProfData {
// #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
// Type Name;
// #include "llvm/ProfileData/InstrProfData.inc"
// };
RUN: printf '\xfa\xd5\x8d\xe7\x36\x64\x95\xdb' >> %t.profraw // NameRef
RUN: printf '\x18\0\0\0\0\0\0\0' >> %t.profraw // FuncHash
RUN: printf '\xf8\xff\xff\xff\xff\xff\xff\xff' >> %t.profraw // RelativeCounterPtr
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw // FunctionPointer
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw // Values
// Make NumCounters = 0 so that we get "number of counters is zero" error message
RUN: printf '\0\0\0\0\0\0\0\0' >> %t.profraw // NumCounters and NumValueSites
// Counter section
RUN: printf '\1\0\0\0\0\0\0\0' >> %t.profraw
// Name section (Name section is 14 bytes and 2 bytes padding is added)
RUN: printf '\x04\x0c\x78\xda\xcb\x4d\xcc\xcc' >> %t.profraw
RUN: printf '\x03\x00\x04\x1b\x01\xa6\x00\x00' >> %t.profraw
RUN: not llvm-profdata show %t.profraw 2>&1 | FileCheck %s
CHECK: malformed instrumentation profile data: 'number of counters is zero'

View File

@ -53,5 +53,5 @@ RUN: printf '\101\0\0\0\0\0\0\0' >> %t.profraw
RUN: printf '\3\0bar\0\0\0' >> %t.profraw RUN: printf '\3\0bar\0\0\0' >> %t.profraw
RUN: not llvm-profdata merge -o /dev/null %t.profraw 2>&1 | FileCheck %s RUN: not llvm-profdata merge -o /dev/null %t.profraw 2>&1 | FileCheck %s
CHECK: warning: {{.+}}: malformed instrumentation profile data CHECK: warning: {{.+}}: malformed instrumentation profile data: 'number of counters is out of bounds(counter offset(1) + number of counters(2) > max number of counters(2))'
CHECK: error: no profile can be merged CHECK: error: no profile can be merged