12f09f445SMaksim Panchenko //===- bolt/Profile/BoltAddressTranslation.cpp ----------------------------===// 2a34c753fSRafael Auler // 3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information. 5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a34c753fSRafael Auler // 7a34c753fSRafael Auler //===----------------------------------------------------------------------===// 82f09f445SMaksim Panchenko 9a34c753fSRafael Auler #include "bolt/Profile/BoltAddressTranslation.h" 10a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h" 11df7d2b2fSAmir Ayupov #include "llvm/ADT/APInt.h" 12a34c753fSRafael Auler #include "llvm/Support/Errc.h" 13565f40d6SAmir Ayupov #include "llvm/Support/Error.h" 14565f40d6SAmir Ayupov #include "llvm/Support/LEB128.h" 15a34c753fSRafael Auler 16a34c753fSRafael Auler #define DEBUG_TYPE "bolt-bat" 17a34c753fSRafael Auler 18a34c753fSRafael Auler namespace llvm { 19a34c753fSRafael Auler namespace bolt { 20a34c753fSRafael Auler 21a34c753fSRafael Auler const char *BoltAddressTranslation::SECTION_NAME = ".note.bolt_bat"; 22a34c753fSRafael Auler 2350574638SAmir Ayupov void BoltAddressTranslation::writeEntriesForBB( 2450574638SAmir Ayupov MapTy &Map, const BinaryBasicBlock &BB, uint64_t FuncInputAddress, 2550574638SAmir Ayupov uint64_t FuncOutputAddress) const { 26a34c753fSRafael Auler const uint64_t BBOutputOffset = 27a91cd53dSAmir Ayupov BB.getOutputAddressRange().first - FuncOutputAddress; 28a34c753fSRafael Auler const uint32_t BBInputOffset = BB.getInputOffset(); 29a34c753fSRafael Auler 30fc0ced73SRafael Auler // Every output BB must track back to an input BB for profile collection 31fc0ced73SRafael Auler // in bolted binaries. If we are missing an offset, it means this block was 32fc0ced73SRafael Auler // created by a pass. We will skip writing any entries for it, and this means 33fc0ced73SRafael Auler // any traffic happening in this block will map to the previous block in the 34fc0ced73SRafael Auler // layout. This covers the case where an input basic block is split into two, 35fc0ced73SRafael Auler // and the second one lacks any offset. 36fc0ced73SRafael Auler if (BBInputOffset == BinaryBasicBlock::INVALID_OFFSET) 37fc0ced73SRafael Auler return; 38a34c753fSRafael Auler 39a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BB " << BB.getName() << "\n"); 40a34c753fSRafael Auler LLVM_DEBUG(dbgs() << " Key: " << Twine::utohexstr(BBOutputOffset) 41a34c753fSRafael Auler << " Val: " << Twine::utohexstr(BBInputOffset) << "\n"); 42a91cd53dSAmir Ayupov // NB: in `writeEntriesForBB` we use the input address because hashes are 43a91cd53dSAmir Ayupov // saved early in `saveMetadata` before output addresses are assigned. 44a91cd53dSAmir Ayupov const BBHashMapTy &BBHashMap = getBBHashMap(FuncInputAddress); 45a91cd53dSAmir Ayupov (void)BBHashMap; 46a91cd53dSAmir Ayupov LLVM_DEBUG( 47a91cd53dSAmir Ayupov dbgs() << formatv(" Hash: {0:x}\n", BBHashMap.getBBHash(BBInputOffset))); 48a91cd53dSAmir Ayupov LLVM_DEBUG( 49a91cd53dSAmir Ayupov dbgs() << formatv(" Index: {0}\n", BBHashMap.getBBIndex(BBInputOffset))); 50a34c753fSRafael Auler // In case of conflicts (same Key mapping to different Vals), the last 51a34c753fSRafael Auler // update takes precedence. Of course it is not ideal to have conflicts and 52a34c753fSRafael Auler // those happen when we have an empty BB that either contained only 53a34c753fSRafael Auler // NOPs or a jump to the next block (successor). Either way, the successor 54a34c753fSRafael Auler // and this deleted block will both share the same output address (the same 55a34c753fSRafael Auler // key), and we need to map back. We choose here to privilege the successor by 56a34c753fSRafael Auler // allowing it to overwrite the previously inserted key in the map. 57d1d9545eSAmir Ayupov Map.emplace(BBOutputOffset, BBInputOffset << 1); 58a34c753fSRafael Auler 5923c8d382SJob Noorman const auto &IOAddressMap = 6023c8d382SJob Noorman BB.getFunction()->getBinaryContext().getIOAddressMap(); 6123c8d382SJob Noorman 6223c8d382SJob Noorman for (const auto &[InputOffset, Sym] : BB.getLocSyms()) { 6323c8d382SJob Noorman const auto InputAddress = BB.getFunction()->getAddress() + InputOffset; 6423c8d382SJob Noorman const auto OutputAddress = IOAddressMap.lookup(InputAddress); 6523c8d382SJob Noorman assert(OutputAddress && "Unknown instruction address"); 66a91cd53dSAmir Ayupov const auto OutputOffset = *OutputAddress - FuncOutputAddress; 67a34c753fSRafael Auler 68a34c753fSRafael Auler // Is this the first instruction in the BB? No need to duplicate the entry. 69a34c753fSRafael Auler if (OutputOffset == BBOutputOffset) 70a34c753fSRafael Auler continue; 71a34c753fSRafael Auler 72a34c753fSRafael Auler LLVM_DEBUG(dbgs() << " Key: " << Twine::utohexstr(OutputOffset) << " Val: " 73a34c753fSRafael Auler << Twine::utohexstr(InputOffset) << " (branch)\n"); 74d1d9545eSAmir Ayupov Map.emplace(OutputOffset, (InputOffset << 1) | BRANCHENTRY); 75a34c753fSRafael Auler } 76a34c753fSRafael Auler } 77a34c753fSRafael Auler 78fc0ced73SRafael Auler void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) { 79a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Writing BOLT Address Translation Tables\n"); 80a34c753fSRafael Auler for (auto &BFI : BC.getBinaryFunctions()) { 81fc0ced73SRafael Auler const BinaryFunction &Function = BFI.second; 82ad00e7e5SAmir Ayupov const uint64_t InputAddress = Function.getAddress(); 83ad00e7e5SAmir Ayupov const uint64_t OutputAddress = Function.getOutputAddress(); 84a34c753fSRafael Auler // We don't need a translation table if the body of the function hasn't 85a34c753fSRafael Auler // changed 86fc0ced73SRafael Auler if (Function.isIgnored() || (!BC.HasRelocations && !Function.isSimple())) 87a34c753fSRafael Auler continue; 88a34c753fSRafael Auler 891b763f23SAmir Ayupov uint32_t NumSecondaryEntryPoints = 0; 901b763f23SAmir Ayupov Function.forEachEntryPoint([&](uint64_t Offset, const MCSymbol *) { 911b763f23SAmir Ayupov if (!Offset) 921b763f23SAmir Ayupov return true; 931b763f23SAmir Ayupov ++NumSecondaryEntryPoints; 941b763f23SAmir Ayupov SecondaryEntryPointsMap[OutputAddress].push_back(Offset); 951b763f23SAmir Ayupov return true; 961b763f23SAmir Ayupov }); 97ad00e7e5SAmir Ayupov 98a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Function name: " << Function.getPrintName() << "\n"); 99a34c753fSRafael Auler LLVM_DEBUG(dbgs() << " Address reference: 0x" 100a34c753fSRafael Auler << Twine::utohexstr(Function.getOutputAddress()) << "\n"); 10102276239SAmir Ayupov LLVM_DEBUG(dbgs() << formatv(" Hash: {0:x}\n", getBFHash(InputAddress))); 1021b763f23SAmir Ayupov LLVM_DEBUG(dbgs() << " Secondary Entry Points: " << NumSecondaryEntryPoints 1031b763f23SAmir Ayupov << '\n'); 1049b6e7861SFabian Parzefall 105a34c753fSRafael Auler MapTy Map; 1069b6e7861SFabian Parzefall for (const BinaryBasicBlock *const BB : 1079b6e7861SFabian Parzefall Function.getLayout().getMainFragment()) 108a91cd53dSAmir Ayupov writeEntriesForBB(Map, *BB, InputAddress, OutputAddress); 109d1d9545eSAmir Ayupov // Add entries for deleted blocks. They are still required for correct BB 110d1d9545eSAmir Ayupov // mapping of branches modified by SCTC. By convention, they would have the 111d1d9545eSAmir Ayupov // end of the function as output address. 112d1d9545eSAmir Ayupov const BBHashMapTy &BBHashMap = getBBHashMap(InputAddress); 113d1d9545eSAmir Ayupov if (BBHashMap.size() != Function.size()) { 114d1d9545eSAmir Ayupov const uint64_t EndOffset = Function.getOutputSize(); 115d1d9545eSAmir Ayupov std::unordered_set<uint32_t> MappedInputOffsets; 116d1d9545eSAmir Ayupov for (const BinaryBasicBlock &BB : Function) 117d1d9545eSAmir Ayupov MappedInputOffsets.emplace(BB.getInputOffset()); 118d1d9545eSAmir Ayupov for (const auto &[InputOffset, _] : BBHashMap) 119d1d9545eSAmir Ayupov if (!llvm::is_contained(MappedInputOffsets, InputOffset)) 120d1d9545eSAmir Ayupov Map.emplace(EndOffset, InputOffset << 1); 121d1d9545eSAmir Ayupov } 1229b6e7861SFabian Parzefall Maps.emplace(Function.getOutputAddress(), std::move(Map)); 123ad00e7e5SAmir Ayupov ReverseMap.emplace(OutputAddress, InputAddress); 124a34c753fSRafael Auler 1259b6e7861SFabian Parzefall if (!Function.isSplit()) 126a34c753fSRafael Auler continue; 127a34c753fSRafael Auler 1289b6e7861SFabian Parzefall // Split maps 1296304e382SFabian Parzefall LLVM_DEBUG(dbgs() << " Cold part\n"); 1309b6e7861SFabian Parzefall for (const FunctionFragment &FF : 1319b6e7861SFabian Parzefall Function.getLayout().getSplitFragments()) { 132dc1da939SAmir Ayupov // Skip empty fragments to avoid adding zero-address entries to maps. 133dc1da939SAmir Ayupov if (FF.empty()) 134dc1da939SAmir Ayupov continue; 135ad00e7e5SAmir Ayupov ColdPartSource.emplace(FF.getAddress(), Function.getOutputAddress()); 1369b6e7861SFabian Parzefall Map.clear(); 1379b6e7861SFabian Parzefall for (const BinaryBasicBlock *const BB : FF) 138a91cd53dSAmir Ayupov writeEntriesForBB(Map, *BB, InputAddress, FF.getAddress()); 1399b6e7861SFabian Parzefall 1409b6e7861SFabian Parzefall Maps.emplace(FF.getAddress(), std::move(Map)); 141a34c753fSRafael Auler } 142a34c753fSRafael Auler } 143a34c753fSRafael Auler 1448f1d94aaSAmir Ayupov // Output addresses are delta-encoded 1458f1d94aaSAmir Ayupov uint64_t PrevAddress = 0; 146*79d695f0SAmir Ayupov writeMaps</*Cold=*/false>(PrevAddress, OS); 147*79d695f0SAmir Ayupov writeMaps</*Cold=*/true>(PrevAddress, OS); 148dcba0771SAmir Ayupov 14952cf0711SAmir Ayupov BC.outs() << "BOLT-INFO: Wrote " << Maps.size() << " BAT maps\n"; 150a91cd53dSAmir Ayupov BC.outs() << "BOLT-INFO: Wrote " << FuncHashes.getNumFunctions() 151a91cd53dSAmir Ayupov << " function and " << FuncHashes.getNumBasicBlocks() 152a91cd53dSAmir Ayupov << " basic block hashes\n"; 153dcba0771SAmir Ayupov } 154dcba0771SAmir Ayupov 15550574638SAmir Ayupov APInt BoltAddressTranslation::calculateBranchEntriesBitMask( 15650574638SAmir Ayupov MapTy &Map, size_t EqualElems) const { 157df7d2b2fSAmir Ayupov APInt BitMask(alignTo(EqualElems, 8), 0); 158df7d2b2fSAmir Ayupov size_t Index = 0; 159df7d2b2fSAmir Ayupov for (std::pair<const uint32_t, uint32_t> &KeyVal : Map) { 160df7d2b2fSAmir Ayupov if (Index == EqualElems) 161df7d2b2fSAmir Ayupov break; 162df7d2b2fSAmir Ayupov const uint32_t OutputOffset = KeyVal.second; 163df7d2b2fSAmir Ayupov if (OutputOffset & BRANCHENTRY) 164df7d2b2fSAmir Ayupov BitMask.setBit(Index); 165df7d2b2fSAmir Ayupov ++Index; 166df7d2b2fSAmir Ayupov } 167df7d2b2fSAmir Ayupov return BitMask; 168df7d2b2fSAmir Ayupov } 169df7d2b2fSAmir Ayupov 170b79b6f9cSAmir Ayupov size_t BoltAddressTranslation::getNumEqualOffsets(const MapTy &Map, 171b79b6f9cSAmir Ayupov uint32_t Skew) const { 172df7d2b2fSAmir Ayupov size_t EqualOffsets = 0; 173df7d2b2fSAmir Ayupov for (const std::pair<const uint32_t, uint32_t> &KeyVal : Map) { 174df7d2b2fSAmir Ayupov const uint32_t OutputOffset = KeyVal.first; 175df7d2b2fSAmir Ayupov const uint32_t InputOffset = KeyVal.second >> 1; 176b79b6f9cSAmir Ayupov if (OutputOffset == InputOffset - Skew) 177df7d2b2fSAmir Ayupov ++EqualOffsets; 178df7d2b2fSAmir Ayupov else 179df7d2b2fSAmir Ayupov break; 180df7d2b2fSAmir Ayupov } 181df7d2b2fSAmir Ayupov return EqualOffsets; 182df7d2b2fSAmir Ayupov } 183df7d2b2fSAmir Ayupov 184dcba0771SAmir Ayupov template <bool Cold> 185*79d695f0SAmir Ayupov void BoltAddressTranslation::writeMaps(uint64_t &PrevAddress, raw_ostream &OS) { 186dcba0771SAmir Ayupov const uint32_t NumFuncs = 187dcba0771SAmir Ayupov llvm::count_if(llvm::make_first_range(Maps), [&](const uint64_t Address) { 188dcba0771SAmir Ayupov return Cold == ColdPartSource.count(Address); 189dcba0771SAmir Ayupov }); 190565f40d6SAmir Ayupov encodeULEB128(NumFuncs, OS); 191dcba0771SAmir Ayupov LLVM_DEBUG(dbgs() << "Writing " << NumFuncs << (Cold ? " cold" : "") 192dcba0771SAmir Ayupov << " functions for BAT.\n"); 193dcba0771SAmir Ayupov size_t PrevIndex = 0; 194a34c753fSRafael Auler for (auto &MapEntry : Maps) { 195a34c753fSRafael Auler const uint64_t Address = MapEntry.first; 196dcba0771SAmir Ayupov // Only process cold fragments in cold mode, and vice versa. 197dcba0771SAmir Ayupov if (Cold != ColdPartSource.count(Address)) 198dcba0771SAmir Ayupov continue; 199a91cd53dSAmir Ayupov // NB: in `writeMaps` we use the input address because hashes are saved 200a91cd53dSAmir Ayupov // early in `saveMetadata` before output addresses are assigned. 201ad00e7e5SAmir Ayupov const uint64_t HotInputAddress = 202ad00e7e5SAmir Ayupov ReverseMap[Cold ? ColdPartSource[Address] : Address]; 203a34c753fSRafael Auler MapTy &Map = MapEntry.second; 204a34c753fSRafael Auler const uint32_t NumEntries = Map.size(); 205a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Writing " << NumEntries << " entries for 0x" 206a34c753fSRafael Auler << Twine::utohexstr(Address) << ".\n"); 2078fb8ad66SAmir Ayupov encodeULEB128(Address - PrevAddress, OS); 2088fb8ad66SAmir Ayupov PrevAddress = Address; 2091b763f23SAmir Ayupov const uint32_t NumSecondaryEntryPoints = 2101b763f23SAmir Ayupov SecondaryEntryPointsMap.count(Address) 2111b763f23SAmir Ayupov ? SecondaryEntryPointsMap[Address].size() 2121b763f23SAmir Ayupov : 0; 213b79b6f9cSAmir Ayupov uint32_t Skew = 0; 214dcba0771SAmir Ayupov if (Cold) { 215*79d695f0SAmir Ayupov auto HotEntryIt = llvm::lower_bound(HotFuncs, ColdPartSource[Address]); 216*79d695f0SAmir Ayupov assert(HotEntryIt != HotFuncs.end()); 217*79d695f0SAmir Ayupov size_t HotIndex = std::distance(HotFuncs.begin(), HotEntryIt); 218dcba0771SAmir Ayupov encodeULEB128(HotIndex - PrevIndex, OS); 219dcba0771SAmir Ayupov PrevIndex = HotIndex; 220b79b6f9cSAmir Ayupov // Skew of all input offsets for cold fragments is simply the first input 221b79b6f9cSAmir Ayupov // offset. 222b79b6f9cSAmir Ayupov Skew = Map.begin()->second >> 1; 223b79b6f9cSAmir Ayupov encodeULEB128(Skew, OS); 224ad00e7e5SAmir Ayupov } else { 225*79d695f0SAmir Ayupov HotFuncs.push_back(Address); 226ad00e7e5SAmir Ayupov // Function hash 227a91cd53dSAmir Ayupov size_t BFHash = getBFHash(HotInputAddress); 228a91cd53dSAmir Ayupov LLVM_DEBUG(dbgs() << "Hash: " << formatv("{0:x}\n", BFHash)); 229a91cd53dSAmir Ayupov OS.write(reinterpret_cast<char *>(&BFHash), 8); 230ceba3a38SAmir Ayupov // Number of basic blocks 231e64eede0SAmir Ayupov size_t NumBasicBlocks = NumBasicBlocksMap[HotInputAddress]; 232ceba3a38SAmir Ayupov LLVM_DEBUG(dbgs() << "Basic blocks: " << NumBasicBlocks << '\n'); 233ceba3a38SAmir Ayupov encodeULEB128(NumBasicBlocks, OS); 2341b763f23SAmir Ayupov // Secondary entry points 2351b763f23SAmir Ayupov encodeULEB128(NumSecondaryEntryPoints, OS); 2361b763f23SAmir Ayupov LLVM_DEBUG(dbgs() << "Secondary Entry Points: " << NumSecondaryEntryPoints 2371b763f23SAmir Ayupov << '\n'); 238dcba0771SAmir Ayupov } 239565f40d6SAmir Ayupov encodeULEB128(NumEntries, OS); 240b79b6f9cSAmir Ayupov // Encode the number of equal offsets (output = input - skew) in the 241b79b6f9cSAmir Ayupov // beginning of the function. Only encode one offset in these cases. 242b79b6f9cSAmir Ayupov const size_t EqualElems = getNumEqualOffsets(Map, Skew); 243df7d2b2fSAmir Ayupov encodeULEB128(EqualElems, OS); 244df7d2b2fSAmir Ayupov if (EqualElems) { 245df7d2b2fSAmir Ayupov const size_t BranchEntriesBytes = alignTo(EqualElems, 8) / 8; 246df7d2b2fSAmir Ayupov APInt BranchEntries = calculateBranchEntriesBitMask(Map, EqualElems); 247df7d2b2fSAmir Ayupov OS.write(reinterpret_cast<const char *>(BranchEntries.getRawData()), 248df7d2b2fSAmir Ayupov BranchEntriesBytes); 249df7d2b2fSAmir Ayupov LLVM_DEBUG({ 250df7d2b2fSAmir Ayupov dbgs() << "BranchEntries: "; 251df7d2b2fSAmir Ayupov SmallString<8> BitMaskStr; 252df7d2b2fSAmir Ayupov BranchEntries.toString(BitMaskStr, 2, false); 253df7d2b2fSAmir Ayupov dbgs() << BitMaskStr << '\n'; 254df7d2b2fSAmir Ayupov }); 255df7d2b2fSAmir Ayupov } 256a91cd53dSAmir Ayupov const BBHashMapTy &BBHashMap = getBBHashMap(HotInputAddress); 257df7d2b2fSAmir Ayupov size_t Index = 0; 2588f1d94aaSAmir Ayupov uint64_t InOffset = 0; 259b0e23639SAmir Ayupov size_t PrevBBIndex = 0; 260bbe07989SAmir Ayupov // Output and Input addresses and delta-encoded 261a34c753fSRafael Auler for (std::pair<const uint32_t, uint32_t> &KeyVal : Map) { 2628f1d94aaSAmir Ayupov const uint64_t OutputAddress = KeyVal.first + Address; 2638f1d94aaSAmir Ayupov encodeULEB128(OutputAddress - PrevAddress, OS); 2648f1d94aaSAmir Ayupov PrevAddress = OutputAddress; 265df7d2b2fSAmir Ayupov if (Index++ >= EqualElems) 266bbe07989SAmir Ayupov encodeSLEB128(KeyVal.second - InOffset, OS); 267df7d2b2fSAmir Ayupov InOffset = KeyVal.second; // Keeping InOffset as if BRANCHENTRY is encoded 268ad00e7e5SAmir Ayupov if ((InOffset & BRANCHENTRY) == 0) { 269a91cd53dSAmir Ayupov const bool IsBlock = BBHashMap.isInputBlock(InOffset >> 1); 270a91cd53dSAmir Ayupov unsigned BBIndex = IsBlock ? BBHashMap.getBBIndex(InOffset >> 1) : 0; 271a91cd53dSAmir Ayupov size_t BBHash = IsBlock ? BBHashMap.getBBHash(InOffset >> 1) : 0; 272ad00e7e5SAmir Ayupov OS.write(reinterpret_cast<char *>(&BBHash), 8); 273b0e23639SAmir Ayupov // Basic block index in the input binary 274b0e23639SAmir Ayupov encodeULEB128(BBIndex - PrevBBIndex, OS); 275b0e23639SAmir Ayupov PrevBBIndex = BBIndex; 276b0e23639SAmir Ayupov LLVM_DEBUG(dbgs() << formatv("{0:x} -> {1:x} {2:x} {3}\n", KeyVal.first, 277b0e23639SAmir Ayupov InOffset >> 1, BBHash, BBIndex)); 278ad00e7e5SAmir Ayupov } 279a34c753fSRafael Auler } 2801b763f23SAmir Ayupov uint32_t PrevOffset = 0; 2811b763f23SAmir Ayupov if (!Cold && NumSecondaryEntryPoints) { 2821b763f23SAmir Ayupov LLVM_DEBUG(dbgs() << "Secondary entry points: "); 2831b763f23SAmir Ayupov // Secondary entry point offsets, delta-encoded 2841b763f23SAmir Ayupov for (uint32_t Offset : SecondaryEntryPointsMap[Address]) { 2851b763f23SAmir Ayupov encodeULEB128(Offset - PrevOffset, OS); 2861b763f23SAmir Ayupov LLVM_DEBUG(dbgs() << formatv("{0:x} ", Offset)); 2871b763f23SAmir Ayupov PrevOffset = Offset; 2881b763f23SAmir Ayupov } 2891b763f23SAmir Ayupov LLVM_DEBUG(dbgs() << '\n'); 2901b763f23SAmir Ayupov } 291a34c753fSRafael Auler } 292a34c753fSRafael Auler } 293a34c753fSRafael Auler 29452cf0711SAmir Ayupov std::error_code BoltAddressTranslation::parse(raw_ostream &OS, StringRef Buf) { 295a34c753fSRafael Auler DataExtractor DE = DataExtractor(Buf, true, 8); 296a34c753fSRafael Auler uint64_t Offset = 0; 297a34c753fSRafael Auler if (Buf.size() < 12) 298a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 299a34c753fSRafael Auler 300a34c753fSRafael Auler const uint32_t NameSz = DE.getU32(&Offset); 301a34c753fSRafael Auler const uint32_t DescSz = DE.getU32(&Offset); 302a34c753fSRafael Auler const uint32_t Type = DE.getU32(&Offset); 303a34c753fSRafael Auler 304a34c753fSRafael Auler if (Type != BinarySection::NT_BOLT_BAT || 305a34c753fSRafael Auler Buf.size() + Offset < alignTo(NameSz, 4) + DescSz) 306a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 307a34c753fSRafael Auler 308a34c753fSRafael Auler StringRef Name = Buf.slice(Offset, Offset + NameSz); 309a34c753fSRafael Auler Offset = alignTo(Offset + NameSz, 4); 3108901f718SKazu Hirata if (!Name.starts_with("BOLT")) 311a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 312a34c753fSRafael Auler 313565f40d6SAmir Ayupov Error Err(Error::success()); 3148f1d94aaSAmir Ayupov uint64_t PrevAddress = 0; 315*79d695f0SAmir Ayupov parseMaps</*Cold=*/false>(PrevAddress, DE, Offset, Err); 316*79d695f0SAmir Ayupov parseMaps</*Cold=*/true>(PrevAddress, DE, Offset, Err); 31752cf0711SAmir Ayupov OS << "BOLT-INFO: Parsed " << Maps.size() << " BAT entries\n"; 318dcba0771SAmir Ayupov return errorToErrorCode(std::move(Err)); 319dcba0771SAmir Ayupov } 320dcba0771SAmir Ayupov 321dcba0771SAmir Ayupov template <bool Cold> 322*79d695f0SAmir Ayupov void BoltAddressTranslation::parseMaps(uint64_t &PrevAddress, DataExtractor &DE, 3238f1d94aaSAmir Ayupov uint64_t &Offset, Error &Err) { 324565f40d6SAmir Ayupov const uint32_t NumFunctions = DE.getULEB128(&Offset, &Err); 325dcba0771SAmir Ayupov LLVM_DEBUG(dbgs() << "Parsing " << NumFunctions << (Cold ? " cold" : "") 326dcba0771SAmir Ayupov << " functions\n"); 327dcba0771SAmir Ayupov size_t HotIndex = 0; 328a34c753fSRafael Auler for (uint32_t I = 0; I < NumFunctions; ++I) { 3298fb8ad66SAmir Ayupov const uint64_t Address = PrevAddress + DE.getULEB128(&Offset, &Err); 330ad00e7e5SAmir Ayupov uint64_t HotAddress = Cold ? 0 : Address; 3318fb8ad66SAmir Ayupov PrevAddress = Address; 3321b763f23SAmir Ayupov uint32_t SecondaryEntryPoints = 0; 333b79b6f9cSAmir Ayupov uint64_t ColdInputSkew = 0; 334dcba0771SAmir Ayupov if (Cold) { 335dcba0771SAmir Ayupov HotIndex += DE.getULEB128(&Offset, &Err); 336ad00e7e5SAmir Ayupov HotAddress = HotFuncs[HotIndex]; 337ad00e7e5SAmir Ayupov ColdPartSource.emplace(Address, HotAddress); 338b79b6f9cSAmir Ayupov ColdInputSkew = DE.getULEB128(&Offset, &Err); 339dcba0771SAmir Ayupov } else { 340dcba0771SAmir Ayupov HotFuncs.push_back(Address); 341ad00e7e5SAmir Ayupov // Function hash 342ad00e7e5SAmir Ayupov const size_t FuncHash = DE.getU64(&Offset, &Err); 343a91cd53dSAmir Ayupov FuncHashes.addEntry(Address, FuncHash); 344ad00e7e5SAmir Ayupov LLVM_DEBUG(dbgs() << formatv("{0:x}: hash {1:x}\n", Address, FuncHash)); 345ceba3a38SAmir Ayupov // Number of basic blocks 346ceba3a38SAmir Ayupov const size_t NumBasicBlocks = DE.getULEB128(&Offset, &Err); 347ceba3a38SAmir Ayupov NumBasicBlocksMap.emplace(Address, NumBasicBlocks); 348ceba3a38SAmir Ayupov LLVM_DEBUG(dbgs() << formatv("{0:x}: #bbs {1}, {2} bytes\n", Address, 349ceba3a38SAmir Ayupov NumBasicBlocks, 350ceba3a38SAmir Ayupov getULEB128Size(NumBasicBlocks))); 3511b763f23SAmir Ayupov // Secondary entry points 3521b763f23SAmir Ayupov SecondaryEntryPoints = DE.getULEB128(&Offset, &Err); 3531b763f23SAmir Ayupov LLVM_DEBUG( 3541b763f23SAmir Ayupov dbgs() << formatv("{0:x}: secondary entry points {1}, {2} bytes\n", 3551b763f23SAmir Ayupov Address, SecondaryEntryPoints, 3561b763f23SAmir Ayupov getULEB128Size(SecondaryEntryPoints))); 357dcba0771SAmir Ayupov } 358565f40d6SAmir Ayupov const uint32_t NumEntries = DE.getULEB128(&Offset, &Err); 359b79b6f9cSAmir Ayupov // Equal offsets. 360b79b6f9cSAmir Ayupov const size_t EqualElems = DE.getULEB128(&Offset, &Err); 361df7d2b2fSAmir Ayupov APInt BEBitMask; 362b79b6f9cSAmir Ayupov LLVM_DEBUG(dbgs() << formatv("Equal offsets: {0}, {1} bytes\n", EqualElems, 363b79b6f9cSAmir Ayupov getULEB128Size(EqualElems))); 364df7d2b2fSAmir Ayupov if (EqualElems) { 365df7d2b2fSAmir Ayupov const size_t BranchEntriesBytes = alignTo(EqualElems, 8) / 8; 366df7d2b2fSAmir Ayupov BEBitMask = APInt(alignTo(EqualElems, 8), 0); 367df7d2b2fSAmir Ayupov LoadIntFromMemory( 368df7d2b2fSAmir Ayupov BEBitMask, 369df7d2b2fSAmir Ayupov reinterpret_cast<const uint8_t *>( 370df7d2b2fSAmir Ayupov DE.getBytes(&Offset, BranchEntriesBytes, &Err).data()), 371df7d2b2fSAmir Ayupov BranchEntriesBytes); 372df7d2b2fSAmir Ayupov LLVM_DEBUG({ 373df7d2b2fSAmir Ayupov dbgs() << "BEBitMask: "; 374df7d2b2fSAmir Ayupov SmallString<8> BitMaskStr; 375df7d2b2fSAmir Ayupov BEBitMask.toString(BitMaskStr, 2, false); 376df7d2b2fSAmir Ayupov dbgs() << BitMaskStr << ", " << BranchEntriesBytes << " bytes\n"; 377df7d2b2fSAmir Ayupov }); 378df7d2b2fSAmir Ayupov } 379a34c753fSRafael Auler MapTy Map; 380a34c753fSRafael Auler 381a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Parsing " << NumEntries << " entries for 0x" 382a34c753fSRafael Auler << Twine::utohexstr(Address) << "\n"); 3838f1d94aaSAmir Ayupov uint64_t InputOffset = 0; 384b0e23639SAmir Ayupov size_t BBIndex = 0; 385a34c753fSRafael Auler for (uint32_t J = 0; J < NumEntries; ++J) { 386bbe07989SAmir Ayupov const uint64_t OutputDelta = DE.getULEB128(&Offset, &Err); 3878f1d94aaSAmir Ayupov const uint64_t OutputAddress = PrevAddress + OutputDelta; 3888f1d94aaSAmir Ayupov const uint64_t OutputOffset = OutputAddress - Address; 3898f1d94aaSAmir Ayupov PrevAddress = OutputAddress; 390df7d2b2fSAmir Ayupov int64_t InputDelta = 0; 391df7d2b2fSAmir Ayupov if (J < EqualElems) { 3928927ac86SKazu Hirata InputOffset = ((OutputOffset + ColdInputSkew) << 1) | BEBitMask[J]; 393df7d2b2fSAmir Ayupov } else { 394df7d2b2fSAmir Ayupov InputDelta = DE.getSLEB128(&Offset, &Err); 395bbe07989SAmir Ayupov InputOffset += InputDelta; 396df7d2b2fSAmir Ayupov } 397bbe07989SAmir Ayupov Map.insert(std::pair<uint32_t, uint32_t>(OutputOffset, InputOffset)); 398ad00e7e5SAmir Ayupov size_t BBHash = 0; 399b0e23639SAmir Ayupov size_t BBIndexDelta = 0; 400ad00e7e5SAmir Ayupov const bool IsBranchEntry = InputOffset & BRANCHENTRY; 401ad00e7e5SAmir Ayupov if (!IsBranchEntry) { 402ad00e7e5SAmir Ayupov BBHash = DE.getU64(&Offset, &Err); 403b0e23639SAmir Ayupov BBIndexDelta = DE.getULEB128(&Offset, &Err); 404b0e23639SAmir Ayupov BBIndex += BBIndexDelta; 405ad00e7e5SAmir Ayupov // Map basic block hash to hot fragment by input offset 406a91cd53dSAmir Ayupov getBBHashMap(HotAddress).addEntry(InputOffset >> 1, BBIndex, BBHash); 407ad00e7e5SAmir Ayupov } 408ad00e7e5SAmir Ayupov LLVM_DEBUG({ 409ad00e7e5SAmir Ayupov dbgs() << formatv( 410ad00e7e5SAmir Ayupov "{0:x} -> {1:x} ({2}/{3}b -> {4}/{5}b), {6:x}", OutputOffset, 411ad00e7e5SAmir Ayupov InputOffset, OutputDelta, getULEB128Size(OutputDelta), InputDelta, 412ad00e7e5SAmir Ayupov (J < EqualElems) ? 0 : getSLEB128Size(InputDelta), OutputAddress); 413b0e23639SAmir Ayupov if (!IsBranchEntry) { 414b0e23639SAmir Ayupov dbgs() << formatv(" {0:x} {1}/{2}b", BBHash, BBIndex, 415b0e23639SAmir Ayupov getULEB128Size(BBIndexDelta)); 416b0e23639SAmir Ayupov } 417ad00e7e5SAmir Ayupov dbgs() << '\n'; 418ad00e7e5SAmir Ayupov }); 419a34c753fSRafael Auler } 420a34c753fSRafael Auler Maps.insert(std::pair<uint64_t, MapTy>(Address, Map)); 4211b763f23SAmir Ayupov if (!Cold && SecondaryEntryPoints) { 4221b763f23SAmir Ayupov uint32_t EntryPointOffset = 0; 4231b763f23SAmir Ayupov LLVM_DEBUG(dbgs() << "Secondary entry points: "); 4241b763f23SAmir Ayupov for (uint32_t EntryPointId = 0; EntryPointId != SecondaryEntryPoints; 4251b763f23SAmir Ayupov ++EntryPointId) { 4261b763f23SAmir Ayupov uint32_t OffsetDelta = DE.getULEB128(&Offset, &Err); 4271b763f23SAmir Ayupov EntryPointOffset += OffsetDelta; 4281b763f23SAmir Ayupov SecondaryEntryPointsMap[Address].push_back(EntryPointOffset); 4291b763f23SAmir Ayupov LLVM_DEBUG(dbgs() << formatv("{0:x}/{1}b ", EntryPointOffset, 4301b763f23SAmir Ayupov getULEB128Size(OffsetDelta))); 4311b763f23SAmir Ayupov } 4321b763f23SAmir Ayupov LLVM_DEBUG(dbgs() << '\n'); 4331b763f23SAmir Ayupov } 434a34c753fSRafael Auler } 435a34c753fSRafael Auler } 436a34c753fSRafael Auler 43750574638SAmir Ayupov void BoltAddressTranslation::dump(raw_ostream &OS) const { 438fc0ced73SRafael Auler const size_t NumTables = Maps.size(); 439fc0ced73SRafael Auler OS << "BAT tables for " << NumTables << " functions:\n"; 440fc0ced73SRafael Auler for (const auto &MapEntry : Maps) { 441ad00e7e5SAmir Ayupov const uint64_t Address = MapEntry.first; 442ad00e7e5SAmir Ayupov const uint64_t HotAddress = fetchParentAddress(Address); 443e64eede0SAmir Ayupov const bool IsHotFunction = HotAddress == 0; 444ad00e7e5SAmir Ayupov OS << "Function Address: 0x" << Twine::utohexstr(Address); 445e64eede0SAmir Ayupov if (IsHotFunction) 446ad00e7e5SAmir Ayupov OS << formatv(", hash: {0:x}", getBFHash(Address)); 447ad00e7e5SAmir Ayupov OS << "\n"; 448fc0ced73SRafael Auler OS << "BB mappings:\n"; 449a91cd53dSAmir Ayupov const BBHashMapTy &BBHashMap = 450a91cd53dSAmir Ayupov getBBHashMap(HotAddress ? HotAddress : Address); 451fc0ced73SRafael Auler for (const auto &Entry : MapEntry.second) { 452fc0ced73SRafael Auler const bool IsBranch = Entry.second & BRANCHENTRY; 453565f40d6SAmir Ayupov const uint32_t Val = Entry.second >> 1; // dropping BRANCHENTRY bit 454fc0ced73SRafael Auler OS << "0x" << Twine::utohexstr(Entry.first) << " -> " 455fc0ced73SRafael Auler << "0x" << Twine::utohexstr(Val); 456fc0ced73SRafael Auler if (IsBranch) 457fc0ced73SRafael Auler OS << " (branch)"; 458ad00e7e5SAmir Ayupov else 459a91cd53dSAmir Ayupov OS << formatv(" hash: {0:x}", BBHashMap.getBBHash(Val)); 460fc0ced73SRafael Auler OS << "\n"; 461fc0ced73SRafael Auler } 46250574638SAmir Ayupov if (IsHotFunction) { 46350574638SAmir Ayupov auto NumBasicBlocksIt = NumBasicBlocksMap.find(Address); 46450574638SAmir Ayupov assert(NumBasicBlocksIt != NumBasicBlocksMap.end()); 46550574638SAmir Ayupov OS << "NumBlocks: " << NumBasicBlocksIt->second << '\n'; 46650574638SAmir Ayupov } 46750574638SAmir Ayupov auto SecondaryEntryPointsIt = SecondaryEntryPointsMap.find(Address); 46850574638SAmir Ayupov if (SecondaryEntryPointsIt != SecondaryEntryPointsMap.end()) { 4691b763f23SAmir Ayupov const std::vector<uint32_t> &SecondaryEntryPoints = 47050574638SAmir Ayupov SecondaryEntryPointsIt->second; 4711b763f23SAmir Ayupov OS << SecondaryEntryPoints.size() << " secondary entry points:\n"; 4721b763f23SAmir Ayupov for (uint32_t EntryPointOffset : SecondaryEntryPoints) 4731b763f23SAmir Ayupov OS << formatv("{0:x}\n", EntryPointOffset); 4741b763f23SAmir Ayupov } 475fc0ced73SRafael Auler OS << "\n"; 476fc0ced73SRafael Auler } 477fc0ced73SRafael Auler const size_t NumColdParts = ColdPartSource.size(); 478fc0ced73SRafael Auler if (!NumColdParts) 479fc0ced73SRafael Auler return; 480fc0ced73SRafael Auler 481fc0ced73SRafael Auler OS << NumColdParts << " cold mappings:\n"; 482fc0ced73SRafael Auler for (const auto &Entry : ColdPartSource) { 483fc0ced73SRafael Auler OS << "0x" << Twine::utohexstr(Entry.first) << " -> " 484fc0ced73SRafael Auler << Twine::utohexstr(Entry.second) << "\n"; 485fc0ced73SRafael Auler } 486fc0ced73SRafael Auler OS << "\n"; 487fc0ced73SRafael Auler } 488fc0ced73SRafael Auler 489fc0ced73SRafael Auler uint64_t BoltAddressTranslation::translate(uint64_t FuncAddress, 490a34c753fSRafael Auler uint64_t Offset, 491a34c753fSRafael Auler bool IsBranchSrc) const { 492fc0ced73SRafael Auler auto Iter = Maps.find(FuncAddress); 493a34c753fSRafael Auler if (Iter == Maps.end()) 494a34c753fSRafael Auler return Offset; 495a34c753fSRafael Auler 496a34c753fSRafael Auler const MapTy &Map = Iter->second; 497a34c753fSRafael Auler auto KeyVal = Map.upper_bound(Offset); 498a34c753fSRafael Auler if (KeyVal == Map.begin()) 499a34c753fSRafael Auler return Offset; 500a34c753fSRafael Auler 501a34c753fSRafael Auler --KeyVal; 502a34c753fSRafael Auler 503565f40d6SAmir Ayupov const uint32_t Val = KeyVal->second >> 1; // dropping BRANCHENTRY bit 504a34c753fSRafael Auler // Branch source addresses are translated to the first instruction of the 505a34c753fSRafael Auler // source BB to avoid accounting for modifications BOLT may have made in the 506a34c753fSRafael Auler // BB regarding deletion/addition of instructions. 507a34c753fSRafael Auler if (IsBranchSrc) 508a34c753fSRafael Auler return Val; 509a34c753fSRafael Auler return Offset - KeyVal->first + Val; 510a34c753fSRafael Auler } 511a34c753fSRafael Auler 5123d573fdbSAmir Ayupov std::optional<BoltAddressTranslation::FallthroughListTy> 513fc0ced73SRafael Auler BoltAddressTranslation::getFallthroughsInTrace(uint64_t FuncAddress, 51440c2e0faSMaksim Panchenko uint64_t From, 51540c2e0faSMaksim Panchenko uint64_t To) const { 516a34c753fSRafael Auler SmallVector<std::pair<uint64_t, uint64_t>, 16> Res; 517a34c753fSRafael Auler 518a34c753fSRafael Auler // Filter out trivial case 519a34c753fSRafael Auler if (From >= To) 520a34c753fSRafael Auler return Res; 521a34c753fSRafael Auler 522fc0ced73SRafael Auler From -= FuncAddress; 523fc0ced73SRafael Auler To -= FuncAddress; 524a34c753fSRafael Auler 525fc0ced73SRafael Auler auto Iter = Maps.find(FuncAddress); 526def464aaSAmir Ayupov if (Iter == Maps.end()) 527e324a80fSKazu Hirata return std::nullopt; 528a34c753fSRafael Auler 529a34c753fSRafael Auler const MapTy &Map = Iter->second; 530a34c753fSRafael Auler auto FromIter = Map.upper_bound(From); 531a34c753fSRafael Auler if (FromIter == Map.begin()) 532a34c753fSRafael Auler return Res; 533a34c753fSRafael Auler // Skip instruction entries, to create fallthroughs we are only interested in 534a34c753fSRafael Auler // BB boundaries 535a34c753fSRafael Auler do { 536a34c753fSRafael Auler if (FromIter == Map.begin()) 537a34c753fSRafael Auler return Res; 538a34c753fSRafael Auler --FromIter; 539a34c753fSRafael Auler } while (FromIter->second & BRANCHENTRY); 540a34c753fSRafael Auler 541a34c753fSRafael Auler auto ToIter = Map.upper_bound(To); 542a34c753fSRafael Auler if (ToIter == Map.begin()) 543a34c753fSRafael Auler return Res; 544a34c753fSRafael Auler --ToIter; 545a34c753fSRafael Auler if (FromIter->first >= ToIter->first) 546a34c753fSRafael Auler return Res; 547a34c753fSRafael Auler 548a34c753fSRafael Auler for (auto Iter = FromIter; Iter != ToIter;) { 549a34c753fSRafael Auler const uint32_t Src = Iter->first; 550a34c753fSRafael Auler if (Iter->second & BRANCHENTRY) { 551a34c753fSRafael Auler ++Iter; 552a34c753fSRafael Auler continue; 553a34c753fSRafael Auler } 554a34c753fSRafael Auler 555a34c753fSRafael Auler ++Iter; 556def464aaSAmir Ayupov while (Iter->second & BRANCHENTRY && Iter != ToIter) 557a34c753fSRafael Auler ++Iter; 558a34c753fSRafael Auler if (Iter->second & BRANCHENTRY) 559a34c753fSRafael Auler break; 560a34c753fSRafael Auler Res.emplace_back(Src, Iter->first); 561a34c753fSRafael Auler } 562a34c753fSRafael Auler 563a34c753fSRafael Auler return Res; 564a34c753fSRafael Auler } 565a34c753fSRafael Auler 566a34c753fSRafael Auler bool BoltAddressTranslation::enabledFor( 567a34c753fSRafael Auler llvm::object::ELFObjectFileBase *InputFile) const { 568a34c753fSRafael Auler for (const SectionRef &Section : InputFile->sections()) { 569a34c753fSRafael Auler Expected<StringRef> SectionNameOrErr = Section.getName(); 570a34c753fSRafael Auler if (Error E = SectionNameOrErr.takeError()) 571a34c753fSRafael Auler continue; 572a34c753fSRafael Auler 573a34c753fSRafael Auler if (SectionNameOrErr.get() == SECTION_NAME) 574a34c753fSRafael Auler return true; 575a34c753fSRafael Auler } 576a34c753fSRafael Auler return false; 577a34c753fSRafael Auler } 578d2c9a19dSAmir Ayupov 579d2c9a19dSAmir Ayupov void BoltAddressTranslation::saveMetadata(BinaryContext &BC) { 580d2c9a19dSAmir Ayupov for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { 581d2c9a19dSAmir Ayupov // We don't need a translation table if the body of the function hasn't 582d2c9a19dSAmir Ayupov // changed 583d2c9a19dSAmir Ayupov if (BF.isIgnored() || (!BC.HasRelocations && !BF.isSimple())) 584d2c9a19dSAmir Ayupov continue; 585d2c9a19dSAmir Ayupov // Prepare function and block hashes 586a91cd53dSAmir Ayupov FuncHashes.addEntry(BF.getAddress(), BF.computeHash()); 587d2c9a19dSAmir Ayupov BF.computeBlockHashes(); 588a91cd53dSAmir Ayupov BBHashMapTy &BBHashMap = getBBHashMap(BF.getAddress()); 589a91cd53dSAmir Ayupov // Set BF/BB metadata 590d2c9a19dSAmir Ayupov for (const BinaryBasicBlock &BB : BF) 591a91cd53dSAmir Ayupov BBHashMap.addEntry(BB.getInputOffset(), BB.getIndex(), BB.getHash()); 592e64eede0SAmir Ayupov NumBasicBlocksMap.emplace(BF.getAddress(), BF.size()); 593d2c9a19dSAmir Ayupov } 594d2c9a19dSAmir Ayupov } 595ad00e7e5SAmir Ayupov 5962d3c827cSAmir Ayupov unsigned 5972d3c827cSAmir Ayupov BoltAddressTranslation::getSecondaryEntryPointId(uint64_t Address, 5982d3c827cSAmir Ayupov uint32_t Offset) const { 5992d3c827cSAmir Ayupov auto FunctionIt = SecondaryEntryPointsMap.find(Address); 6002d3c827cSAmir Ayupov if (FunctionIt == SecondaryEntryPointsMap.end()) 6012d3c827cSAmir Ayupov return 0; 6022d3c827cSAmir Ayupov const std::vector<uint32_t> &Offsets = FunctionIt->second; 6032d3c827cSAmir Ayupov auto OffsetIt = std::find(Offsets.begin(), Offsets.end(), Offset); 6042d3c827cSAmir Ayupov if (OffsetIt == Offsets.end()) 6052d3c827cSAmir Ayupov return 0; 6062d3c827cSAmir Ayupov // Adding one here because main entry point is not stored in BAT, and 6072d3c827cSAmir Ayupov // enumeration for secondary entry points starts with 1. 6082d3c827cSAmir Ayupov return OffsetIt - Offsets.begin() + 1; 6092d3c827cSAmir Ayupov } 6102d3c827cSAmir Ayupov 6112d3c827cSAmir Ayupov std::pair<const BinaryFunction *, unsigned> 6122d3c827cSAmir Ayupov BoltAddressTranslation::translateSymbol(const BinaryContext &BC, 6132d3c827cSAmir Ayupov const MCSymbol &Symbol, 6142d3c827cSAmir Ayupov uint32_t Offset) const { 6152d3c827cSAmir Ayupov // The symbol could be a secondary entry in a cold fragment. 6162d3c827cSAmir Ayupov uint64_t SymbolValue = cantFail(errorOrToExpected(BC.getSymbolValue(Symbol))); 6172d3c827cSAmir Ayupov 6182d3c827cSAmir Ayupov const BinaryFunction *Callee = BC.getFunctionForSymbol(&Symbol); 6192d3c827cSAmir Ayupov assert(Callee); 6202d3c827cSAmir Ayupov 6212d3c827cSAmir Ayupov // Containing function, not necessarily the same as symbol value. 6222d3c827cSAmir Ayupov const uint64_t CalleeAddress = Callee->getAddress(); 6232d3c827cSAmir Ayupov const uint32_t OutputOffset = SymbolValue - CalleeAddress; 6242d3c827cSAmir Ayupov 6252d3c827cSAmir Ayupov const uint64_t ParentAddress = fetchParentAddress(CalleeAddress); 6262d3c827cSAmir Ayupov const uint64_t HotAddress = ParentAddress ? ParentAddress : CalleeAddress; 6272d3c827cSAmir Ayupov 6282d3c827cSAmir Ayupov const BinaryFunction *ParentBF = BC.getBinaryFunctionAtAddress(HotAddress); 6292d3c827cSAmir Ayupov 6302d3c827cSAmir Ayupov const uint32_t InputOffset = 6312d3c827cSAmir Ayupov translate(CalleeAddress, OutputOffset, /*IsBranchSrc*/ false) + Offset; 6322d3c827cSAmir Ayupov 6332d3c827cSAmir Ayupov unsigned SecondaryEntryId{0}; 6342d3c827cSAmir Ayupov if (InputOffset) 6352d3c827cSAmir Ayupov SecondaryEntryId = getSecondaryEntryPointId(HotAddress, InputOffset); 6362d3c827cSAmir Ayupov 6372d3c827cSAmir Ayupov return std::pair(ParentBF, SecondaryEntryId); 6382d3c827cSAmir Ayupov } 6392d3c827cSAmir Ayupov 64040c2e0faSMaksim Panchenko } // namespace bolt 64140c2e0faSMaksim Panchenko } // namespace llvm 642