xref: /freebsd-src/contrib/llvm-project/llvm/lib/ProfileData/InstrProfCorrelator.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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