summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/ProfileData/InstrProf.h1
-rw-r--r--llvm/include/llvm/ProfileData/InstrProfReader.h3
-rw-r--r--llvm/include/llvm/ProfileData/SampleProfReader.h3
-rw-r--r--llvm/lib/ProfileData/InstrProf.cpp12
-rw-r--r--llvm/lib/ProfileData/InstrProfReader.cpp13
-rw-r--r--llvm/lib/ProfileData/SampleProf.cpp8
-rw-r--r--llvm/lib/ProfileData/SampleProfReader.cpp20
-rw-r--r--llvm/test/tools/llvm-profdata/raw-magic-but-no-header.test2
-rw-r--r--llvm/test/tools/llvm-profdata/sample-profile-basic.test4
-rw-r--r--llvm/test/tools/llvm-profdata/text-format-errors.test17
-rw-r--r--llvm/tools/llvm-profdata/llvm-profdata.cpp42
11 files changed, 97 insertions, 28 deletions
diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index 607f29de8a2..2339a46f9c5 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -149,6 +149,7 @@ const std::error_category &instrprof_category();
enum class instrprof_error {
success = 0,
eof,
+ unrecognized_format,
bad_magic,
bad_header,
unsupported_version,
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index d0f5a57b1ae..3d4777a853e 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -111,6 +111,9 @@ public:
TextInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer_)
: DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#') {}
+ /// Return true if the given buffer is in text instrprof format.
+ static bool hasFormat(const MemoryBuffer &Buffer);
+
/// Read the header.
std::error_code readHeader() override { return success(); }
/// Read a single record.
diff --git a/llvm/include/llvm/ProfileData/SampleProfReader.h b/llvm/include/llvm/ProfileData/SampleProfReader.h
index 2f404be50e6..1fb2cf6e0ca 100644
--- a/llvm/include/llvm/ProfileData/SampleProfReader.h
+++ b/llvm/include/llvm/ProfileData/SampleProfReader.h
@@ -292,6 +292,9 @@ public:
/// \brief Read sample profiles from the associated file.
std::error_code read() override;
+
+ /// \brief Return true if \p Buffer is in the format supported by this class.
+ static bool hasFormat(const MemoryBuffer &Buffer);
};
class SampleProfileReaderBinary : public SampleProfileReader {
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index 92a3c251f6e..762f00b48b6 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -32,20 +32,22 @@ class InstrProfErrorCategoryType : public std::error_category {
return "Success";
case instrprof_error::eof:
return "End of File";
+ case instrprof_error::unrecognized_format:
+ return "Unrecognized instrumentation profile encoding format";
case instrprof_error::bad_magic:
- return "Invalid profile data (bad magic)";
+ return "Invalid instrumentation profile data (bad magic)";
case instrprof_error::bad_header:
- return "Invalid profile data (file header is corrupt)";
+ return "Invalid instrumentation profile data (file header is corrupt)";
case instrprof_error::unsupported_version:
- return "Unsupported profiling format version";
+ return "Unsupported instrumentation profile format version";
case instrprof_error::unsupported_hash_type:
- return "Unsupported profiling hash";
+ return "Unsupported instrumentation profile hash type";
case instrprof_error::too_large:
return "Too much profile data";
case instrprof_error::truncated:
return "Truncated profile data";
case instrprof_error::malformed:
- return "Malformed profile data";
+ return "Malformed instrumentation profile data";
case instrprof_error::unknown_function:
return "No profile data available for function";
case instrprof_error::hash_mismatch:
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index bf10b448e4c..6f201243736 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -54,8 +54,10 @@ InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
Result.reset(new RawInstrProfReader64(std::move(Buffer)));
else if (RawInstrProfReader32::hasFormat(*Buffer))
Result.reset(new RawInstrProfReader32(std::move(Buffer)));
- else
+ else if (TextInstrProfReader::hasFormat(*Buffer))
Result.reset(new TextInstrProfReader(std::move(Buffer)));
+ else
+ return instrprof_error::unrecognized_format;
// Initialize the reader and return the result.
if (std::error_code EC = initializeReader(*Result))
@@ -97,6 +99,15 @@ void InstrProfIterator::Increment() {
*this = InstrProfIterator();
}
+bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
+ // Verify that this really looks like plain ASCII text by checking a
+ // 'reasonable' number of characters (up to profile magic size).
+ size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t));
+ StringRef buffer = Buffer.getBufferStart();
+ return count == 0 || std::all_of(buffer.begin(), buffer.begin() + count,
+ [](char c) { return ::isprint(c) || ::isspace(c); });
+}
+
std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
// Skip empty lines and comments.
while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
diff --git a/llvm/lib/ProfileData/SampleProf.cpp b/llvm/lib/ProfileData/SampleProf.cpp
index b5d3b2d2e55..856923e164b 100644
--- a/llvm/lib/ProfileData/SampleProf.cpp
+++ b/llvm/lib/ProfileData/SampleProf.cpp
@@ -28,17 +28,17 @@ class SampleProfErrorCategoryType : public std::error_category {
case sampleprof_error::success:
return "Success";
case sampleprof_error::bad_magic:
- return "Invalid file format (bad magic)";
+ return "Invalid sample profile data (bad magic)";
case sampleprof_error::unsupported_version:
- return "Unsupported format version";
+ return "Unsupported sample profile format version";
case sampleprof_error::too_large:
return "Too much profile data";
case sampleprof_error::truncated:
return "Truncated profile data";
case sampleprof_error::malformed:
- return "Malformed profile data";
+ return "Malformed sample profile data";
case sampleprof_error::unrecognized_format:
- return "Unrecognized profile encoding format";
+ return "Unrecognized sample profile encoding format";
case sampleprof_error::unsupported_writing_format:
return "Profile encoding format unsupported for writing operations";
case sampleprof_error::truncated_name_table:
diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp
index a5d00083b53..0bed4f09f1f 100644
--- a/llvm/lib/ProfileData/SampleProfReader.cpp
+++ b/llvm/lib/ProfileData/SampleProfReader.cpp
@@ -222,6 +222,22 @@ std::error_code SampleProfileReaderText::read() {
return sampleprof_error::success;
}
+bool SampleProfileReaderText::hasFormat(const MemoryBuffer &Buffer) {
+ bool result = false;
+
+ // Check that the first non-comment line is a valid function header.
+ line_iterator LineIt(Buffer, /*SkipBlanks=*/true, '#');
+ if (!LineIt.is_at_eof()) {
+ if ((*LineIt)[0] != ' ') {
+ uint64_t NumSamples, NumHeadSamples;
+ StringRef FName;
+ result = ParseHead(*LineIt, FName, NumSamples, NumHeadSamples);
+ }
+ }
+
+ return result;
+}
+
template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() {
unsigned NumBytesRead = 0;
std::error_code EC;
@@ -685,8 +701,10 @@ SampleProfileReader::create(StringRef Filename, LLVMContext &C) {
Reader.reset(new SampleProfileReaderBinary(std::move(Buffer), C));
else if (SampleProfileReaderGCC::hasFormat(*Buffer))
Reader.reset(new SampleProfileReaderGCC(std::move(Buffer), C));
- else
+ else if (SampleProfileReaderText::hasFormat(*Buffer))
Reader.reset(new SampleProfileReaderText(std::move(Buffer), C));
+ else
+ return sampleprof_error::unrecognized_format;
if (std::error_code EC = Reader->readHeader())
return EC;
diff --git a/llvm/test/tools/llvm-profdata/raw-magic-but-no-header.test b/llvm/test/tools/llvm-profdata/raw-magic-but-no-header.test
index b2a697042b0..76894faa183 100644
--- a/llvm/test/tools/llvm-profdata/raw-magic-but-no-header.test
+++ b/llvm/test/tools/llvm-profdata/raw-magic-but-no-header.test
@@ -3,4 +3,4 @@ RUN: not llvm-profdata show %t 2>&1 | FileCheck %s
RUN: printf '\377lprofr\201' > %t
RUN: not llvm-profdata show %t 2>&1 | FileCheck %s
-CHECK: error: {{.+}}: Invalid profile data (file header is corrupt)
+CHECK: error: {{.+}}: Invalid instrumentation profile data (file header is corrupt)
diff --git a/llvm/test/tools/llvm-profdata/sample-profile-basic.test b/llvm/test/tools/llvm-profdata/sample-profile-basic.test
index 0651c513e96..9981d4204c4 100644
--- a/llvm/test/tools/llvm-profdata/sample-profile-basic.test
+++ b/llvm/test/tools/llvm-profdata/sample-profile-basic.test
@@ -28,3 +28,7 @@ RUN: llvm-profdata merge --sample --text %p/Inputs/sample-profile.proftext %t-bi
MERGE1: main:368038:0
MERGE1: 9: 4128 _Z3fooi:1262 _Z3bari:2942
MERGE1: _Z3fooi:15422:1220
+
+5- Detect invalid text encoding (e.g. instrumentation profile text format).
+RUN: not llvm-profdata show --sample %p/Inputs/foo3bar3-1.proftext 2>&1 | FileCheck %s --check-prefix=BADTEXT
+BADTEXT: error: {{.+}}: Unrecognized sample profile encoding format
diff --git a/llvm/test/tools/llvm-profdata/text-format-errors.test b/llvm/test/tools/llvm-profdata/text-format-errors.test
index 01513e4fcb9..113b10ee4e8 100644
--- a/llvm/test/tools/llvm-profdata/text-format-errors.test
+++ b/llvm/test/tools/llvm-profdata/text-format-errors.test
@@ -1,10 +1,21 @@
+Tests for instrumentation profile bad encoding.
+
+1- Detect invalid count
RUN: not llvm-profdata show %p/Inputs/invalid-count-later.proftext 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER
RUN: not llvm-profdata merge %p/Inputs/invalid-count-later.proftext %p/Inputs/invalid-count-later.profdata -o %t.out 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER
-INVALID-COUNT-LATER: error: {{.*}}invalid-count-later.proftext: Malformed profile data
+INVALID-COUNT-LATER: error: {{.*}}invalid-count-later.proftext: Malformed instrumentation profile data
+2- Detect bad hash
RUN: not llvm-profdata show %p/Inputs/bad-hash.proftext 2>&1 | FileCheck %s --check-prefix=BAD-HASH
RUN: not llvm-profdata merge %p/Inputs/bad-hash.proftext %p/Inputs/bad-hash.proftext -o %t.out 2>&1 | FileCheck %s --check-prefix=BAD-HASH
-BAD-HASH: error: {{.*}}bad-hash.proftext: Malformed profile data
+BAD-HASH: error: {{.*}}bad-hash.proftext: Malformed instrumentation profile data
+3- Detect no counts
RUN: not llvm-profdata show %p/Inputs/no-counts.proftext 2>&1 | FileCheck %s --check-prefix=NO-COUNTS
-NO-COUNTS: error: {{.*}}no-counts.proftext: Malformed profile data
+NO-COUNTS: error: {{.*}}no-counts.proftext: Malformed instrumentation profile data
+
+4- Detect binary input
+RUN: echo -n $'\xff\xe5\xd0\xb1\xf4\c9\x94\xa8' > %t.bin
+RUN: not llvm-profdata show %t.bin 2>&1 | FileCheck %s --check-prefix=BINARY
+BINARY: error: {{.+}}: Unrecognized instrumentation profile encoding format
+BINARY: Perhaps you forgot to use the -sample option?
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 48fc83c6971..1cd47dd5e84 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -29,16 +29,32 @@
using namespace llvm;
-static void exitWithError(const Twine &Message, StringRef Whence = "") {
+static void exitWithError(const Twine &Message,
+ StringRef Whence = "",
+ StringRef Hint = "") {
errs() << "error: ";
if (!Whence.empty())
errs() << Whence << ": ";
errs() << Message << "\n";
+ if (!Hint.empty())
+ errs() << Hint << "\n";
::exit(1);
}
+static void exitWithErrorCode(const std::error_code &Error, StringRef Whence = "") {
+ if (Error.category() == instrprof_category()) {
+ instrprof_error instrError = static_cast<instrprof_error>(Error.value());
+ if (instrError == instrprof_error::unrecognized_format) {
+ // Hint for common error of forgetting -sample for sample profiles.
+ exitWithError(Error.message(), Whence,
+ "Perhaps you forgot to use the -sample option?");
+ }
+ }
+ exitWithError(Error.message(), Whence);
+}
+
namespace {
-enum ProfileKinds { instr, sample };
+ enum ProfileKinds { instr, sample };
}
static void mergeInstrProfile(const cl::list<std::string> &Inputs,
@@ -49,20 +65,20 @@ static void mergeInstrProfile(const cl::list<std::string> &Inputs,
std::error_code EC;
raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::F_None);
if (EC)
- exitWithError(EC.message(), OutputFilename);
+ exitWithErrorCode(EC, OutputFilename);
InstrProfWriter Writer;
for (const auto &Filename : Inputs) {
auto ReaderOrErr = InstrProfReader::create(Filename);
if (std::error_code ec = ReaderOrErr.getError())
- exitWithError(ec.message(), Filename);
+ exitWithErrorCode(ec, Filename);
auto Reader = std::move(ReaderOrErr.get());
for (auto &I : *Reader)
if (std::error_code EC = Writer.addRecord(std::move(I)))
errs() << Filename << ": " << I.Name << ": " << EC.message() << "\n";
if (Reader->hasError())
- exitWithError(Reader->getError().message(), Filename);
+ exitWithErrorCode(Reader->getError(), Filename);
}
Writer.write(Output);
}
@@ -73,7 +89,7 @@ static void mergeSampleProfile(const cl::list<std::string> &Inputs,
using namespace sampleprof;
auto WriterOrErr = SampleProfileWriter::create(OutputFilename, OutputFormat);
if (std::error_code EC = WriterOrErr.getError())
- exitWithError(EC.message(), OutputFilename);
+ exitWithErrorCode(EC, OutputFilename);
auto Writer = std::move(WriterOrErr.get());
StringMap<FunctionSamples> ProfileMap;
@@ -82,7 +98,7 @@ static void mergeSampleProfile(const cl::list<std::string> &Inputs,
auto ReaderOrErr =
SampleProfileReader::create(Filename, getGlobalContext());
if (std::error_code EC = ReaderOrErr.getError())
- exitWithError(EC.message(), Filename);
+ exitWithErrorCode(EC, Filename);
// We need to keep the readers around until after all the files are
// read so that we do not lose the function names stored in each
@@ -91,7 +107,7 @@ static void mergeSampleProfile(const cl::list<std::string> &Inputs,
Readers.push_back(std::move(ReaderOrErr.get()));
const auto Reader = Readers.back().get();
if (std::error_code EC = Reader->read())
- exitWithError(EC.message(), Filename);
+ exitWithErrorCode(EC, Filename);
StringMap<FunctionSamples> &Profiles = Reader->getProfiles();
for (StringMap<FunctionSamples>::iterator I = Profiles.begin(),
@@ -143,7 +159,7 @@ static int showInstrProfile(std::string Filename, bool ShowCounts,
std::string ShowFunction, raw_fd_ostream &OS) {
auto ReaderOrErr = InstrProfReader::create(Filename);
if (std::error_code EC = ReaderOrErr.getError())
- exitWithError(EC.message(), Filename);
+ exitWithErrorCode(EC, Filename);
auto Reader = std::move(ReaderOrErr.get());
uint64_t MaxFunctionCount = 0, MaxBlockCount = 0;
@@ -198,7 +214,7 @@ static int showInstrProfile(std::string Filename, bool ShowCounts,
}
}
if (Reader->hasError())
- exitWithError(Reader->getError().message(), Filename);
+ exitWithErrorCode(Reader->getError(), Filename);
if (ShowAllFunctions || !ShowFunction.empty())
OS << "Functions shown: " << ShownFunctions << "\n";
@@ -214,11 +230,11 @@ static int showSampleProfile(std::string Filename, bool ShowCounts,
using namespace sampleprof;
auto ReaderOrErr = SampleProfileReader::create(Filename, getGlobalContext());
if (std::error_code EC = ReaderOrErr.getError())
- exitWithError(EC.message(), Filename);
+ exitWithErrorCode(EC, Filename);
auto Reader = std::move(ReaderOrErr.get());
if (std::error_code EC = Reader->read())
- exitWithError(EC.message(), Filename);
+ exitWithErrorCode(EC, Filename);
if (ShowAllFunctions || ShowFunction.empty())
Reader->dump(OS);
@@ -259,7 +275,7 @@ static int show_main(int argc, const char *argv[]) {
std::error_code EC;
raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text);
if (EC)
- exitWithError(EC.message(), OutputFilename);
+ exitWithErrorCode(EC, OutputFilename);
if (ShowAllFunctions && !ShowFunction.empty())
errs() << "warning: -function argument ignored: showing all functions\n";
OpenPOWER on IntegriCloud