Skip to content

Commit 6d216fb

Browse files
authored
[perf2bolt] Improve heuristic to map in-process addresses to specific… (#109397)
… segments in Elf binary. The heuristic is improved by also taking into account that only executable segments should contain instructions. Fixes #109384.
1 parent 6f194a6 commit 6d216fb

File tree

5 files changed

+41
-18
lines changed

5 files changed

+41
-18
lines changed

bolt/include/bolt/Core/BinaryContext.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,15 @@ struct SegmentInfo {
7171
uint64_t FileOffset; /// Offset in the file.
7272
uint64_t FileSize; /// Size in file.
7373
uint64_t Alignment; /// Alignment of the segment.
74+
bool IsExecutable; /// Is the executable bit set on the Segment?
7475

7576
void print(raw_ostream &OS) const {
76-
OS << "SegmentInfo { Address: 0x"
77-
<< Twine::utohexstr(Address) << ", Size: 0x"
78-
<< Twine::utohexstr(Size) << ", FileOffset: 0x"
77+
OS << "SegmentInfo { Address: 0x" << Twine::utohexstr(Address)
78+
<< ", Size: 0x" << Twine::utohexstr(Size) << ", FileOffset: 0x"
7979
<< Twine::utohexstr(FileOffset) << ", FileSize: 0x"
8080
<< Twine::utohexstr(FileSize) << ", Alignment: 0x"
81-
<< Twine::utohexstr(Alignment) << "}";
81+
<< Twine::utohexstr(Alignment) << ", " << (IsExecutable ? "x" : " ")
82+
<< "}";
8283
};
8384
};
8485

bolt/lib/Core/BinaryContext.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,6 +2021,9 @@ BinaryContext::getBaseAddressForMapping(uint64_t MMapAddress,
20212021
// Find a segment with a matching file offset.
20222022
for (auto &KV : SegmentMapInfo) {
20232023
const SegmentInfo &SegInfo = KV.second;
2024+
// Only consider executable segments.
2025+
if (!SegInfo.IsExecutable)
2026+
continue;
20242027
// FileOffset is got from perf event,
20252028
// and it is equal to alignDown(SegInfo.FileOffset, pagesize).
20262029
// If the pagesize is not equal to SegInfo.Alignment.

bolt/lib/Profile/DataAggregator.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2043,7 +2043,8 @@ std::error_code DataAggregator::parseMMapEvents() {
20432043
// size of the mapping, but we know it should not exceed the segment
20442044
// alignment value. Hence we are performing an approximate check.
20452045
return SegInfo.Address >= MMapInfo.MMapAddress &&
2046-
SegInfo.Address - MMapInfo.MMapAddress < SegInfo.Alignment;
2046+
SegInfo.Address - MMapInfo.MMapAddress < SegInfo.Alignment &&
2047+
SegInfo.IsExecutable;
20472048
});
20482049
if (!MatchFound) {
20492050
errs() << "PERF2BOLT-WARNING: ignoring mapping of " << NameToUse

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -526,11 +526,9 @@ Error RewriteInstance::discoverStorage() {
526526
NextAvailableOffset = std::max(NextAvailableOffset,
527527
Phdr.p_offset + Phdr.p_filesz);
528528

529-
BC->SegmentMapInfo[Phdr.p_vaddr] = SegmentInfo{Phdr.p_vaddr,
530-
Phdr.p_memsz,
531-
Phdr.p_offset,
532-
Phdr.p_filesz,
533-
Phdr.p_align};
529+
BC->SegmentMapInfo[Phdr.p_vaddr] = SegmentInfo{
530+
Phdr.p_vaddr, Phdr.p_memsz, Phdr.p_offset,
531+
Phdr.p_filesz, Phdr.p_align, ((Phdr.p_flags & ELF::PF_X) != 0)};
534532
if (BC->TheTriple->getArch() == llvm::Triple::x86_64 &&
535533
Phdr.p_vaddr >= BinaryContext::KernelStartX86_64)
536534
BC->IsLinuxKernel = true;

bolt/unittests/Core/BinaryContext.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,13 +160,14 @@ TEST_P(BinaryContextTester, FlushPendingRelocJUMP26) {
160160
TEST_P(BinaryContextTester, BaseAddress) {
161161
// Check that base address calculation is correct for a binary with the
162162
// following segment layout:
163-
BC->SegmentMapInfo[0] = SegmentInfo{0, 0x10e8c2b4, 0, 0x10e8c2b4, 0x1000};
163+
BC->SegmentMapInfo[0] =
164+
SegmentInfo{0, 0x10e8c2b4, 0, 0x10e8c2b4, 0x1000, true};
164165
BC->SegmentMapInfo[0x10e8d2b4] =
165-
SegmentInfo{0x10e8d2b4, 0x3952faec, 0x10e8c2b4, 0x3952faec, 0x1000};
166+
SegmentInfo{0x10e8d2b4, 0x3952faec, 0x10e8c2b4, 0x3952faec, 0x1000, true};
166167
BC->SegmentMapInfo[0x4a3bddc0] =
167-
SegmentInfo{0x4a3bddc0, 0x148e828, 0x4a3bbdc0, 0x148e828, 0x1000};
168+
SegmentInfo{0x4a3bddc0, 0x148e828, 0x4a3bbdc0, 0x148e828, 0x1000, true};
168169
BC->SegmentMapInfo[0x4b84d5e8] =
169-
SegmentInfo{0x4b84d5e8, 0x294f830, 0x4b84a5e8, 0x3d3820, 0x1000};
170+
SegmentInfo{0x4b84d5e8, 0x294f830, 0x4b84a5e8, 0x3d3820, 0x1000, true};
170171

171172
std::optional<uint64_t> BaseAddress =
172173
BC->getBaseAddressForMapping(0x7f13f5556000, 0x10e8c000);
@@ -181,13 +182,13 @@ TEST_P(BinaryContextTester, BaseAddress2) {
181182
// Check that base address calculation is correct for a binary if the
182183
// alignment in ELF file are different from pagesize.
183184
// The segment layout is as follows:
184-
BC->SegmentMapInfo[0] = SegmentInfo{0, 0x2177c, 0, 0x2177c, 0x10000};
185+
BC->SegmentMapInfo[0] = SegmentInfo{0, 0x2177c, 0, 0x2177c, 0x10000, true};
185186
BC->SegmentMapInfo[0x31860] =
186-
SegmentInfo{0x31860, 0x370, 0x21860, 0x370, 0x10000};
187+
SegmentInfo{0x31860, 0x370, 0x21860, 0x370, 0x10000, true};
187188
BC->SegmentMapInfo[0x41c20] =
188-
SegmentInfo{0x41c20, 0x1f8, 0x21c20, 0x1f8, 0x10000};
189+
SegmentInfo{0x41c20, 0x1f8, 0x21c20, 0x1f8, 0x10000, true};
189190
BC->SegmentMapInfo[0x54e18] =
190-
SegmentInfo{0x54e18, 0x51, 0x24e18, 0x51, 0x10000};
191+
SegmentInfo{0x54e18, 0x51, 0x24e18, 0x51, 0x10000, true};
191192

192193
std::optional<uint64_t> BaseAddress =
193194
BC->getBaseAddressForMapping(0xaaaaea444000, 0x21000);
@@ -197,3 +198,22 @@ TEST_P(BinaryContextTester, BaseAddress2) {
197198
BaseAddress = BC->getBaseAddressForMapping(0xaaaaea444000, 0x11000);
198199
ASSERT_FALSE(BaseAddress.has_value());
199200
}
201+
202+
TEST_P(BinaryContextTester, BaseAddressSegmentsSmallerThanAlignment) {
203+
// Check that the correct segment is used to compute the base address
204+
// when multiple segments are close together in the ELF file (closer
205+
// than the required alignment in the process space).
206+
// See https://github.com/llvm/llvm-project/issues/109384
207+
BC->SegmentMapInfo[0] = SegmentInfo{0, 0x1d1c, 0, 0x1d1c, 0x10000, false};
208+
BC->SegmentMapInfo[0x11d40] =
209+
SegmentInfo{0x11d40, 0x11e0, 0x1d40, 0x11e0, 0x10000, true};
210+
BC->SegmentMapInfo[0x22f20] =
211+
SegmentInfo{0x22f20, 0x10e0, 0x2f20, 0x1f0, 0x10000, false};
212+
BC->SegmentMapInfo[0x33110] =
213+
SegmentInfo{0x33110, 0x89, 0x3110, 0x88, 0x10000, false};
214+
215+
std::optional<uint64_t> BaseAddress =
216+
BC->getBaseAddressForMapping(0xaaaaaaab1000, 0x1000);
217+
ASSERT_TRUE(BaseAddress.has_value());
218+
ASSERT_EQ(*BaseAddress, 0xaaaaaaaa0000ULL);
219+
}

0 commit comments

Comments
 (0)