[llvm] 0057c71 - [CSSPGO][llvm-profgen] Truncate stack samples with invalid return address.
Hongtao Yu via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 14 21:56:36 PDT 2021
Author: Hongtao Yu
Date: 2021-09-14T21:56:22-07:00
New Revision: 0057c7185d1cdbcfdaa9385f4b67e677066af8b8
URL: https://github.com/llvm/llvm-project/commit/0057c7185d1cdbcfdaa9385f4b67e677066af8b8
DIFF: https://github.com/llvm/llvm-project/commit/0057c7185d1cdbcfdaa9385f4b67e677066af8b8.diff
LOG: [CSSPGO][llvm-profgen] Truncate stack samples with invalid return address.
Invalid frame addresses exist in call stack samples due to bad unwinding. This could happen to frame-pointer-based unwinding and the callee functions that do not have the frame pointer chain set up. It isn't common when the program is built with the frame pointer omission disabled, but can still happen with third-party static libs built with frame pointer omitted.
Reviewed By: wenlei
Differential Revision: https://reviews.llvm.org/D109638
Added:
llvm/test/tools/llvm-profgen/Inputs/cs-invalid-ret-addr.perfscript
llvm/test/tools/llvm-profgen/cs-invalid-ret-addr.test
Modified:
llvm/tools/llvm-profgen/PerfReader.cpp
llvm/tools/llvm-profgen/PerfReader.h
llvm/tools/llvm-profgen/ProfiledBinary.h
Removed:
################################################################################
diff --git a/llvm/test/tools/llvm-profgen/Inputs/cs-invalid-ret-addr.perfscript b/llvm/test/tools/llvm-profgen/Inputs/cs-invalid-ret-addr.perfscript
new file mode 100644
index 0000000000000..63ba27822e26d
--- /dev/null
+++ b/llvm/test/tools/llvm-profgen/Inputs/cs-invalid-ret-addr.perfscript
@@ -0,0 +1,12 @@
+PERF_RECORD_MMAP2 2854748/2854748: [0x400000(0x1000) @ 0 00:1d 123291722 526021]: r-xp /home/noinline-cs-noprobe.perfbin
+// test for invalid return address
+
+ 4005b0
+ 400686
+ 7f68c5788793
+ 0x40062f/0x4005b0/P/-/-/0 0x400645/0x4005ff/P/-/-/0 0x400637/0x400645/P/-/-/0 0x4005e9/0x400634/P/-/-/0 0x4005c8/0x4005dc/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 0x400645/0x4005ff/P/-/-/0 0x400637/0x400645/P/-/-/0 0x4005e9/0x400634/P/-/-/0 0x4005d7/0x4005e5/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 0x400645/0x4005ff/P/-/-/0 0x400637/0x400645/P/-/-/0 0x4005e9/0x400634/P/-/-/0 0x4005d7/0x4005e5/P/-/-/0 0x40062f/0x4005b0/P/-/-/0
+
+ 4005b2
+ 400686
+ 7f68c5788793
+ 0x40062f/0x4005b0/P/-/-/0 0x400645/0x4005ff/P/-/-/0 0x400637/0x400645/P/-/-/0 0x4005e9/0x400634/P/-/-/0 0x4005c8/0x4005dc/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 0x400645/0x4005ff/P/-/-/0 0x400637/0x400645/P/-/-/0 0x4005e9/0x400634/P/-/-/0 0x4005d7/0x4005e5/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 0x400645/0x4005ff/P/-/-/0 0x400637/0x400645/P/-/-/0 0x4005e9/0x400634/P/-/-/0 0x4005d7/0x4005e5/P/-/-/0 0x40062f/0x4005b0/P/-/-/0
diff --git a/llvm/test/tools/llvm-profgen/cs-invalid-ret-addr.test b/llvm/test/tools/llvm-profgen/cs-invalid-ret-addr.test
new file mode 100644
index 0000000000000..3eac05e65f8bf
--- /dev/null
+++ b/llvm/test/tools/llvm-profgen/cs-invalid-ret-addr.test
@@ -0,0 +1,4 @@
+; REQUIRES: x86_64-linux
+; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/cs-invalid-ret-addr.perfscript --binary=%S/Inputs/noinline-cs-noprobe.perfbin --output=%t 2>&1 | FileCheck %s
+
+; CHECK: warning: Truncated stack sample due to invalid return address at 0x400686, likely caused by frame pointer omission
diff --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp
index 259b23f33d47b..f892d6bf4a2a4 100644
--- a/llvm/tools/llvm-profgen/PerfReader.cpp
+++ b/llvm/tools/llvm-profgen/PerfReader.cpp
@@ -9,13 +9,15 @@
#include "ProfileGenerator.h"
#include "llvm/Support/FileSystem.h"
+#define DEBUG_TYPE "perf-reader"
+
static cl::opt<bool> ShowMmapEvents("show-mmap-events", cl::ReallyHidden,
cl::init(false), cl::ZeroOrMore,
cl::desc("Print binary load events."));
cl::opt<bool> SkipSymbolization("skip-symbolization", cl::ReallyHidden,
cl::init(false), cl::ZeroOrMore,
- cl::desc("Dump the unsumbolized profile to the "
+ cl::desc("Dump the unsymbolized profile to the "
"output file. It will show unwinder "
"output for CS profile generation."));
@@ -517,10 +519,17 @@ bool PerfReaderBase::extractCallstack(TraceStream &TraceIt,
if (!Binary->addressIsCode(FrameAddr))
break;
- // We need to translate return address to call address
- // for non-leaf frames
+ // We need to translate return address to call address for non-leaf frames.
if (!CallStack.empty()) {
- FrameAddr = Binary->getCallAddrFromFrameAddr(FrameAddr);
+ auto CallAddr = Binary->getCallAddrFromFrameAddr(FrameAddr);
+ if (!CallAddr) {
+ // Stop at an invalid return address caused by bad unwinding. This could
+ // happen to frame-pointer-based unwinding and the callee functions that
+ // do not have the frame pointer chain set up.
+ InvalidReturnAddresses.insert(FrameAddr);
+ break;
+ }
+ FrameAddr = CallAddr;
}
CallStack.emplace_back(FrameAddr);
@@ -760,12 +769,22 @@ PerfReaderBase::extractPerfType(cl::list<std::string> &PerfTraceFilenames) {
void HybridPerfReader::generateRawProfile() { unwindSamples(); }
+void PerfReaderBase::warnTruncatedStack() {
+ for (auto Address : InvalidReturnAddresses) {
+ WithColor::warning()
+ << "Truncated stack sample due to invalid return address at "
+ << format("0x%" PRIx64, Address)
+ << ", likely caused by frame pointer omission\n";
+ }
+}
+
void PerfReaderBase::parsePerfTraces(
cl::list<std::string> &PerfTraceFilenames) {
// Parse perf traces and do aggregation.
for (auto Filename : PerfTraceFilenames)
parseAndAggregateTrace(Filename);
+ warnTruncatedStack();
generateRawProfile();
}
diff --git a/llvm/tools/llvm-profgen/PerfReader.h b/llvm/tools/llvm-profgen/PerfReader.h
index 2babcd7246a8b..c281e76c96379 100644
--- a/llvm/tools/llvm-profgen/PerfReader.h
+++ b/llvm/tools/llvm-profgen/PerfReader.h
@@ -594,6 +594,8 @@ class PerfReaderBase {
void parseEventOrSample(TraceStream &TraceIt);
// Warn if the relevant mmap event is missing.
void warnIfMissingMMap();
+ // Emit accumulate warnings.
+ void warnTruncatedStack();
// Extract call stack from the perf trace lines
bool extractCallstack(TraceStream &TraceIt,
SmallVectorImpl<uint64_t> &CallStack);
@@ -619,6 +621,8 @@ class PerfReaderBase {
// Samples with the repeating time generated by the perf reader
AggregatedCounter AggregatedSamples;
PerfScriptType PerfType = PERF_UNKNOWN;
+ // Keep track of all invalid return addresses
+ std::set<uint64_t> InvalidReturnAddresses;
};
/*
diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.h b/llvm/tools/llvm-profgen/ProfiledBinary.h
index 4a3bb561f488e..fabc73d3b5675 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.h
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.h
@@ -299,7 +299,11 @@ class ProfiledBinary {
}
uint64_t getCallAddrFromFrameAddr(uint64_t FrameAddr) const {
- return getAddressforIndex(getIndexForAddr(FrameAddr) - 1);
+ auto I = getIndexForAddr(FrameAddr);
+ FrameAddr = I ? getAddressforIndex(I - 1) : 0;
+ if (FrameAddr && addressIsCall(FrameAddr))
+ return FrameAddr;
+ return 0;
}
StringRef getFuncFromStartOffset(uint64_t Offset) {
More information about the llvm-commits
mailing list