[llvm-profgen] Fix index out of bounds error while using ip.advance

Previously we assume there're some non-executing sections at the bottom of the text section so that we won't hit the array's bound. But on BOLTed binary, it turned out .bolt section is at the bottom of text section which can be profiled, then it crash llvm-profgen. This change try to fix it.

Reviewed By: hoy, wenlei

Differential Revision: https://reviews.llvm.org/D113238
This commit is contained in:
wlei 2021-11-04 20:51:04 -07:00
parent 845561ec9d
commit 5bf191a381
5 changed files with 86 additions and 31 deletions

View File

@ -0,0 +1,5 @@
3
0-0:1
f-fff0:1
ffff-ffff:1
0

View File

@ -9,6 +9,8 @@
; RUN: echo -e "0\n0" > %t
; RUN: llvm-profgen --format=text --unsymbolized-profile=%t --binary=%S/Inputs/inline-noprobe.perfbin --output=%t1 --fill-zero-for-all-funcs
; RUN: FileCheck %s --input-file %t1 --check-prefix=CHECK-ALL-ZERO
; RUN: llvm-profgen --format=text --unsymbolized-profile=%S/Inputs/out-of-bounds.raw.prof --binary=%S/Inputs/inline-noprobe.perfbin --output=%t1
; RUN: FileCheck %s --input-file %t1 --check-prefix=CHECK-OB
CHECK: main:188:0
CHECK: 0: 0
@ -58,6 +60,33 @@ CHECK-RAW-PROFILE-NEXT: 2
CHECK-RAW-PROFILE-NEXT: 677->650:21
CHECK-RAW-PROFILE-NEXT: 691->669:43
;CHECK-OB: foo:8:0
;CHECK-OB: 0: 1
;CHECK-OB: 2.1: 1
;CHECK-OB: 3: 1
;CHECK-OB: 3.2: 1
;CHECK-OB: 4: 1
;CHECK-OB: 3.1: bar:1
;CHECK-OB: 1: 1
;CHECK-OB: 3.2: bar:2
;CHECK-OB: 1: 1
;CHECK-OB: 7: 1
;CHECK-OB: main:8:0
;CHECK-OB: 0: 1
;CHECK-OB: 2: 1
;CHECK-OB: 1: foo:6
;CHECK-OB: 2.1: 1
;CHECK-OB: 3: 1
;CHECK-OB: 3.2: 1
;CHECK-OB: 4: 1
;CHECK-OB: 3.1: bar:1
;CHECK-OB: 1: 1
;CHECK-OB: 3.2: bar:1
;CHECK-OB: 1: 1
;CHECK-OB: bar:2:0
;CHECK-OB: 1: 1
;CHECK-OB: 5: 1
; original code:
; clang -O3 -g -fdebug-info-for-profiling test.c -o a.out
#include <stdio.h>

View File

@ -355,7 +355,7 @@ ProfileGenerator::preprocessRangeCounter(const RangeSample &RangeCounter) {
if (FillZeroForAllFuncs) {
for (auto &FuncI : Binary->getAllBinaryFunctions()) {
for (auto &R : FuncI.second.Ranges) {
Ranges[{R.first, R.second}] += 0;
Ranges[{R.first, R.second - 1}] += 0;
}
}
} else {
@ -385,7 +385,10 @@ void ProfileGenerator::populateBodySamplesForAllFunctions(
// Disjoint ranges may have range in the middle of two instr,
// e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range
// can be Addr1+1 to Addr2-1. We should ignore such range.
while (IP.Address <= RangeEnd) {
if (IP.Address > RangeEnd)
continue;
do {
uint64_t Offset = Binary->virtualAddrToOffset(IP.Address);
const SampleContextFrameVector &FrameVec =
Binary->getFrameLocationStack(Offset);
@ -394,9 +397,7 @@ void ProfileGenerator::populateBodySamplesForAllFunctions(
updateBodySamplesforFunctionProfile(FunctionProfile, FrameVec.back(),
Count);
}
// Move to next IP within the range.
IP.advance();
}
} while (IP.advance() && IP.Address <= RangeEnd);
}
}
@ -538,17 +539,17 @@ void CSProfileGenerator::populateBodySamplesForFunction(
// Disjoint ranges may have range in the middle of two instr,
// e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range
// can be Addr1+1 to Addr2-1. We should ignore such range.
while (IP.Address <= RangeEnd) {
if (IP.Address > RangeEnd)
continue;
do {
uint64_t Offset = Binary->virtualAddrToOffset(IP.Address);
auto LeafLoc = Binary->getInlineLeafFrameLoc(Offset);
if (LeafLoc.hasValue()) {
// Recording body sample for this specific context
updateBodySamplesforFunctionProfile(FunctionProfile, *LeafLoc, Count);
}
// Move to next IP within the range
IP.advance();
}
} while (IP.advance() && IP.Address <= RangeEnd);
}
}
@ -714,14 +715,13 @@ void CSProfileGenerator::extractProbesFromRange(const RangeSample &RangeCounter,
continue;
InstructionPointer IP(Binary, RangeBegin, true);
// Disjoint ranges may have range in the middle of two instr,
// e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range
// can be Addr1+1 to Addr2-1. We should ignore such range.
if (IP.Address > RangeEnd)
continue;
while (IP.Address <= RangeEnd) {
do {
const AddressProbesMap &Address2ProbesMap =
Binary->getAddress2ProbesMap();
auto It = Address2ProbesMap.find(IP.Address);
@ -732,9 +732,7 @@ void CSProfileGenerator::extractProbesFromRange(const RangeSample &RangeCounter,
ProbeCounter[&Probe] += Count;
}
}
IP.advance();
}
} while (IP.advance() && IP.Address <= RangeEnd);
}
}

