diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -308,7 +308,8 @@ class InstrProfError : public ErrorInfo { public: - InstrProfError(instrprof_error Err) : Err(Err) { + InstrProfError(instrprof_error Err, const Twine &ErrStr = "") + : Err(Err), ErrMsg(ErrStr.str()) { assert(Err != instrprof_error::success && "Not an error"); } @@ -321,6 +322,7 @@ } instrprof_error get() const { return Err; } + std::string getErrMsg() const { return ErrMsg; } /// 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. @@ -337,6 +339,7 @@ private: instrprof_error Err; + std::string ErrMsg; }; class SoftInstrProfErrors { @@ -474,7 +477,8 @@ /// is used by the raw and text profile readers. Error addFuncName(StringRef FuncName) { if (FuncName.empty()) - return make_error(instrprof_error::malformed); + return make_error(instrprof_error::malformed, + "Function name is empty"); auto Ins = NameTab.insert(FuncName); if (Ins.second) { MD5NameMap.push_back(std::make_pair( 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 @@ -71,6 +71,7 @@ /// format. Provides an iterator over NamedInstrProfRecords. class InstrProfReader { instrprof_error LastError = instrprof_error::success; + std::string LastErrorMsg; public: InstrProfReader() = default; @@ -114,14 +115,21 @@ std::unique_ptr 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(Err); + return make_error(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.getErrMsg(); + }); + return make_error(LastError, LastErrorMsg); + } /// Clear the current error and return a successful one. Error success() { return error(instrprof_error::success); } @@ -136,7 +144,7 @@ /// Get the current error. Error getError() { if (hasError()) - return make_error(LastError); + return make_error(LastError, LastErrorMsg); return Error::success(); } diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -567,7 +567,9 @@ if (Error Err = CFR->template getFuncName(ProfileNames, FuncName)) return Err; if (FuncName.empty()) - return make_error(instrprof_error::malformed); + return make_error( + instrprof_error::malformed, + "Function name is empty in CovMapFuncRecordReader"); ++CovMapNumUsedRecords; Records.emplace_back(Version, FuncName, FuncHash, Mapping, FileRange.StartingIndex, FileRange.Length); diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -74,53 +74,81 @@ 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 ErrStr; switch (Err) { case instrprof_error::success: - return "success"; + ErrStr = "success"; + break; case instrprof_error::eof: - return "end of File"; + ErrStr = "end of File"; + break; case instrprof_error::unrecognized_format: - return "unrecognized instrumentation profile encoding format"; + ErrStr = "unrecognized instrumentation profile encoding format"; + break; case instrprof_error::bad_magic: - return "invalid instrumentation profile data (bad magic)"; + ErrStr = "invalid instrumentation profile data (bad magic)"; + break; case instrprof_error::bad_header: - return "invalid instrumentation profile data (file header is corrupt)"; + ErrStr = "invalid instrumentation profile data (file header is corrupt)"; + break; case instrprof_error::unsupported_version: - return "unsupported instrumentation profile format version"; + ErrStr = "unsupported instrumentation profile format version"; + break; case instrprof_error::unsupported_hash_type: - return "unsupported instrumentation profile hash type"; + ErrStr = "unsupported instrumentation profile hash type"; + break; case instrprof_error::too_large: - return "too much profile data"; + ErrStr = "too much profile data"; + break; case instrprof_error::truncated: - return "truncated profile data"; + ErrStr = "truncated profile data"; + break; case instrprof_error::malformed: - return "malformed instrumentation profile data"; + ErrStr = "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."; + ErrStr = "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"; + ErrStr = "no profile data available for function"; + break; case instrprof_error::hash_mismatch: - return "function control flow change detected (hash mismatch)"; + ErrStr = "function control flow change detected (hash mismatch)"; + break; case instrprof_error::count_mismatch: - return "function basic block count change detected (counter mismatch)"; + ErrStr = "function basic block count change detected (counter mismatch)"; + break; case instrprof_error::counter_overflow: - return "counter overflow"; + ErrStr = "counter overflow"; + break; case instrprof_error::value_site_count_mismatch: - return "function value site count change detected (counter mismatch)"; + ErrStr = "function value site count change detected (counter mismatch)"; + break; case instrprof_error::compress_failed: - return "failed to compress data (zlib)"; + ErrStr = "failed to compress data (zlib)"; + break; case instrprof_error::uncompress_failed: - return "failed to uncompress data (zlib)"; + ErrStr = "failed to uncompress data (zlib)"; + break; case instrprof_error::empty_raw_profile: - return "empty raw profile file"; + ErrStr = "empty raw profile file"; + break; case instrprof_error::zlib_unavailable: - return "profile uses zlib compression but the profile reader was built " - "without zlib support"; + ErrStr = "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 (!ErrMsg.empty()) + ErrStr = ErrStr + " (" + ErrMsg + ")"; + return ErrStr; } namespace { @@ -217,7 +245,7 @@ } std::string InstrProfError::message() const { - return getInstrProfErrString(Err); + return getInstrProfErrString(Err, ErrMsg); } char InstrProfError::ID = 0; @@ -878,18 +906,26 @@ Error ValueProfData::checkIntegrity() { if (NumValueKinds > IPVK_Last + 1) - return make_error(instrprof_error::malformed); + return make_error( + instrprof_error::malformed, + "Integrity check failure: Number of value profile kinds is corrupted"); // Total size needs to be mulltiple of quadword size. if (TotalSize % sizeof(uint64_t)) - return make_error(instrprof_error::malformed); + return make_error( + instrprof_error::malformed, + "Integrity check failure: Value profile data total size is corrupted"); ValueProfRecord *VR = getFirstValueProfRecord(this); for (uint32_t K = 0; K < this->NumValueKinds; K++) { if (VR->Kind > IPVK_Last) - return make_error(instrprof_error::malformed); + return make_error( + instrprof_error::malformed, + "Integrity check failure: Value kind is corrupted"); VR = getValueProfRecordNext(VR); if ((char *)VR - (char *)this > (ptrdiff_t)TotalSize) - return make_error(instrprof_error::malformed); + return make_error( + instrprof_error::malformed, + "Integrity check failure: Value profile record is corrupted"); } return Error::success(); } 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 @@ -204,13 +204,15 @@ return success(); } if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1) - return error(instrprof_error::malformed); + return error(instrprof_error::malformed, + "Number of value kinds is corrupted"); Line++; for (uint32_t VK = 0; VK < NumValueKinds; VK++) { VP_READ_ADVANCE(ValueKind); if (ValueKind > IPVK_Last) - return error(instrprof_error::malformed); + return error(instrprof_error::malformed, "Value kind is corrupted"); + ; VP_READ_ADVANCE(NumValueSites); if (!NumValueSites) continue; @@ -268,16 +270,16 @@ if (Line.is_at_end()) return error(instrprof_error::truncated); if ((Line++)->getAsInteger(0, Record.Hash)) - return error(instrprof_error::malformed); + return error(instrprof_error::malformed, "Hash is corrupted"); // Read the number of counters. uint64_t NumCounters; if (Line.is_at_end()) return error(instrprof_error::truncated); if ((Line++)->getAsInteger(10, NumCounters)) - return error(instrprof_error::malformed); + return error(instrprof_error::malformed, "Number of counters is corrupted"); 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. Record.Clear(); @@ -287,7 +289,7 @@ return error(instrprof_error::truncated); uint64_t Count; if ((Line++)->getAsInteger(10, Count)) - return error(instrprof_error::malformed); + return error(instrprof_error::malformed, "Count is corrupted"); Record.Counts.push_back(Count); } @@ -332,10 +334,12 @@ // If there isn't enough space for another header, this is probably just // garbage at the end of the file. if (CurrentPos + sizeof(RawInstrProf::Header) > End) - return make_error(instrprof_error::malformed); + return make_error(instrprof_error::malformed, + "Not enough space for another header"); // The writer ensures each profile is padded to start at an aligned address. if (reinterpret_cast(CurrentPos) % alignof(uint64_t)) - return make_error(instrprof_error::malformed); + return make_error(instrprof_error::malformed, + "Padding is missing"); // The magic should have the same byte order as in the previous header. uint64_t Magic = *reinterpret_cast(CurrentPos); if (Magic != swap(RawInstrProf::getMagic())) @@ -428,7 +432,7 @@ uint32_t NumCounters = swap(Data->NumCounters); IntPtrT CounterPtr = Data->CounterPtr; if (NumCounters == 0) - return error(instrprof_error::malformed); + return error(instrprof_error::malformed, "Number of counters is missing"); auto *NamesStartAsCounter = reinterpret_cast(NamesStart); ptrdiff_t MaxNumCounters = NamesStartAsCounter - CountersStart; @@ -436,7 +440,7 @@ // Check bounds. Note that the counter pointer embedded in the data record // may itself be corrupt. if (MaxNumCounters < 0 || NumCounters > (uint32_t)MaxNumCounters) - return error(instrprof_error::malformed); + return error(instrprof_error::malformed, "Counter pointer is corrupted"); // We need to compute the in-buffer counter offset from the in-memory address // distance. The initial CountersDelta is the in-memory address difference @@ -448,7 +452,7 @@ CountersDelta -= sizeof(*Data); if (CounterOffset < 0 || CounterOffset > MaxNumCounters || ((uint32_t)CounterOffset + NumCounters) > (uint32_t)MaxNumCounters) - return error(instrprof_error::malformed); + return error(instrprof_error::malformed, "Counter offset is corrupted"); auto RawCounts = makeArrayRef(getCounter(CounterOffset), NumCounters); @@ -632,7 +636,8 @@ Data = (*Iter); if (Data.empty()) - return make_error(instrprof_error::malformed); + return make_error(instrprof_error::malformed, + "Data is empty"); return Error::success(); } @@ -646,7 +651,8 @@ Data = *RecordIterator; if (Data.empty()) - return make_error(instrprof_error::malformed); + return make_error(instrprof_error::malformed, + "Data is empty"); return Error::success(); } @@ -677,7 +683,7 @@ return Underlying.getRecords(FuncName, Data); } }; -} +} // namespace /// A remapper that applies remappings based on a symbol remapping file. template