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