View File

@ -657,13 +657,19 @@ SampleContextFrameVector ProfiledBinary::symbolize(const InstructionPointer &IP,
void ProfiledBinary::computeInlinedContextSizeForRange(uint64_t StartOffset,
uint64_t EndOffset) {
uint32_t Index = getIndexForOffset(StartOffset);
if (CodeAddrOffsets[Index] != StartOffset)
WithColor::warning() << "Invalid start instruction at "
<< format("%8" PRIx64, StartOffset) << "\n";
uint64_t RangeBegin = offsetToVirtualAddr(StartOffset);
uint64_t RangeEnd = offsetToVirtualAddr(EndOffset);
InstructionPointer IP(this, RangeBegin, true);
uint64_t Offset = CodeAddrOffsets[Index];
while (Offset < EndOffset) {
if (IP.Address != RangeBegin)
WithColor::warning() << "Invalid start instruction at "
<< format("%8" PRIx64, RangeBegin) << "\n";
if (IP.Address >= RangeEnd)
return;
do {
uint64_t Offset = virtualAddrToOffset(IP.Address);
const SampleContextFrameVector &SymbolizedCallStack =
getFrameLocationStack(Offset, UsePseudoProbes);
uint64_t Size = Offset2InstSizeMap[Offset];
@ -671,8 +677,7 @@ void ProfiledBinary::computeInlinedContextSizeForRange(uint64_t StartOffset,
// Record instruction size for the corresponding context
FuncSizeTracker.addInstructionForContext(SymbolizedCallStack, Size);
Offset = CodeAddrOffsets[++Index];
}
} while (IP.advance() && IP.Address < RangeEnd);
}
InstructionPointer::InstructionPointer(const ProfiledBinary *Binary,
@ -682,18 +687,31 @@ InstructionPointer::InstructionPointer(const ProfiledBinary *Binary,
if (RoundToNext) {
// we might get address which is not the code
// it should round to the next valid address
this->Address = Binary->getAddressforIndex(Index);
if (Index >= Binary->getCodeOffsetsSize())
this->Address = UINT64_MAX;
else
this->Address = Binary->getAddressforIndex(Index);
}
}
void InstructionPointer::advance() {
bool InstructionPointer::advance() {
Index++;
if (Index >= Binary->getCodeOffsetsSize()) {
Address = UINT64_MAX;
return false;
}
Address = Binary->getAddressforIndex(Index);
return true;
}
void InstructionPointer::backward() {
bool InstructionPointer::backward() {
if (Index == 0) {
Address = 0;
return false;
}
Index--;
Address = Binary->getAddressforIndex(Index);
return true;
}
void InstructionPointer::update(uint64_t Addr) {

View File

@ -64,8 +64,8 @@ struct InstructionPointer {
uint64_t Index = 0;
InstructionPointer(const ProfiledBinary *Binary, uint64_t Address,
bool RoundToNext = false);
void advance();
void backward();
bool advance();
bool backward();
void update(uint64_t Addr);
};
@ -73,6 +73,7 @@ using RangesTy = std::vector<std::pair<uint64_t, uint64_t>>;
struct BinaryFunction {
StringRef FuncName;
// End of range is an exclusive bound.
RangesTy Ranges;
};
@ -80,7 +81,7 @@ struct BinaryFunction {
// non-continuous ranges, each range corresponds to one FuncRange.
struct FuncRange {
uint64_t StartOffset;
// EndOffset is a exclusive bound.
// EndOffset is an exclusive bound.
uint64_t EndOffset;
// Function the range belongs to
BinaryFunction *Func;
@ -105,7 +106,8 @@ struct PrologEpilogTracker {
for (auto I : FuncStartOffsetMap) {
PrologEpilogSet.insert(I.first);
InstructionPointer IP(Binary, I.first);
IP.advance();
if (!IP.advance())
break;
PrologEpilogSet.insert(IP.Offset);
}
}
@ -115,7 +117,8 @@ struct PrologEpilogTracker {
for (auto Addr : RetAddrs) {
PrologEpilogSet.insert(Addr);
InstructionPointer IP(Binary, Addr);
IP.backward();
if (!IP.backward())
break;
PrologEpilogSet.insert(IP.Offset);
}
}
@ -336,6 +339,8 @@ public:
return offsetToVirtualAddr(CodeAddrOffsets[Index]);
}
size_t getCodeOffsetsSize() const { return CodeAddrOffsets.size(); }
bool usePseudoProbes() const { return UsePseudoProbes; }
// Get the index in CodeAddrOffsets for the address
// As we might get an address which is not the code