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) +
")");
59 auto C = std::make_unique<Context>();
61 if (
auto Err = CountersSection.takeError())
62 return std::move(Err);
66 if (
auto Err = DataSection.takeError())
67 return std::move(Err);
68 auto DataOrErr = DataSection->getContents();
70 return DataOrErr.takeError();
72 if (
auto Err = NameSection.takeError())
73 return std::move(Err);
74 auto NameOrErr = NameSection->getContents();
76 return NameOrErr.takeError();
77 C->DataStart = DataOrErr->data();
78 C->DataEnd = DataOrErr->data() + DataOrErr->size();
79 C->NameStart = NameOrErr->data();
80 C->NameSize = NameOrErr->size();
83 std::string FullSectionName =
90 MachO->fixupTable(Err)) {
91 if (Entry.isRebase() && Entry.segmentName() == SegmentAndSection[0] &&
92 Entry.sectionName() == SegmentAndSection[1]) {
93 C->MachOFixups[Entry.address() - DataSection->getAddress()] =
98 return std::move(Err);
102 C->CountersSectionStart = CountersSection->getAddress();
103 C->CountersSectionEnd =
C->CountersSectionStart + CountersSection->getSize();
107 ++
C->CountersSectionStart;
117 std::optional<std::string> Path;
122 "unsupported profile binary correlation when there is no build ID "
127 "unsupported profile binary correlation when there are multiple "
128 "build IDs in a profile");
140 auto DsymObjectsOrErr =
142 if (
auto Err = DsymObjectsOrErr.takeError())
143 return std::move(Err);
144 if (!DsymObjectsOrErr->empty()) {
147 if (DsymObjectsOrErr->size() > 1)
150 "using multiple objects is not yet supported");
151 Filename = *DsymObjectsOrErr->begin();
154 if (
auto Err = BufferOrErr.takeError())
155 return std::move(Err);
157 return get(std::move(*BufferOrErr), FileKind);
161 if (
auto Err = BufferOrErr.takeError())
162 return std::move(Err);
164 return get(std::move(*BufferOrErr), FileKind);
168 "unsupported correlation kind (only DWARF debug info and Binary format "
169 "(ELF/COFF) are supported)");
174 ProfCorrelatorKind FileKind) {
176 if (
auto Err = BinOrErr.takeError())
177 return std::move(Err);
180 auto CtxOrErr =
Context::get(std::move(Buffer), *Obj, FileKind);
181 if (
auto Err = CtxOrErr.takeError())
182 return std::move(Err);
183 auto T = Obj->makeTriple();
197 return C->getDataSize();
199 return C->getDataSize();
207 std::unique_ptr<InstrProfCorrelator::Context>
Ctx)
212 std::unique_ptr<InstrProfCorrelator::Context>
Ctx)
226template <
class IntPtrT>
229 std::unique_ptr<InstrProfCorrelator::Context>
Ctx,
232 if (Obj.isELF() || Obj.isMachO()) {
234 return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(
235 std::move(DICtx), std::move(
Ctx));
239 "unsupported debug info format (only DWARF is supported)");
241 if (Obj.isELF() || Obj.isCOFF() || Obj.isMachO())
242 return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(
Ctx));
245 "unsupported binary format (only ELF, COFF, and Mach-O are supported)");
248template <
class IntPtrT>
252 if (this->
Data.empty())
255 "could not find any profile data metadata in correlated file");
257 this->CounterOffsets.clear();
282 static const bool flow =
false;
285template <
class IntPtrT>
290 if (
Data.Probes.empty())
293 "could not find any profile data metadata in debug info");
299template <
class IntPtrT>
302 IntPtrT CounterOffset,
306 if (!CounterOffsets.insert(CounterOffset).second)
326template <
class IntPtrT>
327std::optional<uint64_t>
328DwarfInstrProfCorrelator<IntPtrT>::getLocation(
const DWARFDie &Die)
const {
329 auto Locations = Die.
getLocations(dwarf::DW_AT_location);
336 for (
auto &Location : *Locations) {
339 for (
auto &
Op : Expr) {
340 if (
Op.getCode() == dwarf::DW_OP_addr)
341 return Op.getRawOperand(0);
342 if (
Op.getCode() == dwarf::DW_OP_addrx) {
344 if (
auto SA = DU.getAddrOffsetSectionItem(Index))
352template <
class IntPtrT>
353bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(
const DWARFDie &Die) {
357 if (Die.
getTag() != dwarf::DW_TAG_variable)
359 if (!ParentDie.isSubprogramDIE())
368template <
class IntPtrT>
369void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
371 bool UnlimitedWarnings = (MaxWarnings == 0);
373 int NumSuppressedWarnings = -MaxWarnings;
374 auto MaybeAddProbe = [&](
DWARFDie Die) {
375 if (!isDIEOfProbe(Die))
377 std::optional<const char *> FunctionName;
378 std::optional<uint64_t> CFGHash;
379 std::optional<uint64_t> CounterPtr =
getLocation(Die);
384 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
386 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
387 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
388 if (!AnnotationFormName || !AnnotationFormValue)
390 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
391 if (
auto Err = AnnotationNameOrErr.takeError()) {
395 StringRef AnnotationName = *AnnotationNameOrErr;
398 AnnotationFormValue->getAsCString().moveInto(FunctionName))
401 CFGHash = AnnotationFormValue->getAsUnsignedConstant();
402 }
else if (AnnotationName ==
404 NumCounters = AnnotationFormValue->getAsUnsignedConstant();
408 if (!FunctionPtr && !CounterPtr)
410 if (!FunctionName || !CFGHash || !CounterPtr || !
NumCounters) {
411 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
413 <<
"Incomplete DIE for function " << FunctionName
414 <<
": CFGHash=" << CFGHash <<
" CounterPtr=" << CounterPtr
420 uint64_t CountersStart = this->Ctx->CountersSectionStart;
421 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
422 if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
423 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
425 <<
format(
"CounterPtr out of range for function %s: Actual=0x%x "
426 "Expected=[0x%x, 0x%x)\n",
427 *FunctionName, *CounterPtr, CountersStart, CountersEnd);
432 if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
439 IntPtrT CounterOffset = *CounterPtr - CountersStart;
442 P.FunctionName = *FunctionName;
444 P.LinkageName =
Name;
445 P.CFGHash = *CFGHash;
446 P.CounterOffset = CounterOffset;
448 auto FilePath = FnDie.getDeclFile(
450 if (!FilePath.empty())
451 P.FilePath = FilePath;
452 if (
auto LineNumber = FnDie.getDeclLine())
453 P.LineNumber = LineNumber;
454 Data->Probes.push_back(
P);
457 CounterOffset, FunctionPtr.value_or(0), *
NumCounters);
458 this->NamesVec.push_back(*FunctionName);
461 for (
auto &
CU : DICtx->normal_units())
462 for (
const auto &Entry :
CU->dies())
464 for (
auto &
CU : DICtx->dwo_units())
465 for (
const auto &Entry :
CU->dies())
468 if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
470 NumSuppressedWarnings);
473template <
class IntPtrT>
474Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
475 if (this->NamesVec.empty()) {
478 "could not find any profile name metadata in debug info");
486template <
class IntPtrT>
487void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
490 bool UnlimitedWarnings = (MaxWarnings == 0);
492 int NumSuppressedWarnings = -MaxWarnings;
494 const RawProfData *DataStart = (
const RawProfData *)this->Ctx->DataStart;
495 const RawProfData *DataEnd = (
const RawProfData *)this->Ctx->DataEnd;
497 for (
const RawProfData *
I = DataStart;
I < DataEnd; ++
I) {
498 uint64_t CounterPtr = this->
template maybeSwap<IntPtrT>(
I->CounterPtr);
499 uint64_t CountersStart = this->Ctx->CountersSectionStart;
500 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
501 if (!this->Ctx->MachOFixups.empty()) {
503 auto It = this->Ctx->MachOFixups.find(
Offset);
504 if (It != this->Ctx->MachOFixups.end()) {
505 CounterPtr = It->second;
506 }
else if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
508 "Mach-O fixup not found for covdata offset 0x%llx\n",
Offset);
511 if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) {
512 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
514 <<
format(
"CounterPtr out of range for function: Actual=0x%x "
515 "Expected=[0x%x, 0x%x) at data offset=0x%x\n",
516 CounterPtr, CountersStart, CountersEnd,
517 (
I - DataStart) *
sizeof(RawProfData));
522 IntPtrT CounterOffset = CounterPtr - CountersStart;
523 this->addDataProbe(
I->NameRef,
I->FuncHash, CounterOffset,
524 I->FunctionPointer,
I->NumCounters);
528template <
class IntPtrT>
529Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
530 if (this->Ctx->NameSize == 0) {
533 "could not find any profile data metadata in object file");
535 this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static Expected< object::SectionRef > getInstrProfSection(const object::ObjectFile &Obj, InstrProfSectKind IPSK)
Get profile section.
static constexpr StringLiteral Filename
static MemoryLocation getLocation(Instruction *I)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
const T & front() const
front - Get the first element.
size_t size() const
size - Get the array size.
bool empty() const
empty - 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 FunctionPtr, uint32_t NumCounters)
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 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.
StringRef - 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 std::optional< 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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
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.
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.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
@ 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.
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)