Skip to content

Commit

Permalink
[compiler-rt] Add more diagnostic to InstrProfError
Browse files Browse the repository at this point in the history
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
  • Loading branch information
gulfemsavrun committed Nov 9, 2021
1 parent 1e78d5d commit ee88b8d
Show file tree
Hide file tree
Showing 9 changed files with 241 additions and 60 deletions.
8 changes: 6 additions & 2 deletions llvm/include/llvm/ProfileData/InstrProf.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,8 @@ inline std::error_code make_error_code(instrprof_error E) {

class InstrProfError : public ErrorInfo<InstrProfError> {
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");
}

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

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
/// Error must either be a success value, or contain a single InstrProfError.
Expand All @@ -337,6 +339,7 @@ class InstrProfError : public ErrorInfo<InstrProfError> {

private:
instrprof_error Err;
std::string Msg;
};

class SoftInstrProfErrors {
Expand Down Expand Up @@ -474,7 +477,8 @@ class InstrProfSymtab {
/// is used by the raw and text profile readers.
Error addFuncName(StringRef FuncName) {
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);
if (Ins.second) {
MD5NameMap.push_back(std::make_pair(
Expand Down
16 changes: 12 additions & 4 deletions llvm/include/llvm/ProfileData/InstrProfReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class InstrProfIterator {
/// format. Provides an iterator over NamedInstrProfRecords.
class InstrProfReader {
instrprof_error LastError = instrprof_error::success;
std::string LastErrorMsg;

public:
InstrProfReader() = default;
Expand Down Expand Up @@ -114,14 +115,21 @@ class InstrProfReader {
std::unique_ptr<InstrProfSymtab> Symtab;

/// Set the current error and return same.
Error error(instrprof_error Err) {
Error error(instrprof_error Err, const std::string &ErrMsg = "") {
LastError = Err;
LastErrorMsg = ErrMsg;
if (Err == instrprof_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.
Error success() { return error(instrprof_error::success); }
Expand All @@ -136,7 +144,7 @@ class InstrProfReader {
/// Get the current error.
Error getError() {
if (hasError())
return make_error<InstrProfError>(LastError);
return make_error<InstrProfError>(LastError, LastErrorMsg);
return Error::success();
}

Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,8 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName))
return Err;
if (FuncName.empty())
return make_error<InstrProfError>(instrprof_error::malformed);
return make_error<InstrProfError>(instrprof_error::malformed,
"function name is empty");
++CovMapNumUsedRecords;
Records.emplace_back(Version, FuncName, FuncHash, Mapping,
FileRange.StartingIndex, FileRange.Length);
Expand Down
99 changes: 68 additions & 31 deletions llvm/lib/ProfileData/InstrProf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,53 +74,85 @@ static cl::opt<unsigned> StaticFuncStripDirNamePrefix(
cl::desc("Strip specified level of directory name from source path in "
"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) {
case instrprof_error::success:
return "success";
OS << "success";
break;
case instrprof_error::eof:
return "end of File";
OS << "end of File";
break;
case instrprof_error::unrecognized_format:
return "unrecognized instrumentation profile encoding format";
OS << "unrecognized instrumentation profile encoding format";
break;
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:
return "invalid instrumentation profile data (file header is corrupt)";
OS << "invalid instrumentation profile data (file header is corrupt)";
break;
case instrprof_error::unsupported_version:
return "unsupported instrumentation profile format version";
OS << "unsupported instrumentation profile format version";
break;
case instrprof_error::unsupported_hash_type:
return "unsupported instrumentation profile hash type";
OS << "unsupported instrumentation profile hash type";
break;
case instrprof_error::too_large:
return "too much profile data";
OS << "too much profile data";
break;
case instrprof_error::truncated:
return "truncated profile data";
OS << "truncated profile data";
break;
case instrprof_error::malformed:
return "malformed instrumentation profile data";
OS << "malformed instrumentation profile data";
break;
case instrprof_error::invalid_prof:
return "invalid profile created. Please file a bug "
"at: " BUG_REPORT_URL
" and include the profraw files that caused this error.";
OS << "invalid profile created. Please file a bug "
"at: " BUG_REPORT_URL
" and include the profraw files that caused this error.";
break;
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:
return "function control flow change detected (hash mismatch)";
OS << "function control flow change detected (hash mismatch)";
break;
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:
return "counter overflow";
OS << "counter overflow";
break;
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:
return "failed to compress data (zlib)";
OS << "failed to compress data (zlib)";
break;
case instrprof_error::uncompress_failed:
return "failed to uncompress data (zlib)";
OS << "failed to uncompress data (zlib)";
break;
case instrprof_error::empty_raw_profile:
return "empty raw profile file";
OS << "empty raw profile file";
break;
case instrprof_error::zlib_unavailable:
return "profile uses zlib compression but the profile reader was built "
"without zlib support";
OS << "profile uses zlib compression but the profile reader was built "
"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 {
Expand Down Expand Up @@ -217,7 +249,7 @@ void SoftInstrProfErrors::addError(instrprof_error IE) {
}

std::string InstrProfError::message() const {
return getInstrProfErrString(Err);
return getInstrProfErrString(Err, Msg);
}

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

Error ValueProfData::checkIntegrity() {
if (NumValueKinds > IPVK_Last + 1)
return make_error<InstrProfError>(instrprof_error::malformed);
// Total size needs to be mulltiple of quadword size.
return make_error<InstrProfError>(
instrprof_error::malformed, "number of value profile kinds is invalid");
// Total size needs to be multiple of quadword size.
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);
for (uint32_t K = 0; K < this->NumValueKinds; K++) {
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);
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();
}
Expand Down
Loading

0 comments on commit ee88b8d

Please sign in to comment.