Skip to content

Commit f0d74dc

Browse files
gulfemsavrunnikic
authored andcommitted
[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
1 parent f9b03d0 commit f0d74dc

File tree

9 files changed

+255
-57
lines changed

9 files changed

+255
-57
lines changed

llvm/include/llvm/ProfileData/InstrProf.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,8 @@ inline std::error_code make_error_code(instrprof_error E) {
308308

309309
class InstrProfError : public ErrorInfo<InstrProfError> {
310310
public:
311-
InstrProfError(instrprof_error Err) : Err(Err) {
311+
InstrProfError(instrprof_error Err, const Twine &ErrStr = Twine())
312+
: Err(Err), Msg(ErrStr.str()) {
312313
assert(Err != instrprof_error::success && "Not an error");
313314
}
314315

@@ -321,6 +322,7 @@ class InstrProfError : public ErrorInfo<InstrProfError> {
321322
}
322323

323324
instrprof_error get() const { return Err; }
325+
const std::string &getMessage() const { return Msg; }
324326

325327
/// Consume an Error and return the raw enum value contained within it. The
326328
/// Error must either be a success value, or contain a single InstrProfError.
@@ -337,6 +339,7 @@ class InstrProfError : public ErrorInfo<InstrProfError> {
337339

338340
private:
339341
instrprof_error Err;
342+
std::string Msg;
340343
};
341344

342345
class SoftInstrProfErrors {
@@ -474,7 +477,8 @@ class InstrProfSymtab {
474477
/// is used by the raw and text profile readers.
475478
Error addFuncName(StringRef FuncName) {
476479
if (FuncName.empty())
477-
return make_error<InstrProfError>(instrprof_error::malformed);
480+
return make_error<InstrProfError>(instrprof_error::malformed,
481+
"function name is empty");
478482
auto Ins = NameTab.insert(FuncName);
479483
if (Ins.second) {
480484
MD5NameMap.push_back(std::make_pair(

llvm/include/llvm/ProfileData/InstrProfReader.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class InstrProfIterator {
7171
/// format. Provides an iterator over NamedInstrProfRecords.
7272
class InstrProfReader {
7373
instrprof_error LastError = instrprof_error::success;
74+
std::string LastErrorMsg;
7475

7576
public:
7677
InstrProfReader() = default;
@@ -114,14 +115,21 @@ class InstrProfReader {
114115
std::unique_ptr<InstrProfSymtab> Symtab;
115116

116117
/// Set the current error and return same.
117-
Error error(instrprof_error Err) {
118+
Error error(instrprof_error Err, const std::string &ErrMsg = "") {
118119
LastError = Err;
120+
LastErrorMsg = ErrMsg;
119121
if (Err == instrprof_error::success)
120122
return Error::success();
121-
return make_error<InstrProfError>(Err);
123+
return make_error<InstrProfError>(Err, ErrMsg);
122124
}
123125

124-
Error error(Error &&E) { return error(InstrProfError::take(std::move(E))); }
126+
Error error(Error &&E) {
127+
handleAllErrors(std::move(E), [&](const InstrProfError &IPE) {
128+
LastError = IPE.get();
129+
LastErrorMsg = IPE.getMessage();
130+
});
131+
return make_error<InstrProfError>(LastError, LastErrorMsg);
132+
}
125133

126134
/// Clear the current error and return a successful one.
127135
Error success() { return error(instrprof_error::success); }
@@ -136,7 +144,7 @@ class InstrProfReader {
136144
/// Get the current error.
137145
Error getError() {
138146
if (hasError())
139-
return make_error<InstrProfError>(LastError);
147+
return make_error<InstrProfError>(LastError, LastErrorMsg);
140148
return Error::success();
141149
}
142150

llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,8 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
567567
if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName))
568568
return Err;
569569
if (FuncName.empty())
570-
return make_error<InstrProfError>(instrprof_error::malformed);
570+
return make_error<InstrProfError>(instrprof_error::malformed,
571+
"function name is empty");
571572
++CovMapNumUsedRecords;
572573
Records.emplace_back(Version, FuncName, FuncHash, Mapping,
573574
FileRange.StartingIndex, FileRange.Length);

llvm/lib/ProfileData/InstrProf.cpp

Lines changed: 68 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -74,53 +74,85 @@ static cl::opt<unsigned> StaticFuncStripDirNamePrefix(
7474
cl::desc("Strip specified level of directory name from source path in "
7575
"the profile counter name for static functions."));
7676

77-
static std::string getInstrProfErrString(instrprof_error Err) {
77+
static std::string getInstrProfErrString(instrprof_error Err,
78+
const std::string &ErrMsg = "") {
79+
std::string Msg;
80+
raw_string_ostream OS(Msg);
81+
7882
switch (Err) {
7983
case instrprof_error::success:
80-
return "success";
84+
OS << "success";
85+
break;
8186
case instrprof_error::eof:
82-
return "end of File";
87+
OS << "end of File";
88+
break;
8389
case instrprof_error::unrecognized_format:
84-
return "unrecognized instrumentation profile encoding format";
90+
OS << "unrecognized instrumentation profile encoding format";
91+
break;
8592
case instrprof_error::bad_magic:
86-
return "invalid instrumentation profile data (bad magic)";
93+
OS << "invalid instrumentation profile data (bad magic)";
94+
break;
8795
case instrprof_error::bad_header:
88-
return "invalid instrumentation profile data (file header is corrupt)";
96+
OS << "invalid instrumentation profile data (file header is corrupt)";
97+
break;
8998
case instrprof_error::unsupported_version:
90-
return "unsupported instrumentation profile format version";
99+
OS << "unsupported instrumentation profile format version";
100+
break;
91101
case instrprof_error::unsupported_hash_type:
92-
return "unsupported instrumentation profile hash type";
102+
OS << "unsupported instrumentation profile hash type";
103+
break;
93104
case instrprof_error::too_large:
94-
return "too much profile data";
105+
OS << "too much profile data";
106+
break;
95107
case instrprof_error::truncated:
96-
return "truncated profile data";
108+
OS << "truncated profile data";
109+
break;
97110
case instrprof_error::malformed:
98-
return "malformed instrumentation profile data";
111+
OS << "malformed instrumentation profile data";
112+
break;
99113
case instrprof_error::invalid_prof:
100-
return "invalid profile created. Please file a bug "
101-
"at: " BUG_REPORT_URL
102-
" and include the profraw files that caused this error.";
114+
OS << "invalid profile created. Please file a bug "
115+
"at: " BUG_REPORT_URL
116+
" and include the profraw files that caused this error.";
117+
break;
103118
case instrprof_error::unknown_function:
104-
return "no profile data available for function";
119+
OS << "no profile data available for function";
120+
break;
105121
case instrprof_error::hash_mismatch:
106-
return "function control flow change detected (hash mismatch)";
122+
OS << "function control flow change detected (hash mismatch)";
123+
break;
107124
case instrprof_error::count_mismatch:
108-
return "function basic block count change detected (counter mismatch)";
125+
OS << "function basic block count change detected (counter mismatch)";
126+
break;
109127
case instrprof_error::counter_overflow:
110-
return "counter overflow";
128+
OS << "counter overflow";
129+
break;
111130
case instrprof_error::value_site_count_mismatch:
112-
return "function value site count change detected (counter mismatch)";
131+
OS << "function value site count change detected (counter mismatch)";
132+
break;
113133
case instrprof_error::compress_failed:
114-
return "failed to compress data (zlib)";
134+
OS << "failed to compress data (zlib)";
135+
break;
115136
case instrprof_error::uncompress_failed:
116-
return "failed to uncompress data (zlib)";
137+
OS << "failed to uncompress data (zlib)";
138+
break;
117139
case instrprof_error::empty_raw_profile:
118-
return "empty raw profile file";
140+
OS << "empty raw profile file";
141+
break;
119142
case instrprof_error::zlib_unavailable:
120-
return "profile uses zlib compression but the profile reader was built "
121-
"without zlib support";
143+
OS << "profile uses zlib compression but the profile reader was built "
144+
"without zlib support";
145+
break;
146+
default:
147+
llvm_unreachable("A value of instrprof_error has no message.");
148+
break;
122149
}
123-
llvm_unreachable("A value of instrprof_error has no message.");
150+
151+
// If optional error message is not empty, append it to the message.
152+
if (!ErrMsg.empty())
153+
OS << ": '" << ErrMsg << "'";
154+
155+
return OS.str();
124156
}
125157

126158
namespace {
@@ -217,7 +249,7 @@ void SoftInstrProfErrors::addError(instrprof_error IE) {
217249
}
218250

219251
std::string InstrProfError::message() const {
220-
return getInstrProfErrString(Err);
252+
return getInstrProfErrString(Err, Msg);
221253
}
222254

223255
char InstrProfError::ID = 0;
@@ -878,18 +910,23 @@ static std::unique_ptr<ValueProfData> allocValueProfData(uint32_t TotalSize) {
878910

879911
Error ValueProfData::checkIntegrity() {
880912
if (NumValueKinds > IPVK_Last + 1)
881-
return make_error<InstrProfError>(instrprof_error::malformed);
882-
// Total size needs to be mulltiple of quadword size.
913+
return make_error<InstrProfError>(
914+
instrprof_error::malformed, "number of value profile kinds is invalid");
915+
// Total size needs to be multiple of quadword size.
883916
if (TotalSize % sizeof(uint64_t))
884-
return make_error<InstrProfError>(instrprof_error::malformed);
917+
return make_error<InstrProfError>(
918+
instrprof_error::malformed, "total size is not multiples of quardword");
885919

886920
ValueProfRecord *VR = getFirstValueProfRecord(this);
887921
for (uint32_t K = 0; K < this->NumValueKinds; K++) {
888922
if (VR->Kind > IPVK_Last)
889-
return make_error<InstrProfError>(instrprof_error::malformed);
923+
return make_error<InstrProfError>(instrprof_error::malformed,
924+
"value kind is invalid");
890925
VR = getValueProfRecordNext(VR);
891926
if ((char *)VR - (char *)this > (ptrdiff_t)TotalSize)
892-
return make_error<InstrProfError>(instrprof_error::malformed);
927+
return make_error<InstrProfError>(
928+
instrprof_error::malformed,
929+
"value profile address is greater than total size");
893930
}
894931
return Error::success();
895932
}

llvm/lib/ProfileData/InstrProfReader.cpp

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -204,13 +204,15 @@ TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
204204
return success();
205205
}
206206
if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
207-
return error(instrprof_error::malformed);
207+
return error(instrprof_error::malformed,
208+
"number of value kinds is invalid");
208209
Line++;
209210

210211
for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
211212
VP_READ_ADVANCE(ValueKind);
212213
if (ValueKind > IPVK_Last)
213-
return error(instrprof_error::malformed);
214+
return error(instrprof_error::malformed, "value kind is invalid");
215+
;
214216
VP_READ_ADVANCE(NumValueSites);
215217
if (!NumValueSites)
216218
continue;
@@ -268,16 +270,18 @@ Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
268270
if (Line.is_at_end())
269271
return error(instrprof_error::truncated);
270272
if ((Line++)->getAsInteger(0, Record.Hash))
271-
return error(instrprof_error::malformed);
273+
return error(instrprof_error::malformed,
274+
"function hash is not a valid integer");
272275

273276
// Read the number of counters.
274277
uint64_t NumCounters;
275278
if (Line.is_at_end())
276279
return error(instrprof_error::truncated);
277280
if ((Line++)->getAsInteger(10, NumCounters))
278-
return error(instrprof_error::malformed);
281+
return error(instrprof_error::malformed,
282+
"number of counters is not a valid integer");
279283
if (NumCounters == 0)
280-
return error(instrprof_error::malformed);
284+
return error(instrprof_error::malformed, "number of counters is zero");
281285

282286
// Read each counter and fill our internal storage with the values.
283287
Record.Clear();
@@ -287,7 +291,7 @@ Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
287291
return error(instrprof_error::truncated);
288292
uint64_t Count;
289293
if ((Line++)->getAsInteger(10, Count))
290-
return error(instrprof_error::malformed);
294+
return error(instrprof_error::malformed, "count is invalid");
291295
Record.Counts.push_back(Count);
292296
}
293297

@@ -332,10 +336,12 @@ Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
332336
// If there isn't enough space for another header, this is probably just
333337
// garbage at the end of the file.
334338
if (CurrentPos + sizeof(RawInstrProf::Header) > End)
335-
return make_error<InstrProfError>(instrprof_error::malformed);
339+
return make_error<InstrProfError>(instrprof_error::malformed,
340+
"not enough space for another header");
336341
// The writer ensures each profile is padded to start at an aligned address.
337342
if (reinterpret_cast<size_t>(CurrentPos) % alignof(uint64_t))
338-
return make_error<InstrProfError>(instrprof_error::malformed);
343+
return make_error<InstrProfError>(instrprof_error::malformed,
344+
"insufficient padding");
339345
// The magic should have the same byte order as in the previous header.
340346
uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
341347
if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
@@ -426,21 +432,39 @@ template <class IntPtrT>
426432
Error RawInstrProfReader<IntPtrT>::readRawCounts(
427433
InstrProfRecord &Record) {
428434
uint32_t NumCounters = swap(Data->NumCounters);
429-
IntPtrT CounterPtr = Data->CounterPtr;
430435
if (NumCounters == 0)
431-
return error(instrprof_error::malformed);
436+
return error(instrprof_error::malformed, "number of counters is zero");
432437

438+
IntPtrT CounterPtr = Data->CounterPtr;
433439
auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
434440
ptrdiff_t MaxNumCounters = NamesStartAsCounter - CountersStart;
435441

436442
// Check bounds. Note that the counter pointer embedded in the data record
437443
// may itself be corrupt.
438444
if (MaxNumCounters < 0 || NumCounters > (uint32_t)MaxNumCounters)
439-
return error(instrprof_error::malformed);
445+
return error(instrprof_error::malformed,
446+
"counter pointer is out of bounds");
440447
ptrdiff_t CounterOffset = getCounterOffset(CounterPtr);
441-
if (CounterOffset < 0 || CounterOffset > MaxNumCounters ||
442-
((uint32_t)CounterOffset + NumCounters) > (uint32_t)MaxNumCounters)
443-
return error(instrprof_error::malformed);
448+
if (CounterOffset < 0)
449+
return error(
450+
instrprof_error::malformed,
451+
("counter offset(" + Twine(CounterOffset) + ")" + " is < 0").str());
452+
453+
if (CounterOffset > MaxNumCounters)
454+
return error(instrprof_error::malformed,
455+
("counter offset(" + Twine(CounterOffset) + ")" + " > " +
456+
"max number of counters(" + Twine((uint32_t)MaxNumCounters) +
457+
")")
458+
.str());
459+
460+
if (((uint32_t)CounterOffset + NumCounters) > (uint32_t)MaxNumCounters)
461+
return error(instrprof_error::malformed,
462+
("number of counters is out of bounds(counter offset(" +
463+
Twine((uint32_t)CounterOffset) + ") + " +
464+
"number of counters(" + Twine(NumCounters) + ") > " +
465+
"max number of counters(" + Twine((uint32_t)MaxNumCounters) +
466+
"))")
467+
.str());
444468

445469
auto RawCounts = makeArrayRef(getCounter(CounterOffset), NumCounters);
446470

@@ -524,7 +548,9 @@ Error RawInstrProfReader<IntPtrT>::printBinaryIds(raw_ostream &OS) {
524548
// Increment by binary id length data type size.
525549
BI += sizeof(BinaryIdLen);
526550
if (BI > (const uint8_t *)DataBuffer->getBufferEnd())
527-
return make_error<InstrProfError>(instrprof_error::malformed);
551+
return make_error<InstrProfError>(
552+
instrprof_error::malformed,
553+
"binary id that is read is bigger than buffer size");
528554

529555
for (uint64_t I = 0; I < BinaryIdLen; I++)
530556
OS << format("%02x", BI[I]);
@@ -624,7 +650,8 @@ Error InstrProfReaderIndex<HashTableImpl>::getRecords(
624650

625651
Data = (*Iter);
626652
if (Data.empty())
627-
return make_error<InstrProfError>(instrprof_error::malformed);
653+
return make_error<InstrProfError>(instrprof_error::malformed,
654+
"profile data is empty");
628655

629656
return Error::success();
630657
}
@@ -638,7 +665,8 @@ Error InstrProfReaderIndex<HashTableImpl>::getRecords(
638665
Data = *RecordIterator;
639666

640667
if (Data.empty())
641-
return make_error<InstrProfError>(instrprof_error::malformed);
668+
return make_error<InstrProfError>(instrprof_error::malformed,
669+
"profile data is empty");
642670

643671
return Error::success();
644672
}
@@ -669,7 +697,7 @@ class InstrProfReaderNullRemapper : public InstrProfReaderRemapper {
669697
return Underlying.getRecords(FuncName, Data);
670698
}
671699
};
672-
}
700+
} // namespace
673701

674702
/// A remapper that applies remappings based on a symbol remapping file.
675703
template <typename HashTableImpl>

0 commit comments

Comments
 (0)