10eae32dcSDimitry Andric //===-- InstrProfCorrelator.cpp -------------------------------------------===// 20eae32dcSDimitry Andric // 30eae32dcSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40eae32dcSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50eae32dcSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60eae32dcSDimitry Andric // 70eae32dcSDimitry Andric //===----------------------------------------------------------------------===// 80eae32dcSDimitry Andric 90eae32dcSDimitry Andric #include "llvm/ProfileData/InstrProfCorrelator.h" 1081ad6265SDimitry Andric #include "llvm/DebugInfo/DIContext.h" 1181ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h" 1281ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDie.h" 1381ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 1481ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" 1581ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" 1681ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFUnit.h" 170eae32dcSDimitry Andric #include "llvm/Object/MachO.h" 180eae32dcSDimitry Andric #include "llvm/Support/Debug.h" 195f757f3fSDimitry Andric #include "llvm/Support/Format.h" 205f757f3fSDimitry Andric #include "llvm/Support/WithColor.h" 21bdd1243dSDimitry Andric #include <optional> 220eae32dcSDimitry Andric 230eae32dcSDimitry Andric #define DEBUG_TYPE "correlator" 240eae32dcSDimitry Andric 250eae32dcSDimitry Andric using namespace llvm; 260eae32dcSDimitry Andric 275f757f3fSDimitry Andric /// Get profile section. 285f757f3fSDimitry Andric Expected<object::SectionRef> getInstrProfSection(const object::ObjectFile &Obj, 295f757f3fSDimitry Andric InstrProfSectKind IPSK) { 305f757f3fSDimitry Andric // On COFF, the getInstrProfSectionName returns the section names may followed 315f757f3fSDimitry Andric // by "$M". The linker removes the dollar and everything after it in the final 325f757f3fSDimitry Andric // binary. Do the same to match. 335f757f3fSDimitry Andric Triple::ObjectFormatType ObjFormat = Obj.getTripleObjectFormat(); 345f757f3fSDimitry Andric auto StripSuffix = [ObjFormat](StringRef N) { 355f757f3fSDimitry Andric return ObjFormat == Triple::COFF ? N.split('$').first : N; 365f757f3fSDimitry Andric }; 375f757f3fSDimitry Andric std::string ExpectedSectionName = 385f757f3fSDimitry Andric getInstrProfSectionName(IPSK, ObjFormat, 395f757f3fSDimitry Andric /*AddSegmentInfo=*/false); 405f757f3fSDimitry Andric ExpectedSectionName = StripSuffix(ExpectedSectionName); 415f757f3fSDimitry Andric for (auto &Section : Obj.sections()) { 420eae32dcSDimitry Andric if (auto SectionName = Section.getName()) 435f757f3fSDimitry Andric if (*SectionName == ExpectedSectionName) 440eae32dcSDimitry Andric return Section; 455f757f3fSDimitry Andric } 460eae32dcSDimitry Andric return make_error<InstrProfError>( 4704eeddc0SDimitry Andric instrprof_error::unable_to_correlate_profile, 485f757f3fSDimitry Andric "could not find section (" + Twine(ExpectedSectionName) + ")"); 490eae32dcSDimitry Andric } 500eae32dcSDimitry Andric 510eae32dcSDimitry Andric const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name"; 520eae32dcSDimitry Andric const char *InstrProfCorrelator::CFGHashAttributeName = "CFG Hash"; 530eae32dcSDimitry Andric const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters"; 540eae32dcSDimitry Andric 550eae32dcSDimitry Andric llvm::Expected<std::unique_ptr<InstrProfCorrelator::Context>> 560eae32dcSDimitry Andric InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer, 575f757f3fSDimitry Andric const object::ObjectFile &Obj, 585f757f3fSDimitry Andric ProfCorrelatorKind FileKind) { 595f757f3fSDimitry Andric auto C = std::make_unique<Context>(); 605f757f3fSDimitry Andric auto CountersSection = getInstrProfSection(Obj, IPSK_cnts); 610eae32dcSDimitry Andric if (auto Err = CountersSection.takeError()) 620eae32dcSDimitry Andric return std::move(Err); 635f757f3fSDimitry Andric if (FileKind == InstrProfCorrelator::BINARY) { 645f757f3fSDimitry Andric auto DataSection = getInstrProfSection(Obj, IPSK_covdata); 655f757f3fSDimitry Andric if (auto Err = DataSection.takeError()) 665f757f3fSDimitry Andric return std::move(Err); 675f757f3fSDimitry Andric auto DataOrErr = DataSection->getContents(); 685f757f3fSDimitry Andric if (!DataOrErr) 695f757f3fSDimitry Andric return DataOrErr.takeError(); 705f757f3fSDimitry Andric auto NameSection = getInstrProfSection(Obj, IPSK_covname); 715f757f3fSDimitry Andric if (auto Err = NameSection.takeError()) 725f757f3fSDimitry Andric return std::move(Err); 735f757f3fSDimitry Andric auto NameOrErr = NameSection->getContents(); 745f757f3fSDimitry Andric if (!NameOrErr) 755f757f3fSDimitry Andric return NameOrErr.takeError(); 765f757f3fSDimitry Andric C->DataStart = DataOrErr->data(); 775f757f3fSDimitry Andric C->DataEnd = DataOrErr->data() + DataOrErr->size(); 785f757f3fSDimitry Andric C->NameStart = NameOrErr->data(); 795f757f3fSDimitry Andric C->NameSize = NameOrErr->size(); 805f757f3fSDimitry Andric } 810eae32dcSDimitry Andric C->Buffer = std::move(Buffer); 820eae32dcSDimitry Andric C->CountersSectionStart = CountersSection->getAddress(); 830eae32dcSDimitry Andric C->CountersSectionEnd = C->CountersSectionStart + CountersSection->getSize(); 845f757f3fSDimitry Andric // In COFF object file, there's a null byte at the beginning of the counter 855f757f3fSDimitry Andric // section which doesn't exist in raw profile. 865f757f3fSDimitry Andric if (Obj.getTripleObjectFormat() == Triple::COFF) 875f757f3fSDimitry Andric ++C->CountersSectionStart; 885f757f3fSDimitry Andric 890eae32dcSDimitry Andric C->ShouldSwapBytes = Obj.isLittleEndian() != sys::IsLittleEndianHost; 900eae32dcSDimitry Andric return Expected<std::unique_ptr<Context>>(std::move(C)); 910eae32dcSDimitry Andric } 920eae32dcSDimitry Andric 930eae32dcSDimitry Andric llvm::Expected<std::unique_ptr<InstrProfCorrelator>> 945f757f3fSDimitry Andric InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind) { 955f757f3fSDimitry Andric if (FileKind == DEBUG_INFO) { 960eae32dcSDimitry Andric auto DsymObjectsOrErr = 975f757f3fSDimitry Andric object::MachOObjectFile::findDsymObjectMembers(Filename); 980eae32dcSDimitry Andric if (auto Err = DsymObjectsOrErr.takeError()) 990eae32dcSDimitry Andric return std::move(Err); 1000eae32dcSDimitry Andric if (!DsymObjectsOrErr->empty()) { 1010eae32dcSDimitry Andric // TODO: Enable profile correlation when there are multiple objects in a 1020eae32dcSDimitry Andric // dSYM bundle. 1030eae32dcSDimitry Andric if (DsymObjectsOrErr->size() > 1) 10404eeddc0SDimitry Andric return make_error<InstrProfError>( 10504eeddc0SDimitry Andric instrprof_error::unable_to_correlate_profile, 10604eeddc0SDimitry Andric "using multiple objects is not yet supported"); 1075f757f3fSDimitry Andric Filename = *DsymObjectsOrErr->begin(); 1080eae32dcSDimitry Andric } 1095f757f3fSDimitry Andric auto BufferOrErr = errorOrToExpected(MemoryBuffer::getFile(Filename)); 1100eae32dcSDimitry Andric if (auto Err = BufferOrErr.takeError()) 1110eae32dcSDimitry Andric return std::move(Err); 1120eae32dcSDimitry Andric 1135f757f3fSDimitry Andric return get(std::move(*BufferOrErr), FileKind); 1145f757f3fSDimitry Andric } 1155f757f3fSDimitry Andric if (FileKind == BINARY) { 1165f757f3fSDimitry Andric auto BufferOrErr = errorOrToExpected(MemoryBuffer::getFile(Filename)); 1175f757f3fSDimitry Andric if (auto Err = BufferOrErr.takeError()) 1185f757f3fSDimitry Andric return std::move(Err); 1195f757f3fSDimitry Andric 1205f757f3fSDimitry Andric return get(std::move(*BufferOrErr), FileKind); 1215f757f3fSDimitry Andric } 1225f757f3fSDimitry Andric return make_error<InstrProfError>( 1235f757f3fSDimitry Andric instrprof_error::unable_to_correlate_profile, 1245f757f3fSDimitry Andric "unsupported correlation kind (only DWARF debug info and Binary format " 1255f757f3fSDimitry Andric "(ELF/COFF) are supported)"); 1260eae32dcSDimitry Andric } 1270eae32dcSDimitry Andric 1280eae32dcSDimitry Andric llvm::Expected<std::unique_ptr<InstrProfCorrelator>> 1295f757f3fSDimitry Andric InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer, 1305f757f3fSDimitry Andric ProfCorrelatorKind FileKind) { 1310eae32dcSDimitry Andric auto BinOrErr = object::createBinary(*Buffer); 1320eae32dcSDimitry Andric if (auto Err = BinOrErr.takeError()) 1330eae32dcSDimitry Andric return std::move(Err); 1340eae32dcSDimitry Andric 1350eae32dcSDimitry Andric if (auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) { 1365f757f3fSDimitry Andric auto CtxOrErr = Context::get(std::move(Buffer), *Obj, FileKind); 1370eae32dcSDimitry Andric if (auto Err = CtxOrErr.takeError()) 1380eae32dcSDimitry Andric return std::move(Err); 1390eae32dcSDimitry Andric auto T = Obj->makeTriple(); 1400eae32dcSDimitry Andric if (T.isArch64Bit()) 1415f757f3fSDimitry Andric return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj, 1425f757f3fSDimitry Andric FileKind); 1430eae32dcSDimitry Andric if (T.isArch32Bit()) 1445f757f3fSDimitry Andric return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj, 1455f757f3fSDimitry Andric FileKind); 1460eae32dcSDimitry Andric } 1470eae32dcSDimitry Andric return make_error<InstrProfError>( 14804eeddc0SDimitry Andric instrprof_error::unable_to_correlate_profile, "not an object file"); 14904eeddc0SDimitry Andric } 15004eeddc0SDimitry Andric 151bdd1243dSDimitry Andric std::optional<size_t> InstrProfCorrelator::getDataSize() const { 15204eeddc0SDimitry Andric if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint32_t>>(this)) { 15304eeddc0SDimitry Andric return C->getDataSize(); 15404eeddc0SDimitry Andric } else if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint64_t>>(this)) { 15504eeddc0SDimitry Andric return C->getDataSize(); 15604eeddc0SDimitry Andric } 15704eeddc0SDimitry Andric return {}; 1580eae32dcSDimitry Andric } 1590eae32dcSDimitry Andric 1600eae32dcSDimitry Andric namespace llvm { 1610eae32dcSDimitry Andric 1620eae32dcSDimitry Andric template <> 1630eae32dcSDimitry Andric InstrProfCorrelatorImpl<uint32_t>::InstrProfCorrelatorImpl( 1640eae32dcSDimitry Andric std::unique_ptr<InstrProfCorrelator::Context> Ctx) 1650eae32dcSDimitry Andric : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_32Bit, 1660eae32dcSDimitry Andric std::move(Ctx)) {} 1670eae32dcSDimitry Andric template <> 1680eae32dcSDimitry Andric InstrProfCorrelatorImpl<uint64_t>::InstrProfCorrelatorImpl( 1690eae32dcSDimitry Andric std::unique_ptr<InstrProfCorrelator::Context> Ctx) 1700eae32dcSDimitry Andric : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_64Bit, 1710eae32dcSDimitry Andric std::move(Ctx)) {} 1720eae32dcSDimitry Andric template <> 1730eae32dcSDimitry Andric bool InstrProfCorrelatorImpl<uint32_t>::classof(const InstrProfCorrelator *C) { 1740eae32dcSDimitry Andric return C->getKind() == InstrProfCorrelatorKind::CK_32Bit; 1750eae32dcSDimitry Andric } 1760eae32dcSDimitry Andric template <> 1770eae32dcSDimitry Andric bool InstrProfCorrelatorImpl<uint64_t>::classof(const InstrProfCorrelator *C) { 1780eae32dcSDimitry Andric return C->getKind() == InstrProfCorrelatorKind::CK_64Bit; 1790eae32dcSDimitry Andric } 1800eae32dcSDimitry Andric 1810eae32dcSDimitry Andric } // end namespace llvm 1820eae32dcSDimitry Andric 1830eae32dcSDimitry Andric template <class IntPtrT> 1840eae32dcSDimitry Andric llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>> 1850eae32dcSDimitry Andric InstrProfCorrelatorImpl<IntPtrT>::get( 1860eae32dcSDimitry Andric std::unique_ptr<InstrProfCorrelator::Context> Ctx, 1875f757f3fSDimitry Andric const object::ObjectFile &Obj, ProfCorrelatorKind FileKind) { 1885f757f3fSDimitry Andric if (FileKind == DEBUG_INFO) { 1890eae32dcSDimitry Andric if (Obj.isELF() || Obj.isMachO()) { 1900eae32dcSDimitry Andric auto DICtx = DWARFContext::create(Obj); 1915f757f3fSDimitry Andric return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>( 1925f757f3fSDimitry Andric std::move(DICtx), std::move(Ctx)); 1930eae32dcSDimitry Andric } 19404eeddc0SDimitry Andric return make_error<InstrProfError>( 19504eeddc0SDimitry Andric instrprof_error::unable_to_correlate_profile, 19604eeddc0SDimitry Andric "unsupported debug info format (only DWARF is supported)"); 1970eae32dcSDimitry Andric } 1985f757f3fSDimitry Andric if (Obj.isELF() || Obj.isCOFF()) 1995f757f3fSDimitry Andric return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx)); 20004eeddc0SDimitry Andric return make_error<InstrProfError>( 20104eeddc0SDimitry Andric instrprof_error::unable_to_correlate_profile, 2025f757f3fSDimitry Andric "unsupported binary format (only ELF and COFF are supported)"); 2035f757f3fSDimitry Andric } 2045f757f3fSDimitry Andric 2055f757f3fSDimitry Andric template <class IntPtrT> 2065f757f3fSDimitry Andric Error InstrProfCorrelatorImpl<IntPtrT>::correlateProfileData(int MaxWarnings) { 2075f757f3fSDimitry Andric assert(Data.empty() && Names.empty() && NamesVec.empty()); 2085f757f3fSDimitry Andric correlateProfileDataImpl(MaxWarnings); 2095f757f3fSDimitry Andric if (this->Data.empty()) 2105f757f3fSDimitry Andric return make_error<InstrProfError>( 2115f757f3fSDimitry Andric instrprof_error::unable_to_correlate_profile, 2125f757f3fSDimitry Andric "could not find any profile data metadata in correlated file"); 2135f757f3fSDimitry Andric Error Result = correlateProfileNameImpl(); 2145f757f3fSDimitry Andric this->CounterOffsets.clear(); 2155f757f3fSDimitry Andric this->NamesVec.clear(); 2160eae32dcSDimitry Andric return Result; 2170eae32dcSDimitry Andric } 2180eae32dcSDimitry Andric 219bdd1243dSDimitry Andric template <> struct yaml::MappingTraits<InstrProfCorrelator::CorrelationData> { 220bdd1243dSDimitry Andric static void mapping(yaml::IO &io, 221bdd1243dSDimitry Andric InstrProfCorrelator::CorrelationData &Data) { 222bdd1243dSDimitry Andric io.mapRequired("Probes", Data.Probes); 223bdd1243dSDimitry Andric } 224bdd1243dSDimitry Andric }; 225bdd1243dSDimitry Andric 226bdd1243dSDimitry Andric template <> struct yaml::MappingTraits<InstrProfCorrelator::Probe> { 227bdd1243dSDimitry Andric static void mapping(yaml::IO &io, InstrProfCorrelator::Probe &P) { 228bdd1243dSDimitry Andric io.mapRequired("Function Name", P.FunctionName); 229bdd1243dSDimitry Andric io.mapOptional("Linkage Name", P.LinkageName); 230bdd1243dSDimitry Andric io.mapRequired("CFG Hash", P.CFGHash); 231bdd1243dSDimitry Andric io.mapRequired("Counter Offset", P.CounterOffset); 232bdd1243dSDimitry Andric io.mapRequired("Num Counters", P.NumCounters); 233bdd1243dSDimitry Andric io.mapOptional("File", P.FilePath); 234bdd1243dSDimitry Andric io.mapOptional("Line", P.LineNumber); 235bdd1243dSDimitry Andric } 236bdd1243dSDimitry Andric }; 237bdd1243dSDimitry Andric 238bdd1243dSDimitry Andric template <> struct yaml::SequenceElementTraits<InstrProfCorrelator::Probe> { 239bdd1243dSDimitry Andric static const bool flow = false; 240bdd1243dSDimitry Andric }; 241bdd1243dSDimitry Andric 242bdd1243dSDimitry Andric template <class IntPtrT> 2435f757f3fSDimitry Andric Error InstrProfCorrelatorImpl<IntPtrT>::dumpYaml(int MaxWarnings, 2445f757f3fSDimitry Andric raw_ostream &OS) { 245bdd1243dSDimitry Andric InstrProfCorrelator::CorrelationData Data; 2465f757f3fSDimitry Andric correlateProfileDataImpl(MaxWarnings, &Data); 247bdd1243dSDimitry Andric if (Data.Probes.empty()) 248bdd1243dSDimitry Andric return make_error<InstrProfError>( 249bdd1243dSDimitry Andric instrprof_error::unable_to_correlate_profile, 2505f757f3fSDimitry Andric "could not find any profile data metadata in debug info"); 251bdd1243dSDimitry Andric yaml::Output YamlOS(OS); 252bdd1243dSDimitry Andric YamlOS << Data; 253bdd1243dSDimitry Andric return Error::success(); 254bdd1243dSDimitry Andric } 255bdd1243dSDimitry Andric 2560eae32dcSDimitry Andric template <class IntPtrT> 2575f757f3fSDimitry Andric void InstrProfCorrelatorImpl<IntPtrT>::addDataProbe(uint64_t NameRef, 2580eae32dcSDimitry Andric uint64_t CFGHash, 2590eae32dcSDimitry Andric IntPtrT CounterOffset, 2600eae32dcSDimitry Andric IntPtrT FunctionPtr, 2610eae32dcSDimitry Andric uint32_t NumCounters) { 26204eeddc0SDimitry Andric // Check if a probe was already added for this counter offset. 26304eeddc0SDimitry Andric if (!CounterOffsets.insert(CounterOffset).second) 26404eeddc0SDimitry Andric return; 2650eae32dcSDimitry Andric Data.push_back({ 2665f757f3fSDimitry Andric maybeSwap<uint64_t>(NameRef), 2670eae32dcSDimitry Andric maybeSwap<uint64_t>(CFGHash), 2680eae32dcSDimitry Andric // In this mode, CounterPtr actually stores the section relative address 2690eae32dcSDimitry Andric // of the counter. 2700eae32dcSDimitry Andric maybeSwap<IntPtrT>(CounterOffset), 2715f757f3fSDimitry Andric // TODO: MC/DC is not yet supported. 2725f757f3fSDimitry Andric /*BitmapOffset=*/maybeSwap<IntPtrT>(0), 2730eae32dcSDimitry Andric maybeSwap<IntPtrT>(FunctionPtr), 2740eae32dcSDimitry Andric // TODO: Value profiling is not yet supported. 2750eae32dcSDimitry Andric /*ValuesPtr=*/maybeSwap<IntPtrT>(0), 2760eae32dcSDimitry Andric maybeSwap<uint32_t>(NumCounters), 2770eae32dcSDimitry Andric /*NumValueSites=*/{maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)}, 2785f757f3fSDimitry Andric // TODO: MC/DC is not yet supported. 2795f757f3fSDimitry Andric /*NumBitmapBytes=*/maybeSwap<uint32_t>(0), 2800eae32dcSDimitry Andric }); 2810eae32dcSDimitry Andric } 2820eae32dcSDimitry Andric 2830eae32dcSDimitry Andric template <class IntPtrT> 284bdd1243dSDimitry Andric std::optional<uint64_t> 2850eae32dcSDimitry Andric DwarfInstrProfCorrelator<IntPtrT>::getLocation(const DWARFDie &Die) const { 2860eae32dcSDimitry Andric auto Locations = Die.getLocations(dwarf::DW_AT_location); 2870eae32dcSDimitry Andric if (!Locations) { 2880eae32dcSDimitry Andric consumeError(Locations.takeError()); 2890eae32dcSDimitry Andric return {}; 2900eae32dcSDimitry Andric } 2910eae32dcSDimitry Andric auto &DU = *Die.getDwarfUnit(); 2920eae32dcSDimitry Andric auto AddressSize = DU.getAddressByteSize(); 29304eeddc0SDimitry Andric for (auto &Location : *Locations) { 2940eae32dcSDimitry Andric DataExtractor Data(Location.Expr, DICtx->isLittleEndian(), AddressSize); 2950eae32dcSDimitry Andric DWARFExpression Expr(Data, AddressSize); 29604eeddc0SDimitry Andric for (auto &Op : Expr) { 29704eeddc0SDimitry Andric if (Op.getCode() == dwarf::DW_OP_addr) { 2980eae32dcSDimitry Andric return Op.getRawOperand(0); 29904eeddc0SDimitry Andric } else if (Op.getCode() == dwarf::DW_OP_addrx) { 30004eeddc0SDimitry Andric uint64_t Index = Op.getRawOperand(0); 30104eeddc0SDimitry Andric if (auto SA = DU.getAddrOffsetSectionItem(Index)) 30204eeddc0SDimitry Andric return SA->Address; 30304eeddc0SDimitry Andric } 30404eeddc0SDimitry Andric } 3050eae32dcSDimitry Andric } 3060eae32dcSDimitry Andric return {}; 3070eae32dcSDimitry Andric } 3080eae32dcSDimitry Andric 3090eae32dcSDimitry Andric template <class IntPtrT> 3100eae32dcSDimitry Andric bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(const DWARFDie &Die) { 3110eae32dcSDimitry Andric const auto &ParentDie = Die.getParent(); 3120eae32dcSDimitry Andric if (!Die.isValid() || !ParentDie.isValid() || Die.isNULL()) 3130eae32dcSDimitry Andric return false; 3140eae32dcSDimitry Andric if (Die.getTag() != dwarf::DW_TAG_variable) 3150eae32dcSDimitry Andric return false; 3160eae32dcSDimitry Andric if (!ParentDie.isSubprogramDIE()) 3170eae32dcSDimitry Andric return false; 3180eae32dcSDimitry Andric if (!Die.hasChildren()) 3190eae32dcSDimitry Andric return false; 3200eae32dcSDimitry Andric if (const char *Name = Die.getName(DINameKind::ShortName)) 3215f757f3fSDimitry Andric return StringRef(Name).starts_with(getInstrProfCountersVarPrefix()); 3220eae32dcSDimitry Andric return false; 3230eae32dcSDimitry Andric } 3240eae32dcSDimitry Andric 3250eae32dcSDimitry Andric template <class IntPtrT> 326bdd1243dSDimitry Andric void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl( 3275f757f3fSDimitry Andric int MaxWarnings, InstrProfCorrelator::CorrelationData *Data) { 3285f757f3fSDimitry Andric bool UnlimitedWarnings = (MaxWarnings == 0); 3295f757f3fSDimitry Andric // -N suppressed warnings means we can emit up to N (unsuppressed) warnings 3305f757f3fSDimitry Andric int NumSuppressedWarnings = -MaxWarnings; 3310eae32dcSDimitry Andric auto maybeAddProbe = [&](DWARFDie Die) { 3320eae32dcSDimitry Andric if (!isDIEOfProbe(Die)) 3330eae32dcSDimitry Andric return; 334bdd1243dSDimitry Andric std::optional<const char *> FunctionName; 335bdd1243dSDimitry Andric std::optional<uint64_t> CFGHash; 336bdd1243dSDimitry Andric std::optional<uint64_t> CounterPtr = getLocation(Die); 337bdd1243dSDimitry Andric auto FnDie = Die.getParent(); 338bdd1243dSDimitry Andric auto FunctionPtr = dwarf::toAddress(FnDie.find(dwarf::DW_AT_low_pc)); 339bdd1243dSDimitry Andric std::optional<uint64_t> NumCounters; 3400eae32dcSDimitry Andric for (const DWARFDie &Child : Die.children()) { 3410eae32dcSDimitry Andric if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation) 3420eae32dcSDimitry Andric continue; 3430eae32dcSDimitry Andric auto AnnotationFormName = Child.find(dwarf::DW_AT_name); 3440eae32dcSDimitry Andric auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value); 3450eae32dcSDimitry Andric if (!AnnotationFormName || !AnnotationFormValue) 3460eae32dcSDimitry Andric continue; 3470eae32dcSDimitry Andric auto AnnotationNameOrErr = AnnotationFormName->getAsCString(); 3480eae32dcSDimitry Andric if (auto Err = AnnotationNameOrErr.takeError()) { 3490eae32dcSDimitry Andric consumeError(std::move(Err)); 3500eae32dcSDimitry Andric continue; 3510eae32dcSDimitry Andric } 3520eae32dcSDimitry Andric StringRef AnnotationName = *AnnotationNameOrErr; 353*0fca6ea1SDimitry Andric if (AnnotationName == InstrProfCorrelator::FunctionNameAttributeName) { 3540eae32dcSDimitry Andric if (auto EC = 3550eae32dcSDimitry Andric AnnotationFormValue->getAsCString().moveInto(FunctionName)) 3560eae32dcSDimitry Andric consumeError(std::move(EC)); 357*0fca6ea1SDimitry Andric } else if (AnnotationName == InstrProfCorrelator::CFGHashAttributeName) { 3580eae32dcSDimitry Andric CFGHash = AnnotationFormValue->getAsUnsignedConstant(); 359*0fca6ea1SDimitry Andric } else if (AnnotationName == 360*0fca6ea1SDimitry Andric InstrProfCorrelator::NumCountersAttributeName) { 3610eae32dcSDimitry Andric NumCounters = AnnotationFormValue->getAsUnsignedConstant(); 3620eae32dcSDimitry Andric } 3630eae32dcSDimitry Andric } 3640eae32dcSDimitry Andric if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) { 3655f757f3fSDimitry Andric if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) { 3665f757f3fSDimitry Andric WithColor::warning() 3675f757f3fSDimitry Andric << "Incomplete DIE for function " << FunctionName 3685f757f3fSDimitry Andric << ": CFGHash=" << CFGHash << " CounterPtr=" << CounterPtr 3695f757f3fSDimitry Andric << " NumCounters=" << NumCounters << "\n"; 3700eae32dcSDimitry Andric LLVM_DEBUG(Die.dump(dbgs())); 3715f757f3fSDimitry Andric } 3720eae32dcSDimitry Andric return; 3730eae32dcSDimitry Andric } 3740eae32dcSDimitry Andric uint64_t CountersStart = this->Ctx->CountersSectionStart; 3750eae32dcSDimitry Andric uint64_t CountersEnd = this->Ctx->CountersSectionEnd; 3760eae32dcSDimitry Andric if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) { 3775f757f3fSDimitry Andric if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) { 3785f757f3fSDimitry Andric WithColor::warning() 3795f757f3fSDimitry Andric << format("CounterPtr out of range for function %s: Actual=0x%x " 3805f757f3fSDimitry Andric "Expected=[0x%x, 0x%x)\n", 3815f757f3fSDimitry Andric *FunctionName, *CounterPtr, CountersStart, CountersEnd); 3820eae32dcSDimitry Andric LLVM_DEBUG(Die.dump(dbgs())); 3835f757f3fSDimitry Andric } 3840eae32dcSDimitry Andric return; 3850eae32dcSDimitry Andric } 3865f757f3fSDimitry Andric if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) { 3875f757f3fSDimitry Andric WithColor::warning() << format("Could not find address of function %s\n", 3885f757f3fSDimitry Andric *FunctionName); 3890eae32dcSDimitry Andric LLVM_DEBUG(Die.dump(dbgs())); 3900eae32dcSDimitry Andric } 3915f757f3fSDimitry Andric // In debug info correlation mode, the CounterPtr is an absolute address of 3925f757f3fSDimitry Andric // the counter, but it's expected to be relative later when iterating Data. 393bdd1243dSDimitry Andric IntPtrT CounterOffset = *CounterPtr - CountersStart; 394bdd1243dSDimitry Andric if (Data) { 395bdd1243dSDimitry Andric InstrProfCorrelator::Probe P; 396bdd1243dSDimitry Andric P.FunctionName = *FunctionName; 397bdd1243dSDimitry Andric if (auto Name = FnDie.getName(DINameKind::LinkageName)) 398bdd1243dSDimitry Andric P.LinkageName = Name; 399bdd1243dSDimitry Andric P.CFGHash = *CFGHash; 400bdd1243dSDimitry Andric P.CounterOffset = CounterOffset; 401bdd1243dSDimitry Andric P.NumCounters = *NumCounters; 402bdd1243dSDimitry Andric auto FilePath = FnDie.getDeclFile( 403bdd1243dSDimitry Andric DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath); 404bdd1243dSDimitry Andric if (!FilePath.empty()) 405bdd1243dSDimitry Andric P.FilePath = FilePath; 406bdd1243dSDimitry Andric if (auto LineNumber = FnDie.getDeclLine()) 407bdd1243dSDimitry Andric P.LineNumber = LineNumber; 408bdd1243dSDimitry Andric Data->Probes.push_back(P); 409bdd1243dSDimitry Andric } else { 4105f757f3fSDimitry Andric this->addDataProbe(IndexedInstrProf::ComputeHash(*FunctionName), *CFGHash, 4115f757f3fSDimitry Andric CounterOffset, FunctionPtr.value_or(0), *NumCounters); 4125f757f3fSDimitry Andric this->NamesVec.push_back(*FunctionName); 413bdd1243dSDimitry Andric } 4140eae32dcSDimitry Andric }; 4150eae32dcSDimitry Andric for (auto &CU : DICtx->normal_units()) 4160eae32dcSDimitry Andric for (const auto &Entry : CU->dies()) 4170eae32dcSDimitry Andric maybeAddProbe(DWARFDie(CU.get(), &Entry)); 4180eae32dcSDimitry Andric for (auto &CU : DICtx->dwo_units()) 4190eae32dcSDimitry Andric for (const auto &Entry : CU->dies()) 4200eae32dcSDimitry Andric maybeAddProbe(DWARFDie(CU.get(), &Entry)); 4215f757f3fSDimitry Andric 4225f757f3fSDimitry Andric if (!UnlimitedWarnings && NumSuppressedWarnings > 0) 4235f757f3fSDimitry Andric WithColor::warning() << format("Suppressed %d additional warnings\n", 4245f757f3fSDimitry Andric NumSuppressedWarnings); 4255f757f3fSDimitry Andric } 4265f757f3fSDimitry Andric 4275f757f3fSDimitry Andric template <class IntPtrT> 4285f757f3fSDimitry Andric Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() { 4295f757f3fSDimitry Andric if (this->NamesVec.empty()) { 4305f757f3fSDimitry Andric return make_error<InstrProfError>( 4315f757f3fSDimitry Andric instrprof_error::unable_to_correlate_profile, 4325f757f3fSDimitry Andric "could not find any profile name metadata in debug info"); 4335f757f3fSDimitry Andric } 4345f757f3fSDimitry Andric auto Result = 4355f757f3fSDimitry Andric collectGlobalObjectNameStrings(this->NamesVec, 4365f757f3fSDimitry Andric /*doCompression=*/false, this->Names); 4375f757f3fSDimitry Andric return Result; 4385f757f3fSDimitry Andric } 4395f757f3fSDimitry Andric 4405f757f3fSDimitry Andric template <class IntPtrT> 4415f757f3fSDimitry Andric void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl( 4425f757f3fSDimitry Andric int MaxWarnings, InstrProfCorrelator::CorrelationData *CorrelateData) { 4435f757f3fSDimitry Andric using RawProfData = RawInstrProf::ProfileData<IntPtrT>; 4445f757f3fSDimitry Andric bool UnlimitedWarnings = (MaxWarnings == 0); 4455f757f3fSDimitry Andric // -N suppressed warnings means we can emit up to N (unsuppressed) warnings 4465f757f3fSDimitry Andric int NumSuppressedWarnings = -MaxWarnings; 4475f757f3fSDimitry Andric 4485f757f3fSDimitry Andric const RawProfData *DataStart = (const RawProfData *)this->Ctx->DataStart; 4495f757f3fSDimitry Andric const RawProfData *DataEnd = (const RawProfData *)this->Ctx->DataEnd; 4505f757f3fSDimitry Andric // We need to use < here because the last data record may have no padding. 4515f757f3fSDimitry Andric for (const RawProfData *I = DataStart; I < DataEnd; ++I) { 4525f757f3fSDimitry Andric uint64_t CounterPtr = this->template maybeSwap<IntPtrT>(I->CounterPtr); 4535f757f3fSDimitry Andric uint64_t CountersStart = this->Ctx->CountersSectionStart; 4545f757f3fSDimitry Andric uint64_t CountersEnd = this->Ctx->CountersSectionEnd; 4555f757f3fSDimitry Andric if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) { 4565f757f3fSDimitry Andric if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) { 4575f757f3fSDimitry Andric WithColor::warning() 4585f757f3fSDimitry Andric << format("CounterPtr out of range for function: Actual=0x%x " 4595f757f3fSDimitry Andric "Expected=[0x%x, 0x%x) at data offset=0x%x\n", 4605f757f3fSDimitry Andric CounterPtr, CountersStart, CountersEnd, 4615f757f3fSDimitry Andric (I - DataStart) * sizeof(RawProfData)); 4625f757f3fSDimitry Andric } 4635f757f3fSDimitry Andric } 4645f757f3fSDimitry Andric // In binary correlation mode, the CounterPtr is an absolute address of the 4655f757f3fSDimitry Andric // counter, but it's expected to be relative later when iterating Data. 4665f757f3fSDimitry Andric IntPtrT CounterOffset = CounterPtr - CountersStart; 4675f757f3fSDimitry Andric this->addDataProbe(I->NameRef, I->FuncHash, CounterOffset, 4685f757f3fSDimitry Andric I->FunctionPointer, I->NumCounters); 4695f757f3fSDimitry Andric } 4705f757f3fSDimitry Andric } 4715f757f3fSDimitry Andric 4725f757f3fSDimitry Andric template <class IntPtrT> 4735f757f3fSDimitry Andric Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() { 4745f757f3fSDimitry Andric if (this->Ctx->NameSize == 0) { 4755f757f3fSDimitry Andric return make_error<InstrProfError>( 4765f757f3fSDimitry Andric instrprof_error::unable_to_correlate_profile, 4775f757f3fSDimitry Andric "could not find any profile data metadata in object file"); 4785f757f3fSDimitry Andric } 4795f757f3fSDimitry Andric this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize); 4805f757f3fSDimitry Andric return Error::success(); 4810eae32dcSDimitry Andric } 482