Skip to content

Commit 0057c71

Browse files
committed
[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
1 parent 0dc4614 commit 0057c71

File tree

5 files changed

+48
-5
lines changed

5 files changed

+48
-5
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
PERF_RECORD_MMAP2 2854748/2854748: [0x400000(0x1000) @ 0 00:1d 123291722 526021]: r-xp /home/noinline-cs-noprobe.perfbin
2+
// test for invalid return address
3+
4+
4005b0
5+
400686
6+
7f68c5788793
7+
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
8+
9+
4005b2
10+
400686
11+
7f68c5788793
12+
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
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
; REQUIRES: x86_64-linux
2+
; 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
3+
4+
; CHECK: warning: Truncated stack sample due to invalid return address at 0x400686, likely caused by frame pointer omission

llvm/tools/llvm-profgen/PerfReader.cpp

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
#include "ProfileGenerator.h"
1010
#include "llvm/Support/FileSystem.h"
1111

12+
#define DEBUG_TYPE "perf-reader"
13+
1214
static cl::opt<bool> ShowMmapEvents("show-mmap-events", cl::ReallyHidden,
1315
cl::init(false), cl::ZeroOrMore,
1416
cl::desc("Print binary load events."));
1517

1618
cl::opt<bool> SkipSymbolization("skip-symbolization", cl::ReallyHidden,
1719
cl::init(false), cl::ZeroOrMore,
18-
cl::desc("Dump the unsumbolized profile to the "
20+
cl::desc("Dump the unsymbolized profile to the "
1921
"output file. It will show unwinder "
2022
"output for CS profile generation."));
2123

@@ -517,10 +519,17 @@ bool PerfReaderBase::extractCallstack(TraceStream &TraceIt,
517519
if (!Binary->addressIsCode(FrameAddr))
518520
break;
519521

520-
// We need to translate return address to call address
521-
// for non-leaf frames
522+
// We need to translate return address to call address for non-leaf frames.
522523
if (!CallStack.empty()) {
523-
FrameAddr = Binary->getCallAddrFromFrameAddr(FrameAddr);
524+
auto CallAddr = Binary->getCallAddrFromFrameAddr(FrameAddr);
525+
if (!CallAddr) {
526+
// Stop at an invalid return address caused by bad unwinding. This could
527+
// happen to frame-pointer-based unwinding and the callee functions that
528+
// do not have the frame pointer chain set up.
529+
InvalidReturnAddresses.insert(FrameAddr);
530+
break;
531+
}
532+
FrameAddr = CallAddr;
524533
}
525534

526535
CallStack.emplace_back(FrameAddr);
@@ -760,12 +769,22 @@ PerfReaderBase::extractPerfType(cl::list<std::string> &PerfTraceFilenames) {
760769

761770
void HybridPerfReader::generateRawProfile() { unwindSamples(); }
762771

772+
void PerfReaderBase::warnTruncatedStack() {
773+
for (auto Address : InvalidReturnAddresses) {
774+
WithColor::warning()
775+
<< "Truncated stack sample due to invalid return address at "
776+
<< format("0x%" PRIx64, Address)
777+
<< ", likely caused by frame pointer omission\n";
778+
}
779+
}
780+
763781
void PerfReaderBase::parsePerfTraces(
764782
cl::list<std::string> &PerfTraceFilenames) {
765783
// Parse perf traces and do aggregation.
766784
for (auto Filename : PerfTraceFilenames)
767785
parseAndAggregateTrace(Filename);
768786

787+
warnTruncatedStack();
769788
generateRawProfile();
770789
}
771790

llvm/tools/llvm-profgen/PerfReader.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,8 @@ class PerfReaderBase {
594594
void parseEventOrSample(TraceStream &TraceIt);
595595
// Warn if the relevant mmap event is missing.
596596
void warnIfMissingMMap();
597+
// Emit accumulate warnings.
598+
void warnTruncatedStack();
597599
// Extract call stack from the perf trace lines
598600
bool extractCallstack(TraceStream &TraceIt,
599601
SmallVectorImpl<uint64_t> &CallStack);
@@ -619,6 +621,8 @@ class PerfReaderBase {
619621
// Samples with the repeating time generated by the perf reader
620622
AggregatedCounter AggregatedSamples;
621623
PerfScriptType PerfType = PERF_UNKNOWN;
624+
// Keep track of all invalid return addresses
625+
std::set<uint64_t> InvalidReturnAddresses;
622626
};
623627

624628
/*

llvm/tools/llvm-profgen/ProfiledBinary.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,11 @@ class ProfiledBinary {
299299
}
300300

301301
uint64_t getCallAddrFromFrameAddr(uint64_t FrameAddr) const {
302-
return getAddressforIndex(getIndexForAddr(FrameAddr) - 1);
302+
auto I = getIndexForAddr(FrameAddr);
303+
FrameAddr = I ? getAddressforIndex(I - 1) : 0;
304+
if (FrameAddr && addressIsCall(FrameAddr))
305+
return FrameAddr;
306+
return 0;
303307
}
304308

305309
StringRef getFuncFromStartOffset(uint64_t Offset) {

0 commit comments

Comments
 (0)