xref: /llvm-project/bolt/unittests/Core/MemoryMaps.cpp (revision 2ccf7ed277df28651b94bbee9fccefdf22fb074f)
151003076SPaschalis Mpeis //===- bolt/unittest/Core/MemoryMaps.cpp ----------------------------------===//
251003076SPaschalis Mpeis //
351003076SPaschalis Mpeis // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
451003076SPaschalis Mpeis // See https://llvm.org/LICENSE.txt for license information.
551003076SPaschalis Mpeis // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
651003076SPaschalis Mpeis //
751003076SPaschalis Mpeis //===----------------------------------------------------------------------===//
851003076SPaschalis Mpeis 
951003076SPaschalis Mpeis #include "bolt/Core/BinaryContext.h"
1051003076SPaschalis Mpeis #include "bolt/Profile/DataAggregator.h"
1151003076SPaschalis Mpeis #include "llvm/BinaryFormat/ELF.h"
1251003076SPaschalis Mpeis #include "llvm/DebugInfo/DWARF/DWARFContext.h"
1351003076SPaschalis Mpeis #include "llvm/Support/CommandLine.h"
1451003076SPaschalis Mpeis #include "llvm/Support/TargetSelect.h"
1551003076SPaschalis Mpeis #include "llvm/Testing/Support/Error.h"
1651003076SPaschalis Mpeis #include "gtest/gtest.h"
1751003076SPaschalis Mpeis 
1851003076SPaschalis Mpeis using namespace llvm;
1951003076SPaschalis Mpeis using namespace llvm::object;
2051003076SPaschalis Mpeis using namespace llvm::ELF;
2151003076SPaschalis Mpeis using namespace bolt;
2251003076SPaschalis Mpeis 
2351003076SPaschalis Mpeis namespace opts {
2451003076SPaschalis Mpeis extern cl::opt<std::string> ReadPerfEvents;
2551003076SPaschalis Mpeis } // namespace opts
2651003076SPaschalis Mpeis 
2751003076SPaschalis Mpeis namespace {
2851003076SPaschalis Mpeis 
2951003076SPaschalis Mpeis /// Perform checks on memory map events normally captured in perf. Tests use
3051003076SPaschalis Mpeis /// the 'opts::ReadPerfEvents' flag to emulate these events, passing a custom
3151003076SPaschalis Mpeis /// 'perf script' output to DataAggregator.
3251003076SPaschalis Mpeis struct MemoryMapsTester : public testing::TestWithParam<Triple::ArchType> {
3351003076SPaschalis Mpeis   void SetUp() override {
3451003076SPaschalis Mpeis     initalizeLLVM();
3551003076SPaschalis Mpeis     prepareElf();
3651003076SPaschalis Mpeis     initializeBOLT();
3751003076SPaschalis Mpeis   }
3851003076SPaschalis Mpeis 
3951003076SPaschalis Mpeis protected:
4051003076SPaschalis Mpeis   void initalizeLLVM() {
4151003076SPaschalis Mpeis     llvm::InitializeAllTargetInfos();
4251003076SPaschalis Mpeis     llvm::InitializeAllTargetMCs();
4351003076SPaschalis Mpeis     llvm::InitializeAllAsmParsers();
4451003076SPaschalis Mpeis     llvm::InitializeAllDisassemblers();
4551003076SPaschalis Mpeis     llvm::InitializeAllTargets();
4651003076SPaschalis Mpeis     llvm::InitializeAllAsmPrinters();
4751003076SPaschalis Mpeis   }
4851003076SPaschalis Mpeis 
4951003076SPaschalis Mpeis   void prepareElf() {
5051003076SPaschalis Mpeis     memcpy(ElfBuf, "\177ELF", 4);
5151003076SPaschalis Mpeis     ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
5251003076SPaschalis Mpeis     EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
5351003076SPaschalis Mpeis     EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
5451003076SPaschalis Mpeis     EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64;
5551003076SPaschalis Mpeis     MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
5651003076SPaschalis Mpeis     ObjFile = cantFail(ObjectFile::createObjectFile(Source));
5751003076SPaschalis Mpeis   }
5851003076SPaschalis Mpeis 
5951003076SPaschalis Mpeis   void initializeBOLT() {
6051003076SPaschalis Mpeis     Relocation::Arch = ObjFile->makeTriple().getArch();
6151003076SPaschalis Mpeis     BC = cantFail(BinaryContext::createBinaryContext(
62*2ccf7ed2SJared Wyles         ObjFile->makeTriple(), std::make_shared<orc::SymbolStringPool>(),
63*2ccf7ed2SJared Wyles         ObjFile->getFileName(), nullptr, true,
6451003076SPaschalis Mpeis         DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()}));
6551003076SPaschalis Mpeis     ASSERT_FALSE(!BC);
6651003076SPaschalis Mpeis   }
6751003076SPaschalis Mpeis 
6851003076SPaschalis Mpeis   char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
6951003076SPaschalis Mpeis   std::unique_ptr<ObjectFile> ObjFile;
7051003076SPaschalis Mpeis   std::unique_ptr<BinaryContext> BC;
7151003076SPaschalis Mpeis };
7251003076SPaschalis Mpeis } // namespace
7351003076SPaschalis Mpeis 
7451003076SPaschalis Mpeis #ifdef X86_AVAILABLE
7551003076SPaschalis Mpeis 
7651003076SPaschalis Mpeis INSTANTIATE_TEST_SUITE_P(X86, MemoryMapsTester,
7751003076SPaschalis Mpeis                          ::testing::Values(Triple::x86_64));
7851003076SPaschalis Mpeis 
7951003076SPaschalis Mpeis #endif
8051003076SPaschalis Mpeis 
8151003076SPaschalis Mpeis #ifdef AARCH64_AVAILABLE
8251003076SPaschalis Mpeis 
8351003076SPaschalis Mpeis INSTANTIATE_TEST_SUITE_P(AArch64, MemoryMapsTester,
8451003076SPaschalis Mpeis                          ::testing::Values(Triple::aarch64));
8551003076SPaschalis Mpeis 
8651003076SPaschalis Mpeis #endif
8751003076SPaschalis Mpeis 
8851003076SPaschalis Mpeis /// Check that the correct mmap size is computed when we have multiple text
8951003076SPaschalis Mpeis /// segment mappings.
9051003076SPaschalis Mpeis TEST_P(MemoryMapsTester, ParseMultipleSegments) {
9151003076SPaschalis Mpeis   const int Pid = 1234;
9251003076SPaschalis Mpeis   StringRef Filename = "BINARY";
9351003076SPaschalis Mpeis   opts::ReadPerfEvents = formatv(
9451003076SPaschalis Mpeis       "name       0 [000]     0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
9551003076SPaschalis Mpeis       "[0xabc0000000(0x1000000) @ 0x11c0000 103:01 1573523 0]: r-xp {1}\n"
9651003076SPaschalis Mpeis       "name       0 [000]     0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
9751003076SPaschalis Mpeis       "[0xabc2000000(0x8000000) @ 0x31d0000 103:01 1573523 0]: r-xp {1}\n",
9851003076SPaschalis Mpeis       Pid, Filename);
9951003076SPaschalis Mpeis 
10051003076SPaschalis Mpeis   BC->SegmentMapInfo[0x11da000] =
10151003076SPaschalis Mpeis       SegmentInfo{0x11da000, 0x10da000, 0x11ca000, 0x10da000, 0x10000, true};
10251003076SPaschalis Mpeis   BC->SegmentMapInfo[0x31d0000] =
10351003076SPaschalis Mpeis       SegmentInfo{0x31d0000, 0x51ac82c, 0x31d0000, 0x3000000, 0x200000, true};
10451003076SPaschalis Mpeis 
10551003076SPaschalis Mpeis   DataAggregator DA("");
10651003076SPaschalis Mpeis   BC->setFilename(Filename);
10751003076SPaschalis Mpeis   Error Err = DA.preprocessProfile(*BC);
10851003076SPaschalis Mpeis 
10951003076SPaschalis Mpeis   // Ignore errors from perf2bolt when parsing memory events later on.
11051003076SPaschalis Mpeis   ASSERT_THAT_ERROR(std::move(Err), Succeeded());
11151003076SPaschalis Mpeis 
11251003076SPaschalis Mpeis   auto &BinaryMMapInfo = DA.getBinaryMMapInfo();
11351003076SPaschalis Mpeis   auto El = BinaryMMapInfo.find(Pid);
11451003076SPaschalis Mpeis   // Check that memory mapping is present and has the expected size.
11551003076SPaschalis Mpeis   ASSERT_NE(El, BinaryMMapInfo.end());
11651003076SPaschalis Mpeis   ASSERT_EQ(El->second.Size, static_cast<uint64_t>(0xb1d0000));
11751003076SPaschalis Mpeis }
11851003076SPaschalis Mpeis 
11951003076SPaschalis Mpeis /// Check that DataAggregator aborts when pre-processing an input binary
12051003076SPaschalis Mpeis /// with multiple text segments that have different base addresses.
12151003076SPaschalis Mpeis TEST_P(MemoryMapsTester, MultipleSegmentsMismatchedBaseAddress) {
12251003076SPaschalis Mpeis   const int Pid = 1234;
12351003076SPaschalis Mpeis   StringRef Filename = "BINARY";
12451003076SPaschalis Mpeis   opts::ReadPerfEvents = formatv(
12551003076SPaschalis Mpeis       "name       0 [000]     0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
12651003076SPaschalis Mpeis       "[0xabc0000000(0x1000000) @ 0x11c0000 103:01 1573523 0]: r-xp {1}\n"
12751003076SPaschalis Mpeis       "name       0 [000]     0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
12851003076SPaschalis Mpeis       "[0xabc2000000(0x8000000) @ 0x31d0000 103:01 1573523 0]: r-xp {1}\n",
12951003076SPaschalis Mpeis       Pid, Filename);
13051003076SPaschalis Mpeis 
13151003076SPaschalis Mpeis   BC->SegmentMapInfo[0x11da000] =
13251003076SPaschalis Mpeis       SegmentInfo{0x11da000, 0x10da000, 0x11ca000, 0x10da000, 0x10000, true};
13351003076SPaschalis Mpeis   // Using '0x31d0fff' FileOffset which triggers a different base address
13451003076SPaschalis Mpeis   // for this second text segment.
13551003076SPaschalis Mpeis   BC->SegmentMapInfo[0x31d0000] =
13651003076SPaschalis Mpeis       SegmentInfo{0x31d0000, 0x51ac82c, 0x31d0fff, 0x3000000, 0x200000, true};
13751003076SPaschalis Mpeis 
13851003076SPaschalis Mpeis   DataAggregator DA("");
13951003076SPaschalis Mpeis   BC->setFilename(Filename);
14051003076SPaschalis Mpeis   ASSERT_DEBUG_DEATH(
14151003076SPaschalis Mpeis       { Error Err = DA.preprocessProfile(*BC); },
14251003076SPaschalis Mpeis       "Base address on multiple segment mappings should match");
14351003076SPaschalis Mpeis }
144