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
--- /dev/null
+3
+0-0:1
+f-fff0:1
+ffff-ffff:1
+0
; 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
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>
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 {
// 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);
updateBodySamplesforFunctionProfile(FunctionProfile, FrameVec.back(),
Count);
}
- // Move to next IP within the range.
- IP.advance();
- }
+ } while (IP.advance() && IP.Address <= RangeEnd);
}
}
// 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);
}
}
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);
ProbeCounter[&Probe] += Count;
}
}
-
- IP.advance();
- }
+ } while (IP.advance() && IP.Address <= RangeEnd);
}
}
void ProfiledBinary::computeInlinedContextSizeForRange(uint64_t StartOffset,
uint64_t EndOffset) {
- uint32_t Index = getIndexForOffset(StartOffset);
- if (CodeAddrOffsets[Index] != StartOffset)
+ uint64_t RangeBegin = offsetToVirtualAddr(StartOffset);
+ uint64_t RangeEnd = offsetToVirtualAddr(EndOffset);
+ InstructionPointer IP(this, RangeBegin, true);
+
+ if (IP.Address != RangeBegin)
WithColor::warning() << "Invalid start instruction at "
- << format("%8" PRIx64, StartOffset) << "\n";
+ << format("%8" PRIx64, RangeBegin) << "\n";
+
+ if (IP.Address >= RangeEnd)
+ return;
- uint64_t Offset = CodeAddrOffsets[Index];
- while (Offset < EndOffset) {
+ do {
+ uint64_t Offset = virtualAddrToOffset(IP.Address);
const SampleContextFrameVector &SymbolizedCallStack =
getFrameLocationStack(Offset, UsePseudoProbes);
uint64_t Size = Offset2InstSizeMap[Offset];
// 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,
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) {
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);
};
struct BinaryFunction {
StringRef FuncName;
+ // End of range is an exclusive bound.
RangesTy Ranges;
};
// 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;
for (auto I : FuncStartOffsetMap) {
PrologEpilogSet.insert(I.first);
InstructionPointer IP(Binary, I.first);
- IP.advance();
+ if (!IP.advance())
+ break;
PrologEpilogSet.insert(IP.Offset);
}
}
for (auto Addr : RetAddrs) {
PrologEpilogSet.insert(Addr);
InstructionPointer IP(Binary, Addr);
- IP.backward();
+ if (!IP.backward())
+ break;
PrologEpilogSet.insert(IP.Offset);
}
}
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