23#define DEBUG_TYPE "correlator"
37 std::string ExpectedSectionName =
40 ExpectedSectionName = StripSuffix(ExpectedSectionName);
41 for (
auto &Section : Obj.sections()) {
48 "could not find section (" +
Twine(ExpectedSectionName) +
")");
60 auto C = std::make_unique<Context>();
62 if (
auto Err = CountersSection.takeError())
63 return std::move(Err);
67 if (
auto Err = DataSection.takeError())
68 return std::move(Err);
69 auto DataOrErr = DataSection->getContents();
71 return DataOrErr.takeError();
73 if (
auto Err = NameSection.takeError())
74 return std::move(Err);
75 auto NameOrErr = NameSection->getContents();
77 return NameOrErr.takeError();
78 C->DataStart = DataOrErr->data();
79 C->DataEnd = DataOrErr->data() + DataOrErr->size();
80 C->NameStart = NameOrErr->data();
81 C->NameSize = NameOrErr->size();
84 std::string FullSectionName =
91 MachO->fixupTable(Err)) {
92 if (Entry.isRebase() && Entry.segmentName() == SegmentAndSection[0] &&
93 Entry.sectionName() == SegmentAndSection[1]) {
94 C->MachOFixups[Entry.address() - DataSection->getAddress()] =
99 return std::move(Err);
103 C->CountersSectionStart = CountersSection->getAddress();
104 C->CountersSectionEnd =
C->CountersSectionStart + CountersSection->getSize();
107 if (
auto E = BitmapSection.takeError()) {
110 C->BitmapSectionStart = 0;
111 C->BitmapSectionEnd = 0;
113 C->BitmapSectionStart = BitmapSection->getAddress();
114 C->BitmapSectionEnd =
C->BitmapSectionStart + BitmapSection->getSize();
119 ++
C->CountersSectionStart;
120 if (
C->BitmapSectionStart)
121 ++
C->BitmapSectionStart;
133 std::string EffectiveFilename =
Filename.str();
138 "unsupported profile binary correlation when there is no build ID "
143 "unsupported profile binary correlation when there are multiple "
144 "build IDs in a profile");
155 EffectiveFilename = *Path;
159 auto DsymObjectsOrErr =
161 if (
auto Err = DsymObjectsOrErr.takeError())
162 return std::move(Err);
163 if (!DsymObjectsOrErr->empty()) {
166 if (DsymObjectsOrErr->size() > 1)
169 "using multiple objects is not yet supported");
170 EffectiveFilename = *DsymObjectsOrErr->begin();
174 if (
auto Err = BufferOrErr.takeError())
175 return std::move(Err);
177 return get(std::move(*BufferOrErr), FileKind);
182 if (
auto Err = BufferOrErr.takeError())
183 return std::move(Err);
185 return get(std::move(*BufferOrErr), FileKind);
189 "unsupported correlation kind (only DWARF debug info and Binary format "
190 "(ELF/COFF) are supported)");
195 ProfCorrelatorKind FileKind) {
197 if (
auto Err = BinOrErr.takeError())
198 return std::move(Err);
201 auto CtxOrErr =
Context::get(std::move(Buffer), *Obj, FileKind);
202 if (
auto Err = CtxOrErr.takeError())
203 return std::move(Err);
204 auto T = Obj->makeTriple();
218 return C->getDataSize();
220 return C->getDataSize();
228 std::unique_ptr<InstrProfCorrelator::Context>
Ctx)
233 std::unique_ptr<InstrProfCorrelator::Context>
Ctx)
247template <
class IntPtrT>
250 std::unique_ptr<InstrProfCorrelator::Context>
Ctx,
253 if (Obj.isELF() || Obj.isMachO()) {
255 return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(
256 std::move(DICtx), std::move(
Ctx));
260 "unsupported debug info format (only DWARF is supported)");
262 if (Obj.isELF() || Obj.isCOFF() || Obj.isMachO())
263 return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(
Ctx));
266 "unsupported binary format (only ELF, COFF, and Mach-O are supported)");
269template <
class IntPtrT>
273 if (this->
Data.empty())
276 "could not find any profile data metadata in correlated file");
278 this->CounterOffsets.clear();
279 this->BitmapOffsets.clear();
306 static const bool flow =
false;
309template <
class IntPtrT>
314 if (
Data.Probes.empty())
317 "could not find any profile data metadata in debug info");
323template <
class IntPtrT>
326 IntPtrT BitmapOffset, IntPtrT FunctionPtr,
uint32_t NumCounters,
329 if (NumCounters && !CounterOffsets.insert(CounterOffset).second)
352template <
class IntPtrT>
353std::optional<uint64_t>
354DwarfInstrProfCorrelator<IntPtrT>::getLocation(
const DWARFDie &Die)
const {
355 auto Locations = Die.
getLocations(dwarf::DW_AT_location);
362 for (
auto &Location : *Locations) {
365 for (
auto &
Op : Expr) {
366 if (
Op.getCode() == dwarf::DW_OP_addr)
367 return Op.getRawOperand(0);
368 if (
Op.getCode() == dwarf::DW_OP_addrx) {
370 if (
auto SA = DU.getAddrOffsetSectionItem(Index))
378template <
class IntPtrT>
379bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(
const DWARFDie &Die,
384 if (Die.
getTag() != dwarf::DW_TAG_variable)
386 if (!ParentDie.isSubprogramDIE())
395template <
class IntPtrT>
396std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>>
397DwarfInstrProfCorrelator<IntPtrT>::addCountersToDataProbe(
398 const DWARFDie &Die,
const bool UnlimitedWarnings,
399 int &NumSuppressedWarnings) {
400 std::optional<const char *> FunctionName;
401 std::optional<uint64_t> CFGHash;
402 std::optional<uint64_t> CounterPtr =
getLocation(Die);
405 std::optional<uint64_t> NumCounters;
407 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
409 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
410 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
411 if (!AnnotationFormName || !AnnotationFormValue)
413 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
414 if (
auto Err = AnnotationNameOrErr.takeError()) {
418 StringRef AnnotationName = *AnnotationNameOrErr;
420 if (
auto EC = AnnotationFormValue->getAsCString().moveInto(FunctionName))
423 CFGHash = AnnotationFormValue->getAsUnsignedConstant();
424 }
else if (AnnotationName ==
426 NumCounters = AnnotationFormValue->getAsUnsignedConstant();
430 if (!FunctionPtr && !CounterPtr)
432 if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
433 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
435 <<
": CFGHash=" << CFGHash
436 <<
" CounterPtr=" << CounterPtr
437 <<
" NumCounters=" << NumCounters <<
"\n";
443 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
444 if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
445 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
447 "CounterPtr out of range for function %s: Actual=0x%x "
448 "Expected=[0x%x, 0x%x)\n",
454 if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
464 P.FunctionName = *FunctionName;
466 P.LinkageName =
Name;
467 P.CFGHash = *CFGHash;
468 P.CounterOffset = CounterOffset;
469 P.NumCounters = *NumCounters;
470 auto FilePath = FnDie.getDeclFile(
472 if (!FilePath.empty())
473 P.FilePath = FilePath;
474 if (
auto LineNumber = FnDie.getDeclLine())
475 P.LineNumber = LineNumber;
477 return std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>>(
478 {
P, FunctionPtr.value_or(0)});
481template <
class IntPtrT>
482std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>>
483DwarfInstrProfCorrelator<IntPtrT>::addBitmapToDataProbe(
484 const DWARFDie &Die,
const bool UnlimitedWarnings,
485 int &NumSuppressedWarnings) {
486 std::optional<const char *> FunctionName;
487 std::optional<uint64_t> BitmapPtr =
getLocation(Die);
490 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
492 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
493 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
494 if (!AnnotationFormName || !AnnotationFormValue)
496 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
497 if (
auto Err = AnnotationNameOrErr.takeError()) {
501 StringRef AnnotationName = *AnnotationNameOrErr;
503 if (
auto EC = AnnotationFormValue->getAsCString().moveInto(FunctionName))
505 }
else if (AnnotationName ==
507 std::optional<uint64_t> NumBitmapBits =
508 AnnotationFormValue->getAsUnsignedConstant();
513 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
515 <<
" BitmapPtr=" << BitmapPtr
521 uint64_t BitmapStart = this->Ctx->BitmapSectionStart;
522 uint64_t BitmapEnd = this->Ctx->BitmapSectionEnd;
526 "could not find profile bitmap section in correlated file");
529 if (*BitmapPtr < BitmapStart || (*BitmapPtr >= BitmapEnd &&
NumBitmapBytes)) {
530 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
532 "BitmapPtr out of range for function %s: Actual=0x%x "
533 "Expected=[0x%x, 0x%x)\n",
534 *FunctionName, *BitmapPtr, BitmapStart, BitmapEnd);
541 IntPtrT BitmapOffset = *BitmapPtr - BitmapStart;
543 P.FunctionName = *FunctionName;
544 P.BitmapOffset = BitmapOffset;
547 return std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>>({
P, 0});
550template <
class IntPtrT>
551void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
558 bool UnlimitedWarnings = (MaxWarnings == 0);
560 int NumSuppressedWarnings = -MaxWarnings;
562 auto MaybeAddProbe = [&](
DWARFDie Die) {
563 std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>> ProbeData;
566 addCountersToDataProbe(Die, UnlimitedWarnings, NumSuppressedWarnings);
569 addBitmapToDataProbe(Die, UnlimitedWarnings, NumSuppressedWarnings);
572 auto [Probe, FunctionPtr] = *ProbeData;
575 Probes.
try_emplace(Probe.FunctionName, Probe, FunctionPtr);
577 auto &
P = It->second.first;
579 P.LinkageName = Probe.LinkageName;
580 P.CFGHash = Probe.CFGHash;
581 P.CounterOffset = Probe.CounterOffset;
582 P.NumCounters = Probe.NumCounters;
583 P.FilePath = Probe.FilePath;
584 P.LineNumber = Probe.LineNumber;
586 P.BitmapOffset = Probe.BitmapOffset;
587 P.NumBitmapBytes = Probe.NumBitmapBytes;
591 for (
auto &
CU : DICtx->normal_units())
592 for (
const auto &Entry :
CU->dies())
594 for (
auto &
CU : DICtx->dwo_units())
595 for (
const auto &Entry :
CU->dies())
598 for (
const auto &[FunctionName, ProbeData] : Probes) {
599 const auto &[Probe, FunctionPtr] = ProbeData;
601 Data->Probes.push_back(Probe);
603 this->NamesVec.push_back(FunctionName);
605 this->addDataProbe(NameRef, Probe.CFGHash, Probe.CounterOffset,
606 Probe.BitmapOffset, FunctionPtr, Probe.NumCounters,
607 Probe.NumBitmapBytes);
610 if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
612 NumSuppressedWarnings);
615template <
class IntPtrT>
616Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
617 if (this->NamesVec.empty()) {
620 "could not find any profile name metadata in debug info");
628template <
class IntPtrT>
629void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
632 bool UnlimitedWarnings = (MaxWarnings == 0);
634 int NumSuppressedWarnings = -MaxWarnings;
636 const RawProfData *
DataStart = (
const RawProfData *)this->Ctx->DataStart;
637 const RawProfData *DataEnd = (
const RawProfData *)this->Ctx->DataEnd;
639 for (
const RawProfData *
I =
DataStart;
I < DataEnd; ++
I) {
640 uint64_t CounterPtr = this->
template maybeSwap<IntPtrT>(
I->CounterPtr);
642 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
644 uint64_t BitmapPtr = this->
template maybeSwap<IntPtrT>(
I->BitmapPtr);
645 uint64_t BitmapStart = this->Ctx->BitmapSectionStart;
646 uint64_t BitmapEnd = this->Ctx->BitmapSectionEnd;
647 if (!BitmapStart && !BitmapEnd &&
I->NumBitmapBytes) {
650 "could not find profile bitmap section in correlated file");
653 if (!this->Ctx->MachOFixups.empty()) {
655 auto It = this->Ctx->MachOFixups.find(
Offset);
656 if (It != this->Ctx->MachOFixups.end()) {
658 }
else if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
660 "Mach-O fixup not found for covdata offset 0x%llx\n",
Offset);
665 GetPtrByOffset(CounterOffset, CounterPtr);
666 GetPtrByOffset(BitmapOffset, BitmapPtr);
668 if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) {
669 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
671 <<
format(
"CounterPtr out of range for function: Actual=0x%x "
672 "Expected=[0x%x, 0x%x) at data offset=0x%x\n",
677 if (
I->NumBitmapBytes &&
678 (BitmapPtr < BitmapStart || BitmapPtr >= BitmapEnd)) {
679 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
681 <<
format(
"BitmapPtr out of range for function: Actual=0x%x "
682 "Expected=[0x%x, 0x%x) at data offset=0x%x\n",
683 BitmapPtr, BitmapStart, BitmapEnd,
690 IntPtrT BitmapOffset = BitmapPtr - BitmapStart;
691 this->addDataProbe(
I->NameRef,
I->FuncHash, CounterOffset, BitmapOffset,
692 I->FunctionPointer,
I->NumCounters,
I->NumBitmapBytes);
696template <
class IntPtrT>
697Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
698 if (this->Ctx->NameSize == 0) {
701 "could not find any profile data metadata in object file");
703 this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static Expected< object::SectionRef > getInstrProfSection(const object::ObjectFile &Obj, InstrProfSectKind IPSK)
Get profile section.
static constexpr StringLiteral Filename
static MemoryLocation getLocation(Instruction *I)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
const T & front() const
Get the first element.
size_t size() const
Get the array size.
bool empty() const
Check if the array is empty.
static std::unique_ptr< DWARFContext > create(const object::ObjectFile &Obj, ProcessDebugRelocations RelocAction=ProcessDebugRelocations::Process, const LoadedObjectInfo *L=nullptr, std::string DWPName="", std::function< void(Error)> RecoverableErrorHandler=WithColor::defaultErrorHandler, std::function< void(Error)> WarningHandler=WithColor::defaultWarningHandler, bool ThreadSafe=false)
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
iterator_range< iterator > children() const
LLVM_ABI DWARFDie getParent() const
Get the parent of this DIE object.
DWARFUnit * getDwarfUnit() const
LLVM_ABI const char * getName(DINameKind Kind) const
Return the DIE name resolving DW_AT_specification or DW_AT_abstract_origin references if necessary.
dwarf::Tag getTag() const
LLVM_ABI Expected< DWARFLocationExpressionsVector > getLocations(dwarf::Attribute Attr) const
bool isNULL() const
Returns true for a valid DIE that terminates a sibling chain.
LLVM_ABI void dump(raw_ostream &OS, unsigned indent=0, DIDumpOptions DumpOpts=DIDumpOptions()) const
Dump the DIE and all of its attributes to the supplied stream.
uint8_t getAddressByteSize() const
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
InstrProfCorrelatorImpl - A child of InstrProfCorrelator with a template pointer type so that the Pro...
static llvm::Expected< std::unique_ptr< InstrProfCorrelatorImpl< IntPtrT > > > get(std::unique_ptr< InstrProfCorrelator::Context > Ctx, const object::ObjectFile &Obj, ProfCorrelatorKind FileKind)
virtual Error correlateProfileNameImpl()=0
virtual void correlateProfileDataImpl(int MaxWarnings, InstrProfCorrelator::CorrelationData *Data=nullptr)=0
std::vector< RawInstrProf::ProfileData< IntPtrT > > Data
Error correlateProfileData(int MaxWarnings) override
Construct a ProfileData vector used to correlate raw instrumentation data to their functions.
static bool classof(const InstrProfCorrelator *C)
InstrProfCorrelatorImpl(std::unique_ptr< InstrProfCorrelator::Context > Ctx)
void addDataProbe(uint64_t FunctionName, uint64_t CFGHash, IntPtrT CounterOffset, IntPtrT BitmapOffset, IntPtrT FunctionPtr, uint32_t NumCounters, uint32_t NumBitmapBytes)
T maybeSwap(T Value) const
Error dumpYaml(int MaxWarnings, raw_ostream &OS) override
Process debug info and dump the correlation data.
InstrProfCorrelator - A base class used to create raw instrumentation data to their functions.
static LLVM_ABI const char * FunctionNameAttributeName
static LLVM_ABI const char * CFGHashAttributeName
InstrProfCorrelator(InstrProfCorrelatorKind K, std::unique_ptr< Context > Ctx)
std::vector< std::string > NamesVec
static LLVM_ABI const char * NumCountersAttributeName
ProfCorrelatorKind
Indicate if we should use the debug info or profile metadata sections to correlate.
const std::unique_ptr< Context > Ctx
LLVM_ABI std::optional< size_t > getDataSize() const
Return the number of ProfileData elements.
static LLVM_ABI llvm::Expected< std::unique_ptr< InstrProfCorrelator > > get(StringRef Filename, ProfCorrelatorKind FileKind, const object::BuildIDFetcher *BIDFetcher=nullptr, const ArrayRef< llvm::object::BuildID > BIs={})
static LLVM_ABI const char * NumBitmapBitsAttributeName
This class implements a map that also provides access to all stored values in a deterministic order.
std::pair< iterator, bool > try_emplace(const KeyT &Key, Ts &&...Args)
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
static LLVM_ABI raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
BuildIDFetcher searches local cache directories for debug info.
virtual Expected< std::string > fetch(BuildIDRef BuildID) const
Returns the path to the debug file with the given build ID.
static Expected< std::vector< std::string > > findDsymObjectMembers(StringRef Path)
If the input path is a .dSYM bundle (as created by the dsymutil tool), return the paths to the object...
This class is the base class for all object file types.
This class implements an extremely fast bulk output stream that can only output to a stream.
void mapOptional(StringRef Key, T &Val)
void mapRequired(StringRef Key, T &Val)
The Output class is used to generate a yaml document from in-memory structs and vectors.
@ C
The default llvm calling convention, compatible with C.
uint64_t ComputeHash(StringRef K)
std::optional< uint64_t > toAddress(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an address.
LLVM_ABI Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)
Create a Binary from Source, autodetecting the file type.
constexpr bool IsLittleEndianHost
This is an optimization pass for GlobalISel generic memory operations.
RelativeUniformCounterPtr ValuesPtrExpr NumBitmapBytes
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
StringRef getInstrProfBitmapVarPrefix()
Return the name prefix of profile bitmap variables.
LLVM_ABI std::string getInstrProfSectionName(InstrProfSectKind IPSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
Return the name of the profile section corresponding to IPSK.
StringRef getInstrProfCountersVarPrefix()
Return the name prefix of profile counter variables.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr CountersStart
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
@ unable_to_correlate_profile
DWARFExpression::Operation Op
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
LLVM_ABI Error collectGlobalObjectNameStrings(ArrayRef< std::string > NameStrs, bool doCompression, std::string &Result)
Given a vector of strings (names of global objects like functions or, virtual tables) NameStrs,...
void toHex(ArrayRef< uint8_t > Input, bool LowerCase, SmallVectorImpl< char > &Output)
Convert buffer Input to its hexadecimal representation. The returned string is double the size of Inp...
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr DataStart
void consumeError(Error Err)
Consume a Error without doing anything.
Implement std::hash so that hash_code can be used in STL containers.
std::unique_ptr< MemoryBuffer > Buffer
static LLVM_ABI llvm::Expected< std::unique_ptr< Context > > get(std::unique_ptr< MemoryBuffer > Buffer, object::ObjectFile &Obj, ProfCorrelatorKind FileKind)
This class should be specialized by any type that needs to be converted to/from a YAML mapping.
This class should be specialized by any type for which vectors of that type need to be converted to/f...
static void mapping(yaml::IO &io, InstrProfCorrelator::CorrelationData &Data)
static void mapping(yaml::IO &io, InstrProfCorrelator::Probe &P)