165d7fd02SEllis Hoag //===-- InstrProfCorrelator.cpp -------------------------------------------===// 265d7fd02SEllis Hoag // 365d7fd02SEllis Hoag // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 465d7fd02SEllis Hoag // See https://llvm.org/LICENSE.txt for license information. 565d7fd02SEllis Hoag // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 665d7fd02SEllis Hoag // 765d7fd02SEllis Hoag //===----------------------------------------------------------------------===// 865d7fd02SEllis Hoag 965d7fd02SEllis Hoag #include "llvm/ProfileData/InstrProfCorrelator.h" 10fc97efa4Sserge-sans-paille #include "llvm/DebugInfo/DIContext.h" 11fc97efa4Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFContext.h" 12fc97efa4Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFDie.h" 13290e4823Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 14fc97efa4Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" 15fc97efa4Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" 16fc97efa4Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFUnit.h" 1765d7fd02SEllis Hoag #include "llvm/Object/MachO.h" 1865d7fd02SEllis Hoag #include "llvm/Support/Debug.h" 19d687caaeSEllis Hoag #include "llvm/Support/Format.h" 20d687caaeSEllis Hoag #include "llvm/Support/WithColor.h" 21c589730aSKrzysztof Parzyszek #include <optional> 2265d7fd02SEllis Hoag 2365d7fd02SEllis Hoag #define DEBUG_TYPE "correlator" 2465d7fd02SEllis Hoag 2565d7fd02SEllis Hoag using namespace llvm; 2665d7fd02SEllis Hoag 273c97c8b6SZequan Wu /// Get profile section. 283c97c8b6SZequan Wu Expected<object::SectionRef> getInstrProfSection(const object::ObjectFile &Obj, 293c97c8b6SZequan Wu InstrProfSectKind IPSK) { 30ab3430f8SZequan Wu // On COFF, the getInstrProfSectionName returns the section names may followed 31ab3430f8SZequan Wu // by "$M". The linker removes the dollar and everything after it in the final 32ab3430f8SZequan Wu // binary. Do the same to match. 333c97c8b6SZequan Wu Triple::ObjectFormatType ObjFormat = Obj.getTripleObjectFormat(); 34ab3430f8SZequan Wu auto StripSuffix = [ObjFormat](StringRef N) { 35ab3430f8SZequan Wu return ObjFormat == Triple::COFF ? N.split('$').first : N; 36ab3430f8SZequan Wu }; 373c97c8b6SZequan Wu std::string ExpectedSectionName = 383c97c8b6SZequan Wu getInstrProfSectionName(IPSK, ObjFormat, 393c97c8b6SZequan Wu /*AddSegmentInfo=*/false); 40ab3430f8SZequan Wu ExpectedSectionName = StripSuffix(ExpectedSectionName); 41ab3430f8SZequan Wu for (auto &Section : Obj.sections()) { 4265d7fd02SEllis Hoag if (auto SectionName = Section.getName()) 43ab3430f8SZequan Wu if (*SectionName == ExpectedSectionName) 4465d7fd02SEllis Hoag return Section; 45ab3430f8SZequan Wu } 4665d7fd02SEllis Hoag return make_error<InstrProfError>( 476d523911SEllis Hoag instrprof_error::unable_to_correlate_profile, 483c97c8b6SZequan Wu "could not find section (" + Twine(ExpectedSectionName) + ")"); 4965d7fd02SEllis Hoag } 5065d7fd02SEllis Hoag 5165d7fd02SEllis Hoag const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name"; 5265d7fd02SEllis Hoag const char *InstrProfCorrelator::CFGHashAttributeName = "CFG Hash"; 5365d7fd02SEllis Hoag const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters"; 5465d7fd02SEllis Hoag 5565d7fd02SEllis Hoag llvm::Expected<std::unique_ptr<InstrProfCorrelator::Context>> 5665d7fd02SEllis Hoag InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer, 57ab3430f8SZequan Wu const object::ObjectFile &Obj, 58ab3430f8SZequan Wu ProfCorrelatorKind FileKind) { 59ab3430f8SZequan Wu auto C = std::make_unique<Context>(); 603c97c8b6SZequan Wu auto CountersSection = getInstrProfSection(Obj, IPSK_cnts); 6165d7fd02SEllis Hoag if (auto Err = CountersSection.takeError()) 6265d7fd02SEllis Hoag return std::move(Err); 63ab3430f8SZequan Wu if (FileKind == InstrProfCorrelator::BINARY) { 64ab3430f8SZequan Wu auto DataSection = getInstrProfSection(Obj, IPSK_covdata); 65ab3430f8SZequan Wu if (auto Err = DataSection.takeError()) 66ab3430f8SZequan Wu return std::move(Err); 67ab3430f8SZequan Wu auto DataOrErr = DataSection->getContents(); 68ab3430f8SZequan Wu if (!DataOrErr) 69ab3430f8SZequan Wu return DataOrErr.takeError(); 70ab3430f8SZequan Wu auto NameSection = getInstrProfSection(Obj, IPSK_covname); 71ab3430f8SZequan Wu if (auto Err = NameSection.takeError()) 72ab3430f8SZequan Wu return std::move(Err); 73ab3430f8SZequan Wu auto NameOrErr = NameSection->getContents(); 74ab3430f8SZequan Wu if (!NameOrErr) 75ab3430f8SZequan Wu return NameOrErr.takeError(); 76ab3430f8SZequan Wu C->DataStart = DataOrErr->data(); 77ab3430f8SZequan Wu C->DataEnd = DataOrErr->data() + DataOrErr->size(); 78ab3430f8SZequan Wu C->NameStart = NameOrErr->data(); 79ab3430f8SZequan Wu C->NameSize = NameOrErr->size(); 80ab3430f8SZequan Wu } 8165d7fd02SEllis Hoag C->Buffer = std::move(Buffer); 8265d7fd02SEllis Hoag C->CountersSectionStart = CountersSection->getAddress(); 8365d7fd02SEllis Hoag C->CountersSectionEnd = C->CountersSectionStart + CountersSection->getSize(); 84ab3430f8SZequan Wu // In COFF object file, there's a null byte at the beginning of the counter 85ab3430f8SZequan Wu // section which doesn't exist in raw profile. 86ab3430f8SZequan Wu if (Obj.getTripleObjectFormat() == Triple::COFF) 87ab3430f8SZequan Wu ++C->CountersSectionStart; 88ab3430f8SZequan Wu 8965d7fd02SEllis Hoag C->ShouldSwapBytes = Obj.isLittleEndian() != sys::IsLittleEndianHost; 9065d7fd02SEllis Hoag return Expected<std::unique_ptr<Context>>(std::move(C)); 9165d7fd02SEllis Hoag } 9265d7fd02SEllis Hoag 9365d7fd02SEllis Hoag llvm::Expected<std::unique_ptr<InstrProfCorrelator>> 94*787cd8f0Sgulfemsavrun InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind, 95*787cd8f0Sgulfemsavrun const object::BuildIDFetcher *BIDFetcher, 96*787cd8f0Sgulfemsavrun const ArrayRef<object::BuildID> BIs) { 97*787cd8f0Sgulfemsavrun std::optional<std::string> Path; 98*787cd8f0Sgulfemsavrun if (BIDFetcher) { 99*787cd8f0Sgulfemsavrun if (BIs.empty()) 100*787cd8f0Sgulfemsavrun return make_error<InstrProfError>( 101*787cd8f0Sgulfemsavrun instrprof_error::unable_to_correlate_profile, 102*787cd8f0Sgulfemsavrun "unsupported profile binary correlation when there is no build ID " 103*787cd8f0Sgulfemsavrun "in a profile"); 104*787cd8f0Sgulfemsavrun if (BIs.size() > 1) 105*787cd8f0Sgulfemsavrun return make_error<InstrProfError>( 106*787cd8f0Sgulfemsavrun instrprof_error::unable_to_correlate_profile, 107*787cd8f0Sgulfemsavrun "unsupported profile binary correlation when there are multiple " 108*787cd8f0Sgulfemsavrun "build IDs in a profile"); 109*787cd8f0Sgulfemsavrun 110*787cd8f0Sgulfemsavrun Path = BIDFetcher->fetch(BIs.front()); 111*787cd8f0Sgulfemsavrun if (!Path) 112*787cd8f0Sgulfemsavrun return make_error<InstrProfError>( 113*787cd8f0Sgulfemsavrun instrprof_error::unable_to_correlate_profile, 114*787cd8f0Sgulfemsavrun "Missing build ID: " + llvm::toHex(BIs.front(), 115*787cd8f0Sgulfemsavrun /*LowerCase=*/true)); 116*787cd8f0Sgulfemsavrun Filename = *Path; 117*787cd8f0Sgulfemsavrun } 118*787cd8f0Sgulfemsavrun 1193c97c8b6SZequan Wu if (FileKind == DEBUG_INFO) { 12065d7fd02SEllis Hoag auto DsymObjectsOrErr = 1213c97c8b6SZequan Wu object::MachOObjectFile::findDsymObjectMembers(Filename); 12265d7fd02SEllis Hoag if (auto Err = DsymObjectsOrErr.takeError()) 12365d7fd02SEllis Hoag return std::move(Err); 12465d7fd02SEllis Hoag if (!DsymObjectsOrErr->empty()) { 12565d7fd02SEllis Hoag // TODO: Enable profile correlation when there are multiple objects in a 12665d7fd02SEllis Hoag // dSYM bundle. 12765d7fd02SEllis Hoag if (DsymObjectsOrErr->size() > 1) 1286d523911SEllis Hoag return make_error<InstrProfError>( 1296d523911SEllis Hoag instrprof_error::unable_to_correlate_profile, 1306d523911SEllis Hoag "using multiple objects is not yet supported"); 1313c97c8b6SZequan Wu Filename = *DsymObjectsOrErr->begin(); 13265d7fd02SEllis Hoag } 1333c97c8b6SZequan Wu auto BufferOrErr = errorOrToExpected(MemoryBuffer::getFile(Filename)); 13465d7fd02SEllis Hoag if (auto Err = BufferOrErr.takeError()) 13565d7fd02SEllis Hoag return std::move(Err); 13665d7fd02SEllis Hoag 1373c97c8b6SZequan Wu return get(std::move(*BufferOrErr), FileKind); 13865d7fd02SEllis Hoag } 139ab3430f8SZequan Wu if (FileKind == BINARY) { 140ab3430f8SZequan Wu auto BufferOrErr = errorOrToExpected(MemoryBuffer::getFile(Filename)); 141ab3430f8SZequan Wu if (auto Err = BufferOrErr.takeError()) 142ab3430f8SZequan Wu return std::move(Err); 143ab3430f8SZequan Wu 144ab3430f8SZequan Wu return get(std::move(*BufferOrErr), FileKind); 145ab3430f8SZequan Wu } 14656e205a8SZequan Wu return make_error<InstrProfError>( 14756e205a8SZequan Wu instrprof_error::unable_to_correlate_profile, 148ab3430f8SZequan Wu "unsupported correlation kind (only DWARF debug info and Binary format " 149ab3430f8SZequan Wu "(ELF/COFF) are supported)"); 15056e205a8SZequan Wu } 15165d7fd02SEllis Hoag 15265d7fd02SEllis Hoag llvm::Expected<std::unique_ptr<InstrProfCorrelator>> 1533c97c8b6SZequan Wu InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer, 1543c97c8b6SZequan Wu ProfCorrelatorKind FileKind) { 15565d7fd02SEllis Hoag auto BinOrErr = object::createBinary(*Buffer); 15665d7fd02SEllis Hoag if (auto Err = BinOrErr.takeError()) 15765d7fd02SEllis Hoag return std::move(Err); 15865d7fd02SEllis Hoag 15965d7fd02SEllis Hoag if (auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) { 160ab3430f8SZequan Wu auto CtxOrErr = Context::get(std::move(Buffer), *Obj, FileKind); 16165d7fd02SEllis Hoag if (auto Err = CtxOrErr.takeError()) 16265d7fd02SEllis Hoag return std::move(Err); 16365d7fd02SEllis Hoag auto T = Obj->makeTriple(); 16465d7fd02SEllis Hoag if (T.isArch64Bit()) 1653c97c8b6SZequan Wu return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj, 1663c97c8b6SZequan Wu FileKind); 16765d7fd02SEllis Hoag if (T.isArch32Bit()) 1683c97c8b6SZequan Wu return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj, 1693c97c8b6SZequan Wu FileKind); 17065d7fd02SEllis Hoag } 17165d7fd02SEllis Hoag return make_error<InstrProfError>( 1726d523911SEllis Hoag instrprof_error::unable_to_correlate_profile, "not an object file"); 17365d7fd02SEllis Hoag } 17465d7fd02SEllis Hoag 1754e0e0bbdSFangrui Song std::optional<size_t> InstrProfCorrelator::getDataSize() const { 176c9baa560SEllis Hoag if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint32_t>>(this)) { 177c9baa560SEllis Hoag return C->getDataSize(); 178c9baa560SEllis Hoag } else if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint64_t>>(this)) { 179c9baa560SEllis Hoag return C->getDataSize(); 180c9baa560SEllis Hoag } 181c9baa560SEllis Hoag return {}; 182c9baa560SEllis Hoag } 183c9baa560SEllis Hoag 18465d7fd02SEllis Hoag namespace llvm { 18565d7fd02SEllis Hoag 18665d7fd02SEllis Hoag template <> 18765d7fd02SEllis Hoag InstrProfCorrelatorImpl<uint32_t>::InstrProfCorrelatorImpl( 18865d7fd02SEllis Hoag std::unique_ptr<InstrProfCorrelator::Context> Ctx) 18965d7fd02SEllis Hoag : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_32Bit, 19065d7fd02SEllis Hoag std::move(Ctx)) {} 19165d7fd02SEllis Hoag template <> 19265d7fd02SEllis Hoag InstrProfCorrelatorImpl<uint64_t>::InstrProfCorrelatorImpl( 19365d7fd02SEllis Hoag std::unique_ptr<InstrProfCorrelator::Context> Ctx) 19465d7fd02SEllis Hoag : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_64Bit, 19565d7fd02SEllis Hoag std::move(Ctx)) {} 19665d7fd02SEllis Hoag template <> 19765d7fd02SEllis Hoag bool InstrProfCorrelatorImpl<uint32_t>::classof(const InstrProfCorrelator *C) { 19865d7fd02SEllis Hoag return C->getKind() == InstrProfCorrelatorKind::CK_32Bit; 19965d7fd02SEllis Hoag } 20065d7fd02SEllis Hoag template <> 20165d7fd02SEllis Hoag bool InstrProfCorrelatorImpl<uint64_t>::classof(const InstrProfCorrelator *C) { 20265d7fd02SEllis Hoag return C->getKind() == InstrProfCorrelatorKind::CK_64Bit; 20365d7fd02SEllis Hoag } 20465d7fd02SEllis Hoag 20565d7fd02SEllis Hoag } // end namespace llvm 20665d7fd02SEllis Hoag 20765d7fd02SEllis Hoag template <class IntPtrT> 20865d7fd02SEllis Hoag llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>> 20965d7fd02SEllis Hoag InstrProfCorrelatorImpl<IntPtrT>::get( 21065d7fd02SEllis Hoag std::unique_ptr<InstrProfCorrelator::Context> Ctx, 2113c97c8b6SZequan Wu const object::ObjectFile &Obj, ProfCorrelatorKind FileKind) { 2123c97c8b6SZequan Wu if (FileKind == DEBUG_INFO) { 21365d7fd02SEllis Hoag if (Obj.isELF() || Obj.isMachO()) { 21465d7fd02SEllis Hoag auto DICtx = DWARFContext::create(Obj); 2153c97c8b6SZequan Wu return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>( 2163c97c8b6SZequan Wu std::move(DICtx), std::move(Ctx)); 21765d7fd02SEllis Hoag } 2186d523911SEllis Hoag return make_error<InstrProfError>( 2196d523911SEllis Hoag instrprof_error::unable_to_correlate_profile, 2206d523911SEllis Hoag "unsupported debug info format (only DWARF is supported)"); 22165d7fd02SEllis Hoag } 222ab3430f8SZequan Wu if (Obj.isELF() || Obj.isCOFF()) 223ab3430f8SZequan Wu return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx)); 2243c97c8b6SZequan Wu return make_error<InstrProfError>( 2253c97c8b6SZequan Wu instrprof_error::unable_to_correlate_profile, 226ab3430f8SZequan Wu "unsupported binary format (only ELF and COFF are supported)"); 2273c97c8b6SZequan Wu } 22865d7fd02SEllis Hoag 22965d7fd02SEllis Hoag template <class IntPtrT> 230d687caaeSEllis Hoag Error InstrProfCorrelatorImpl<IntPtrT>::correlateProfileData(int MaxWarnings) { 231f1705952SEllis Hoag assert(Data.empty() && Names.empty() && NamesVec.empty()); 232d687caaeSEllis Hoag correlateProfileDataImpl(MaxWarnings); 2333c97c8b6SZequan Wu if (this->Data.empty()) 2346d523911SEllis Hoag return make_error<InstrProfError>( 2356d523911SEllis Hoag instrprof_error::unable_to_correlate_profile, 2363c97c8b6SZequan Wu "could not find any profile data metadata in correlated file"); 2373c97c8b6SZequan Wu Error Result = correlateProfileNameImpl(); 2383c97c8b6SZequan Wu this->CounterOffsets.clear(); 2393c97c8b6SZequan Wu this->NamesVec.clear(); 24065d7fd02SEllis Hoag return Result; 24165d7fd02SEllis Hoag } 24265d7fd02SEllis Hoag 24370fb7bb5SEllis Hoag template <> struct yaml::MappingTraits<InstrProfCorrelator::CorrelationData> { 24470fb7bb5SEllis Hoag static void mapping(yaml::IO &io, 24570fb7bb5SEllis Hoag InstrProfCorrelator::CorrelationData &Data) { 24670fb7bb5SEllis Hoag io.mapRequired("Probes", Data.Probes); 24770fb7bb5SEllis Hoag } 24870fb7bb5SEllis Hoag }; 24970fb7bb5SEllis Hoag 25070fb7bb5SEllis Hoag template <> struct yaml::MappingTraits<InstrProfCorrelator::Probe> { 25170fb7bb5SEllis Hoag static void mapping(yaml::IO &io, InstrProfCorrelator::Probe &P) { 25270fb7bb5SEllis Hoag io.mapRequired("Function Name", P.FunctionName); 25370fb7bb5SEllis Hoag io.mapOptional("Linkage Name", P.LinkageName); 25470fb7bb5SEllis Hoag io.mapRequired("CFG Hash", P.CFGHash); 25570fb7bb5SEllis Hoag io.mapRequired("Counter Offset", P.CounterOffset); 25670fb7bb5SEllis Hoag io.mapRequired("Num Counters", P.NumCounters); 25770fb7bb5SEllis Hoag io.mapOptional("File", P.FilePath); 25870fb7bb5SEllis Hoag io.mapOptional("Line", P.LineNumber); 25970fb7bb5SEllis Hoag } 26070fb7bb5SEllis Hoag }; 26170fb7bb5SEllis Hoag 26270fb7bb5SEllis Hoag template <> struct yaml::SequenceElementTraits<InstrProfCorrelator::Probe> { 26370fb7bb5SEllis Hoag static const bool flow = false; 26470fb7bb5SEllis Hoag }; 26570fb7bb5SEllis Hoag 26670fb7bb5SEllis Hoag template <class IntPtrT> 267d687caaeSEllis Hoag Error InstrProfCorrelatorImpl<IntPtrT>::dumpYaml(int MaxWarnings, 268d687caaeSEllis Hoag raw_ostream &OS) { 26970fb7bb5SEllis Hoag InstrProfCorrelator::CorrelationData Data; 270d687caaeSEllis Hoag correlateProfileDataImpl(MaxWarnings, &Data); 27170fb7bb5SEllis Hoag if (Data.Probes.empty()) 27270fb7bb5SEllis Hoag return make_error<InstrProfError>( 27370fb7bb5SEllis Hoag instrprof_error::unable_to_correlate_profile, 2743c97c8b6SZequan Wu "could not find any profile data metadata in debug info"); 27570fb7bb5SEllis Hoag yaml::Output YamlOS(OS); 27670fb7bb5SEllis Hoag YamlOS << Data; 27770fb7bb5SEllis Hoag return Error::success(); 27870fb7bb5SEllis Hoag } 27970fb7bb5SEllis Hoag 28065d7fd02SEllis Hoag template <class IntPtrT> 281ab3430f8SZequan Wu void InstrProfCorrelatorImpl<IntPtrT>::addDataProbe(uint64_t NameRef, 28265d7fd02SEllis Hoag uint64_t CFGHash, 28365d7fd02SEllis Hoag IntPtrT CounterOffset, 28465d7fd02SEllis Hoag IntPtrT FunctionPtr, 28565d7fd02SEllis Hoag uint32_t NumCounters) { 28618ffb5dcSEllis Hoag // Check if a probe was already added for this counter offset. 28718ffb5dcSEllis Hoag if (!CounterOffsets.insert(CounterOffset).second) 28818ffb5dcSEllis Hoag return; 28965d7fd02SEllis Hoag Data.push_back({ 290ab3430f8SZequan Wu maybeSwap<uint64_t>(NameRef), 29165d7fd02SEllis Hoag maybeSwap<uint64_t>(CFGHash), 29265d7fd02SEllis Hoag // In this mode, CounterPtr actually stores the section relative address 29365d7fd02SEllis Hoag // of the counter. 29465d7fd02SEllis Hoag maybeSwap<IntPtrT>(CounterOffset), 295f95b2f1aSAlan Phipps // TODO: MC/DC is not yet supported. 296f95b2f1aSAlan Phipps /*BitmapOffset=*/maybeSwap<IntPtrT>(0), 29765d7fd02SEllis Hoag maybeSwap<IntPtrT>(FunctionPtr), 29865d7fd02SEllis Hoag // TODO: Value profiling is not yet supported. 29965d7fd02SEllis Hoag /*ValuesPtr=*/maybeSwap<IntPtrT>(0), 30065d7fd02SEllis Hoag maybeSwap<uint32_t>(NumCounters), 30165d7fd02SEllis Hoag /*NumValueSites=*/{maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)}, 302f95b2f1aSAlan Phipps // TODO: MC/DC is not yet supported. 303f95b2f1aSAlan Phipps /*NumBitmapBytes=*/maybeSwap<uint32_t>(0), 30465d7fd02SEllis Hoag }); 30565d7fd02SEllis Hoag } 30665d7fd02SEllis Hoag 30765d7fd02SEllis Hoag template <class IntPtrT> 3084e0e0bbdSFangrui Song std::optional<uint64_t> 30965d7fd02SEllis Hoag DwarfInstrProfCorrelator<IntPtrT>::getLocation(const DWARFDie &Die) const { 31065d7fd02SEllis Hoag auto Locations = Die.getLocations(dwarf::DW_AT_location); 31165d7fd02SEllis Hoag if (!Locations) { 31265d7fd02SEllis Hoag consumeError(Locations.takeError()); 31365d7fd02SEllis Hoag return {}; 31465d7fd02SEllis Hoag } 31565d7fd02SEllis Hoag auto &DU = *Die.getDwarfUnit(); 31665d7fd02SEllis Hoag auto AddressSize = DU.getAddressByteSize(); 3179c2891a8SEllis Hoag for (auto &Location : *Locations) { 31865d7fd02SEllis Hoag DataExtractor Data(Location.Expr, DICtx->isLittleEndian(), AddressSize); 31965d7fd02SEllis Hoag DWARFExpression Expr(Data, AddressSize); 3209c2891a8SEllis Hoag for (auto &Op : Expr) { 3219c2891a8SEllis Hoag if (Op.getCode() == dwarf::DW_OP_addr) { 32265d7fd02SEllis Hoag return Op.getRawOperand(0); 3239c2891a8SEllis Hoag } else if (Op.getCode() == dwarf::DW_OP_addrx) { 3249c2891a8SEllis Hoag uint64_t Index = Op.getRawOperand(0); 3259c2891a8SEllis Hoag if (auto SA = DU.getAddrOffsetSectionItem(Index)) 3269c2891a8SEllis Hoag return SA->Address; 3279c2891a8SEllis Hoag } 3289c2891a8SEllis Hoag } 32965d7fd02SEllis Hoag } 33065d7fd02SEllis Hoag return {}; 33165d7fd02SEllis Hoag } 33265d7fd02SEllis Hoag 33365d7fd02SEllis Hoag template <class IntPtrT> 33465d7fd02SEllis Hoag bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(const DWARFDie &Die) { 33565d7fd02SEllis Hoag const auto &ParentDie = Die.getParent(); 33665d7fd02SEllis Hoag if (!Die.isValid() || !ParentDie.isValid() || Die.isNULL()) 33765d7fd02SEllis Hoag return false; 33865d7fd02SEllis Hoag if (Die.getTag() != dwarf::DW_TAG_variable) 33965d7fd02SEllis Hoag return false; 34065d7fd02SEllis Hoag if (!ParentDie.isSubprogramDIE()) 34165d7fd02SEllis Hoag return false; 34265d7fd02SEllis Hoag if (!Die.hasChildren()) 34365d7fd02SEllis Hoag return false; 34465d7fd02SEllis Hoag if (const char *Name = Die.getName(DINameKind::ShortName)) 345586ecdf2SKazu Hirata return StringRef(Name).starts_with(getInstrProfCountersVarPrefix()); 34665d7fd02SEllis Hoag return false; 34765d7fd02SEllis Hoag } 34865d7fd02SEllis Hoag 34965d7fd02SEllis Hoag template <class IntPtrT> 35070fb7bb5SEllis Hoag void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl( 351d687caaeSEllis Hoag int MaxWarnings, InstrProfCorrelator::CorrelationData *Data) { 352d687caaeSEllis Hoag bool UnlimitedWarnings = (MaxWarnings == 0); 353d687caaeSEllis Hoag // -N suppressed warnings means we can emit up to N (unsuppressed) warnings 354d687caaeSEllis Hoag int NumSuppressedWarnings = -MaxWarnings; 35565d7fd02SEllis Hoag auto maybeAddProbe = [&](DWARFDie Die) { 35665d7fd02SEllis Hoag if (!isDIEOfProbe(Die)) 35765d7fd02SEllis Hoag return; 35818fd2aa3SKazu Hirata std::optional<const char *> FunctionName; 35989fab98eSFangrui Song std::optional<uint64_t> CFGHash; 3604e0e0bbdSFangrui Song std::optional<uint64_t> CounterPtr = getLocation(Die); 36170fb7bb5SEllis Hoag auto FnDie = Die.getParent(); 36270fb7bb5SEllis Hoag auto FunctionPtr = dwarf::toAddress(FnDie.find(dwarf::DW_AT_low_pc)); 36389fab98eSFangrui Song std::optional<uint64_t> NumCounters; 36465d7fd02SEllis Hoag for (const DWARFDie &Child : Die.children()) { 36565d7fd02SEllis Hoag if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation) 36665d7fd02SEllis Hoag continue; 36765d7fd02SEllis Hoag auto AnnotationFormName = Child.find(dwarf::DW_AT_name); 36865d7fd02SEllis Hoag auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value); 36965d7fd02SEllis Hoag if (!AnnotationFormName || !AnnotationFormValue) 37065d7fd02SEllis Hoag continue; 37165d7fd02SEllis Hoag auto AnnotationNameOrErr = AnnotationFormName->getAsCString(); 37265d7fd02SEllis Hoag if (auto Err = AnnotationNameOrErr.takeError()) { 37365d7fd02SEllis Hoag consumeError(std::move(Err)); 37465d7fd02SEllis Hoag continue; 37565d7fd02SEllis Hoag } 37665d7fd02SEllis Hoag StringRef AnnotationName = *AnnotationNameOrErr; 377b603237bSKazu Hirata if (AnnotationName == InstrProfCorrelator::FunctionNameAttributeName) { 37865d7fd02SEllis Hoag if (auto EC = 37965d7fd02SEllis Hoag AnnotationFormValue->getAsCString().moveInto(FunctionName)) 38065d7fd02SEllis Hoag consumeError(std::move(EC)); 381b603237bSKazu Hirata } else if (AnnotationName == InstrProfCorrelator::CFGHashAttributeName) { 38265d7fd02SEllis Hoag CFGHash = AnnotationFormValue->getAsUnsignedConstant(); 383b603237bSKazu Hirata } else if (AnnotationName == 384b603237bSKazu Hirata InstrProfCorrelator::NumCountersAttributeName) { 38565d7fd02SEllis Hoag NumCounters = AnnotationFormValue->getAsUnsignedConstant(); 38665d7fd02SEllis Hoag } 38765d7fd02SEllis Hoag } 38865d7fd02SEllis Hoag if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) { 389d687caaeSEllis Hoag if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) { 390d687caaeSEllis Hoag WithColor::warning() 391d687caaeSEllis Hoag << "Incomplete DIE for function " << FunctionName 392d687caaeSEllis Hoag << ": CFGHash=" << CFGHash << " CounterPtr=" << CounterPtr 393d687caaeSEllis Hoag << " NumCounters=" << NumCounters << "\n"; 39465d7fd02SEllis Hoag LLVM_DEBUG(Die.dump(dbgs())); 395d687caaeSEllis Hoag } 39665d7fd02SEllis Hoag return; 39765d7fd02SEllis Hoag } 39865d7fd02SEllis Hoag uint64_t CountersStart = this->Ctx->CountersSectionStart; 39965d7fd02SEllis Hoag uint64_t CountersEnd = this->Ctx->CountersSectionEnd; 40065d7fd02SEllis Hoag if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) { 401d687caaeSEllis Hoag if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) { 402d687caaeSEllis Hoag WithColor::warning() 403d687caaeSEllis Hoag << format("CounterPtr out of range for function %s: Actual=0x%x " 404d687caaeSEllis Hoag "Expected=[0x%x, 0x%x)\n", 405d687caaeSEllis Hoag *FunctionName, *CounterPtr, CountersStart, CountersEnd); 40665d7fd02SEllis Hoag LLVM_DEBUG(Die.dump(dbgs())); 407d687caaeSEllis Hoag } 40865d7fd02SEllis Hoag return; 40965d7fd02SEllis Hoag } 410d687caaeSEllis Hoag if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) { 411d687caaeSEllis Hoag WithColor::warning() << format("Could not find address of function %s\n", 412d687caaeSEllis Hoag *FunctionName); 41365d7fd02SEllis Hoag LLVM_DEBUG(Die.dump(dbgs())); 41465d7fd02SEllis Hoag } 415ab3430f8SZequan Wu // In debug info correlation mode, the CounterPtr is an absolute address of 416ab3430f8SZequan Wu // the counter, but it's expected to be relative later when iterating Data. 41770fb7bb5SEllis Hoag IntPtrT CounterOffset = *CounterPtr - CountersStart; 41870fb7bb5SEllis Hoag if (Data) { 41970fb7bb5SEllis Hoag InstrProfCorrelator::Probe P; 42070fb7bb5SEllis Hoag P.FunctionName = *FunctionName; 42170fb7bb5SEllis Hoag if (auto Name = FnDie.getName(DINameKind::LinkageName)) 42270fb7bb5SEllis Hoag P.LinkageName = Name; 42370fb7bb5SEllis Hoag P.CFGHash = *CFGHash; 42470fb7bb5SEllis Hoag P.CounterOffset = CounterOffset; 42570fb7bb5SEllis Hoag P.NumCounters = *NumCounters; 42670fb7bb5SEllis Hoag auto FilePath = FnDie.getDeclFile( 42770fb7bb5SEllis Hoag DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath); 42870fb7bb5SEllis Hoag if (!FilePath.empty()) 42970fb7bb5SEllis Hoag P.FilePath = FilePath; 43070fb7bb5SEllis Hoag if (auto LineNumber = FnDie.getDeclLine()) 43170fb7bb5SEllis Hoag P.LineNumber = LineNumber; 43270fb7bb5SEllis Hoag Data->Probes.push_back(P); 43370fb7bb5SEllis Hoag } else { 434ab3430f8SZequan Wu this->addDataProbe(IndexedInstrProf::ComputeHash(*FunctionName), *CFGHash, 435ab3430f8SZequan Wu CounterOffset, FunctionPtr.value_or(0), *NumCounters); 436ab3430f8SZequan Wu this->NamesVec.push_back(*FunctionName); 43770fb7bb5SEllis Hoag } 43865d7fd02SEllis Hoag }; 43965d7fd02SEllis Hoag for (auto &CU : DICtx->normal_units()) 44065d7fd02SEllis Hoag for (const auto &Entry : CU->dies()) 44165d7fd02SEllis Hoag maybeAddProbe(DWARFDie(CU.get(), &Entry)); 44265d7fd02SEllis Hoag for (auto &CU : DICtx->dwo_units()) 44365d7fd02SEllis Hoag for (const auto &Entry : CU->dies()) 44465d7fd02SEllis Hoag maybeAddProbe(DWARFDie(CU.get(), &Entry)); 445d687caaeSEllis Hoag 446d687caaeSEllis Hoag if (!UnlimitedWarnings && NumSuppressedWarnings > 0) 447d687caaeSEllis Hoag WithColor::warning() << format("Suppressed %d additional warnings\n", 448d687caaeSEllis Hoag NumSuppressedWarnings); 44965d7fd02SEllis Hoag } 4503c97c8b6SZequan Wu 4513c97c8b6SZequan Wu template <class IntPtrT> 4523c97c8b6SZequan Wu Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() { 4533c97c8b6SZequan Wu if (this->NamesVec.empty()) { 4543c97c8b6SZequan Wu return make_error<InstrProfError>( 4553c97c8b6SZequan Wu instrprof_error::unable_to_correlate_profile, 4563c97c8b6SZequan Wu "could not find any profile name metadata in debug info"); 4573c97c8b6SZequan Wu } 4583c97c8b6SZequan Wu auto Result = 4593c97c8b6SZequan Wu collectGlobalObjectNameStrings(this->NamesVec, 4603c97c8b6SZequan Wu /*doCompression=*/false, this->Names); 4613c97c8b6SZequan Wu return Result; 4623c97c8b6SZequan Wu } 463ab3430f8SZequan Wu 464ab3430f8SZequan Wu template <class IntPtrT> 465ab3430f8SZequan Wu void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl( 466ab3430f8SZequan Wu int MaxWarnings, InstrProfCorrelator::CorrelationData *CorrelateData) { 467ab3430f8SZequan Wu using RawProfData = RawInstrProf::ProfileData<IntPtrT>; 468ab3430f8SZequan Wu bool UnlimitedWarnings = (MaxWarnings == 0); 469ab3430f8SZequan Wu // -N suppressed warnings means we can emit up to N (unsuppressed) warnings 470ab3430f8SZequan Wu int NumSuppressedWarnings = -MaxWarnings; 471ab3430f8SZequan Wu 472ab3430f8SZequan Wu const RawProfData *DataStart = (const RawProfData *)this->Ctx->DataStart; 473ab3430f8SZequan Wu const RawProfData *DataEnd = (const RawProfData *)this->Ctx->DataEnd; 474ab3430f8SZequan Wu // We need to use < here because the last data record may have no padding. 475ab3430f8SZequan Wu for (const RawProfData *I = DataStart; I < DataEnd; ++I) { 476ab3430f8SZequan Wu uint64_t CounterPtr = this->template maybeSwap<IntPtrT>(I->CounterPtr); 477ab3430f8SZequan Wu uint64_t CountersStart = this->Ctx->CountersSectionStart; 478ab3430f8SZequan Wu uint64_t CountersEnd = this->Ctx->CountersSectionEnd; 479ab3430f8SZequan Wu if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) { 480ab3430f8SZequan Wu if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) { 481ab3430f8SZequan Wu WithColor::warning() 482ab3430f8SZequan Wu << format("CounterPtr out of range for function: Actual=0x%x " 483ab3430f8SZequan Wu "Expected=[0x%x, 0x%x) at data offset=0x%x\n", 484ab3430f8SZequan Wu CounterPtr, CountersStart, CountersEnd, 485ab3430f8SZequan Wu (I - DataStart) * sizeof(RawProfData)); 486ab3430f8SZequan Wu } 487ab3430f8SZequan Wu } 488ab3430f8SZequan Wu // In binary correlation mode, the CounterPtr is an absolute address of the 489ab3430f8SZequan Wu // counter, but it's expected to be relative later when iterating Data. 490ab3430f8SZequan Wu IntPtrT CounterOffset = CounterPtr - CountersStart; 491ab3430f8SZequan Wu this->addDataProbe(I->NameRef, I->FuncHash, CounterOffset, 492ab3430f8SZequan Wu I->FunctionPointer, I->NumCounters); 493ab3430f8SZequan Wu } 494ab3430f8SZequan Wu } 495ab3430f8SZequan Wu 496ab3430f8SZequan Wu template <class IntPtrT> 497ab3430f8SZequan Wu Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() { 498ab3430f8SZequan Wu if (this->Ctx->NameSize == 0) { 499ab3430f8SZequan Wu return make_error<InstrProfError>( 500ab3430f8SZequan Wu instrprof_error::unable_to_correlate_profile, 501ab3430f8SZequan Wu "could not find any profile data metadata in object file"); 502ab3430f8SZequan Wu } 503ab3430f8SZequan Wu this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize); 504ab3430f8SZequan Wu return Error::success(); 505ab3430f8SZequan Wu } 506