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);
65 if (
auto Err = DataSection.takeError())
66 return std::move(Err);
67 auto DataOrErr = DataSection->getContents();
69 return DataOrErr.takeError();
71 if (
auto Err = NameSection.takeError())
72 return std::move(Err);
73 auto NameOrErr = NameSection->getContents();
75 return NameOrErr.takeError();
76 C->DataStart = DataOrErr->data();
77 C->DataEnd = DataOrErr->data() + DataOrErr->size();
78 C->NameStart = NameOrErr->data();
79 C->NameSize = NameOrErr->size();
82 C->CountersSectionStart = CountersSection->getAddress();
83 C->CountersSectionEnd =
C->CountersSectionStart + CountersSection->getSize();
87 ++
C->CountersSectionStart;
97 std::optional<std::string> Path;
102 "unsupported profile binary correlation when there is no build ID "
107 "unsupported profile binary correlation when there are multiple "
108 "build IDs in a profile");
120 auto DsymObjectsOrErr =
122 if (
auto Err = DsymObjectsOrErr.takeError())
123 return std::move(Err);
124 if (!DsymObjectsOrErr->empty()) {
127 if (DsymObjectsOrErr->size() > 1)
130 "using multiple objects is not yet supported");
131 Filename = *DsymObjectsOrErr->begin();
134 if (
auto Err = BufferOrErr.takeError())
135 return std::move(Err);
137 return get(std::move(*BufferOrErr), FileKind);
141 if (
auto Err = BufferOrErr.takeError())
142 return std::move(Err);
144 return get(std::move(*BufferOrErr), FileKind);
148 "unsupported correlation kind (only DWARF debug info and Binary format "
149 "(ELF/COFF) are supported)");
154 ProfCorrelatorKind FileKind) {
156 if (
auto Err = BinOrErr.takeError())
157 return std::move(Err);
160 auto CtxOrErr =
Context::get(std::move(Buffer), *Obj, FileKind);
161 if (
auto Err = CtxOrErr.takeError())
162 return std::move(Err);
163 auto T = Obj->makeTriple();
177 return C->getDataSize();
179 return C->getDataSize();
188 std::unique_ptr<InstrProfCorrelator::Context>
Ctx)
193 std::unique_ptr<InstrProfCorrelator::Context>
Ctx)
207template <
class IntPtrT>
210 std::unique_ptr<InstrProfCorrelator::Context>
Ctx,
215 return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(
216 std::move(DICtx), std::move(
Ctx));
220 "unsupported debug info format (only DWARF is supported)");
223 return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(
Ctx));
226 "unsupported binary format (only ELF and COFF are supported)");
229template <
class IntPtrT>
233 if (this->
Data.empty())
236 "could not find any profile data metadata in correlated file");
238 this->CounterOffsets.clear();
263 static const bool flow =
false;
266template <
class IntPtrT>
271 if (
Data.Probes.empty())
274 "could not find any profile data metadata in debug info");
280template <
class IntPtrT>
283 IntPtrT CounterOffset,
287 if (!CounterOffsets.insert(CounterOffset).second)
307template <
class IntPtrT>
308std::optional<uint64_t>
309DwarfInstrProfCorrelator<IntPtrT>::getLocation(
const DWARFDie &Die)
const {
310 auto Locations = Die.
getLocations(dwarf::DW_AT_location);
317 for (
auto &Location : *Locations) {
320 for (
auto &
Op : Expr) {
321 if (
Op.getCode() == dwarf::DW_OP_addr) {
322 return Op.getRawOperand(0);
323 }
else if (
Op.getCode() == dwarf::DW_OP_addrx) {
325 if (
auto SA = DU.getAddrOffsetSectionItem(Index))
333template <
class IntPtrT>
334bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(
const DWARFDie &Die) {
338 if (Die.
getTag() != dwarf::DW_TAG_variable)
340 if (!ParentDie.isSubprogramDIE())
349template <
class IntPtrT>
350void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
352 bool UnlimitedWarnings = (MaxWarnings == 0);
354 int NumSuppressedWarnings = -MaxWarnings;
355 auto maybeAddProbe = [&](
DWARFDie Die) {
356 if (!isDIEOfProbe(Die))
358 std::optional<const char *> FunctionName;
359 std::optional<uint64_t> CFGHash;
360 std::optional<uint64_t> CounterPtr =
getLocation(Die);
365 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
367 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
368 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
369 if (!AnnotationFormName || !AnnotationFormValue)
371 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
372 if (
auto Err = AnnotationNameOrErr.takeError()) {
376 StringRef AnnotationName = *AnnotationNameOrErr;
379 AnnotationFormValue->getAsCString().moveInto(FunctionName))
382 CFGHash = AnnotationFormValue->getAsUnsignedConstant();
383 }
else if (AnnotationName ==
385 NumCounters = AnnotationFormValue->getAsUnsignedConstant();
388 if (!FunctionName || !CFGHash || !CounterPtr || !
NumCounters) {
389 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
391 <<
"Incomplete DIE for function " << FunctionName
392 <<
": CFGHash=" << CFGHash <<
" CounterPtr=" << CounterPtr
398 uint64_t CountersStart = this->Ctx->CountersSectionStart;
399 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
400 if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
401 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
403 <<
format(
"CounterPtr out of range for function %s: Actual=0x%x "
404 "Expected=[0x%x, 0x%x)\n",
405 *FunctionName, *CounterPtr, CountersStart, CountersEnd);
410 if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
417 IntPtrT CounterOffset = *CounterPtr - CountersStart;
420 P.FunctionName = *FunctionName;
422 P.LinkageName =
Name;
423 P.CFGHash = *CFGHash;
424 P.CounterOffset = CounterOffset;
426 auto FilePath = FnDie.getDeclFile(
428 if (!FilePath.empty())
429 P.FilePath = FilePath;
430 if (
auto LineNumber = FnDie.getDeclLine())
431 P.LineNumber = LineNumber;
432 Data->Probes.push_back(
P);
435 CounterOffset, FunctionPtr.value_or(0), *
NumCounters);
436 this->NamesVec.push_back(*FunctionName);
439 for (
auto &
CU : DICtx->normal_units())
440 for (
const auto &Entry :
CU->dies())
442 for (
auto &
CU : DICtx->dwo_units())
443 for (
const auto &Entry :
CU->dies())
446 if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
448 NumSuppressedWarnings);
451template <
class IntPtrT>
452Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
453 if (this->NamesVec.empty()) {
456 "could not find any profile name metadata in debug info");
464template <
class IntPtrT>
465void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
468 bool UnlimitedWarnings = (MaxWarnings == 0);
470 int NumSuppressedWarnings = -MaxWarnings;
472 const RawProfData *DataStart = (
const RawProfData *)this->Ctx->DataStart;
473 const RawProfData *DataEnd = (
const RawProfData *)this->Ctx->DataEnd;
475 for (
const RawProfData *
I = DataStart;
I < DataEnd; ++
I) {
476 uint64_t CounterPtr = this->
template maybeSwap<IntPtrT>(
I->CounterPtr);
477 uint64_t CountersStart = this->Ctx->CountersSectionStart;
478 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
479 if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) {
480 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
482 <<
format(
"CounterPtr out of range for function: Actual=0x%x "
483 "Expected=[0x%x, 0x%x) at data offset=0x%x\n",
484 CounterPtr, CountersStart, CountersEnd,
485 (
I - DataStart) *
sizeof(RawProfData));
490 IntPtrT CounterOffset = CounterPtr - CountersStart;
491 this->addDataProbe(
I->NameRef,
I->FuncHash, CounterOffset,
492 I->FunctionPointer,
I->NumCounters);
496template <
class IntPtrT>
497Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
498 if (this->Ctx->NameSize == 0) {
501 "could not find any profile data metadata in object file");
503 this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expected< object::SectionRef > getInstrProfSection(const object::ObjectFile &Obj, InstrProfSectKind IPSK)
Get profile section.
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,...
StringRef - Represent a constant reference to a string, i.e.
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.
Triple::ObjectFormatType getTripleObjectFormat() const
bool isLittleEndian() const
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.
section_iterator_range sections() const
This class implements an extremely fast bulk output stream that can only output to a stream.
void mapOptional(const char *Key, T &Val)
void mapRequired(const char *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, const 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)