1//===-- InstrProfCorrelator.cpp -------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/ProfileData/InstrProfCorrelator.h"
10#include "llvm/DebugInfo/DIContext.h"
11#include "llvm/DebugInfo/DWARF/DWARFContext.h"
12#include "llvm/DebugInfo/DWARF/DWARFDie.h"
13#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
14#include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h"
15#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
16#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"
17#include "llvm/Object/MachO.h"
18#include "llvm/Support/Debug.h"
19#include "llvm/Support/Format.h"
20#include "llvm/Support/WithColor.h"
21#include <optional>
22
23#define DEBUG_TYPE "correlator"
24
25using namespace llvm;
26
27/// Get profile section.
28static Expected<object::SectionRef>
29getInstrProfSection(const object::ObjectFile &Obj, InstrProfSectKind IPSK) {
30 // On COFF, the getInstrProfSectionName returns the section names may followed
31 // by "$M". The linker removes the dollar and everything after it in the final
32 // binary. Do the same to match.
33 Triple::ObjectFormatType ObjFormat = Obj.getTripleObjectFormat();
34 auto StripSuffix = [ObjFormat](StringRef N) {
35 return ObjFormat == Triple::COFF ? N.split(Separator: '$').first : N;
36 };
37 std::string ExpectedSectionName =
38 getInstrProfSectionName(IPSK, OF: ObjFormat,
39 /*AddSegmentInfo=*/false);
40 ExpectedSectionName = StripSuffix(ExpectedSectionName);
41 for (auto &Section : Obj.sections()) {
42 if (auto SectionName = Section.getName())
43 if (*SectionName == ExpectedSectionName)
44 return Section;
45 }
46 return make_error<InstrProfError>(
47 Args: instrprof_error::unable_to_correlate_profile,
48 Args: "could not find section (" + Twine(ExpectedSectionName) + ")");
49}
50
51const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name";
52const char *InstrProfCorrelator::CFGHashAttributeName = "CFG Hash";
53const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters";
54
55llvm::Expected<std::unique_ptr<InstrProfCorrelator::Context>>
56InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer,
57 object::ObjectFile &Obj,
58 ProfCorrelatorKind FileKind) {
59 auto C = std::make_unique<Context>();
60 auto CountersSection = getInstrProfSection(Obj, IPSK: IPSK_cnts);
61 if (auto Err = CountersSection.takeError())
62 return std::move(Err);
63 Triple::ObjectFormatType ObjFormat = Obj.getTripleObjectFormat();
64 if (FileKind == InstrProfCorrelator::BINARY) {
65 auto DataSection = getInstrProfSection(Obj, IPSK: IPSK_covdata);
66 if (auto Err = DataSection.takeError())
67 return std::move(Err);
68 auto DataOrErr = DataSection->getContents();
69 if (!DataOrErr)
70 return DataOrErr.takeError();
71 auto NameSection = getInstrProfSection(Obj, IPSK: IPSK_covname);
72 if (auto Err = NameSection.takeError())
73 return std::move(Err);
74 auto NameOrErr = NameSection->getContents();
75 if (!NameOrErr)
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();
81
82 if (ObjFormat == Triple::MachO) {
83 std::string FullSectionName =
84 getInstrProfSectionName(IPSK: IPSK_covdata, OF: ObjFormat);
85 SmallVector<StringRef, 3> SegmentAndSection;
86 StringRef(FullSectionName).split(A&: SegmentAndSection, Separator: ',', MaxSplit: 2);
87 auto *MachO = static_cast<object::MachOObjectFile *>(&Obj);
88 Error Err = Error::success();
89 for (const object::MachOChainedFixupEntry &Entry :
90 MachO->fixupTable(Err)) {
91 if (Entry.isRebase() && Entry.segmentName() == SegmentAndSection[0] &&
92 Entry.sectionName() == SegmentAndSection[1]) {
93 C->MachOFixups[Entry.address() - DataSection->getAddress()] =
94 Entry.pointerValue();
95 }
96 }
97 if (Err)
98 return std::move(Err);
99 }
100 }
101 C->Buffer = std::move(Buffer);
102 C->CountersSectionStart = CountersSection->getAddress();
103 C->CountersSectionEnd = C->CountersSectionStart + CountersSection->getSize();
104 // In COFF object file, there's a null byte at the beginning of the counter
105 // section which doesn't exist in raw profile.
106 if (ObjFormat == Triple::COFF)
107 ++C->CountersSectionStart;
108
109 C->ShouldSwapBytes = Obj.isLittleEndian() != sys::IsLittleEndianHost;
110 return Expected<std::unique_ptr<Context>>(std::move(C));
111}
112
113llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
114InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind,
115 const object::BuildIDFetcher *BIDFetcher,
116 const ArrayRef<object::BuildID> BIs) {
117 std::optional<std::string> Path;
118 if (BIDFetcher) {
119 if (BIs.empty())
120 return make_error<InstrProfError>(
121 Args: instrprof_error::unable_to_correlate_profile,
122 Args: "unsupported profile binary correlation when there is no build ID "
123 "in a profile");
124 if (BIs.size() > 1)
125 return make_error<InstrProfError>(
126 Args: instrprof_error::unable_to_correlate_profile,
127 Args: "unsupported profile binary correlation when there are multiple "
128 "build IDs in a profile");
129
130 Path = BIDFetcher->fetch(BuildID: BIs.front());
131 if (!Path)
132 return make_error<InstrProfError>(
133 Args: instrprof_error::unable_to_correlate_profile,
134 Args: "Missing build ID: " + llvm::toHex(Input: BIs.front(),
135 /*LowerCase=*/true));
136 Filename = *Path;
137 }
138
139 if (FileKind == DEBUG_INFO) {
140 auto DsymObjectsOrErr =
141 object::MachOObjectFile::findDsymObjectMembers(Path: Filename);
142 if (auto Err = DsymObjectsOrErr.takeError())
143 return std::move(Err);
144 if (!DsymObjectsOrErr->empty()) {
145 // TODO: Enable profile correlation when there are multiple objects in a
146 // dSYM bundle.
147 if (DsymObjectsOrErr->size() > 1)
148 return make_error<InstrProfError>(
149 Args: instrprof_error::unable_to_correlate_profile,
150 Args: "using multiple objects is not yet supported");
151 Filename = *DsymObjectsOrErr->begin();
152 }
153 auto BufferOrErr = errorOrToExpected(EO: MemoryBuffer::getFile(Filename));
154 if (auto Err = BufferOrErr.takeError())
155 return std::move(Err);
156
157 return get(Buffer: std::move(*BufferOrErr), FileKind);
158 }
159 if (FileKind == BINARY) {
160 auto BufferOrErr = errorOrToExpected(EO: MemoryBuffer::getFile(Filename));
161 if (auto Err = BufferOrErr.takeError())
162 return std::move(Err);
163
164 return get(Buffer: std::move(*BufferOrErr), FileKind);
165 }
166 return make_error<InstrProfError>(
167 Args: instrprof_error::unable_to_correlate_profile,
168 Args: "unsupported correlation kind (only DWARF debug info and Binary format "
169 "(ELF/COFF) are supported)");
170}
171
172llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
173InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer,
174 ProfCorrelatorKind FileKind) {
175 auto BinOrErr = object::createBinary(Source: *Buffer);
176 if (auto Err = BinOrErr.takeError())
177 return std::move(Err);
178
179 if (auto *Obj = dyn_cast<object::ObjectFile>(Val: BinOrErr->get())) {
180 auto CtxOrErr = Context::get(Buffer: std::move(Buffer), Obj&: *Obj, FileKind);
181 if (auto Err = CtxOrErr.takeError())
182 return std::move(Err);
183 auto T = Obj->makeTriple();
184 if (T.isArch64Bit())
185 return InstrProfCorrelatorImpl<uint64_t>::get(Ctx: std::move(*CtxOrErr), Obj: *Obj,
186 FileKind);
187 if (T.isArch32Bit())
188 return InstrProfCorrelatorImpl<uint32_t>::get(Ctx: std::move(*CtxOrErr), Obj: *Obj,
189 FileKind);
190 }
191 return make_error<InstrProfError>(
192 Args: instrprof_error::unable_to_correlate_profile, Args: "not an object file");
193}
194
195std::optional<size_t> InstrProfCorrelator::getDataSize() const {
196 if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint32_t>>(Val: this))
197 return C->getDataSize();
198 if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint64_t>>(Val: this))
199 return C->getDataSize();
200 return {};
201}
202
203namespace llvm {
204
205template <>
206InstrProfCorrelatorImpl<uint32_t>::InstrProfCorrelatorImpl(
207 std::unique_ptr<InstrProfCorrelator::Context> Ctx)
208 : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_32Bit,
209 std::move(Ctx)) {}
210template <>
211InstrProfCorrelatorImpl<uint64_t>::InstrProfCorrelatorImpl(
212 std::unique_ptr<InstrProfCorrelator::Context> Ctx)
213 : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_64Bit,
214 std::move(Ctx)) {}
215template <>
216bool InstrProfCorrelatorImpl<uint32_t>::classof(const InstrProfCorrelator *C) {
217 return C->getKind() == InstrProfCorrelatorKind::CK_32Bit;
218}
219template <>
220bool InstrProfCorrelatorImpl<uint64_t>::classof(const InstrProfCorrelator *C) {
221 return C->getKind() == InstrProfCorrelatorKind::CK_64Bit;
222}
223
224} // end namespace llvm
225
226template <class IntPtrT>
227llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>>
228InstrProfCorrelatorImpl<IntPtrT>::get(
229 std::unique_ptr<InstrProfCorrelator::Context> Ctx,
230 const object::ObjectFile &Obj, ProfCorrelatorKind FileKind) {
231 if (FileKind == DEBUG_INFO) {
232 if (Obj.isELF() || Obj.isMachO()) {
233 auto DICtx = DWARFContext::create(Obj);
234 return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(
235 std::move(DICtx), std::move(Ctx));
236 }
237 return make_error<InstrProfError>(
238 Args: instrprof_error::unable_to_correlate_profile,
239 Args: "unsupported debug info format (only DWARF is supported)");
240 }
241 if (Obj.isELF() || Obj.isCOFF() || Obj.isMachO())
242 return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx));
243 return make_error<InstrProfError>(
244 Args: instrprof_error::unable_to_correlate_profile,
245 Args: "unsupported binary format (only ELF, COFF, and Mach-O are supported)");
246}
247
248template <class IntPtrT>
249Error InstrProfCorrelatorImpl<IntPtrT>::correlateProfileData(int MaxWarnings) {
250 assert(Data.empty() && Names.empty() && NamesVec.empty());
251 correlateProfileDataImpl(MaxWarnings);
252 if (this->Data.empty())
253 return make_error<InstrProfError>(
254 Args: instrprof_error::unable_to_correlate_profile,
255 Args: "could not find any profile data metadata in correlated file");
256 Error Result = correlateProfileNameImpl();
257 this->CounterOffsets.clear();
258 this->NamesVec.clear();
259 return Result;
260}
261
262template <> struct yaml::MappingTraits<InstrProfCorrelator::CorrelationData> {
263 static void mapping(yaml::IO &io,
264 InstrProfCorrelator::CorrelationData &Data) {
265 io.mapRequired(Key: "Probes", Val&: Data.Probes);
266 }
267};
268
269template <> struct yaml::MappingTraits<InstrProfCorrelator::Probe> {
270 static void mapping(yaml::IO &io, InstrProfCorrelator::Probe &P) {
271 io.mapRequired(Key: "Function Name", Val&: P.FunctionName);
272 io.mapOptional(Key: "Linkage Name", Val&: P.LinkageName);
273 io.mapRequired(Key: "CFG Hash", Val&: P.CFGHash);
274 io.mapRequired(Key: "Counter Offset", Val&: P.CounterOffset);
275 io.mapRequired(Key: "Num Counters", Val&: P.NumCounters);
276 io.mapOptional(Key: "File", Val&: P.FilePath);
277 io.mapOptional(Key: "Line", Val&: P.LineNumber);
278 }
279};
280
281template <> struct yaml::SequenceElementTraits<InstrProfCorrelator::Probe> {
282 static const bool flow = false;
283};
284
285template <class IntPtrT>
286Error InstrProfCorrelatorImpl<IntPtrT>::dumpYaml(int MaxWarnings,
287 raw_ostream &OS) {
288 InstrProfCorrelator::CorrelationData Data;
289 correlateProfileDataImpl(MaxWarnings, Data: &Data);
290 if (Data.Probes.empty())
291 return make_error<InstrProfError>(
292 Args: instrprof_error::unable_to_correlate_profile,
293 Args: "could not find any profile data metadata in debug info");
294 yaml::Output YamlOS(OS);
295 YamlOS << Data;
296 return Error::success();
297}
298
299template <class IntPtrT>
300void InstrProfCorrelatorImpl<IntPtrT>::addDataProbe(uint64_t NameRef,
301 uint64_t CFGHash,
302 IntPtrT CounterOffset,
303 IntPtrT FunctionPtr,
304 uint32_t NumCounters) {
305 // Check if a probe was already added for this counter offset.
306 if (!CounterOffsets.insert(CounterOffset).second)
307 return;
308 Data.push_back({
309 maybeSwap<uint64_t>(NameRef),
310 maybeSwap<uint64_t>(CFGHash),
311 // In this mode, CounterPtr actually stores the section relative address
312 // of the counter.
313 maybeSwap<IntPtrT>(CounterOffset),
314 // TODO: MC/DC is not yet supported.
315 /*BitmapOffset=*/maybeSwap<IntPtrT>(0),
316 maybeSwap<IntPtrT>(FunctionPtr),
317 // TODO: Value profiling is not yet supported.
318 /*ValuesPtr=*/maybeSwap<IntPtrT>(0),
319 maybeSwap<uint32_t>(NumCounters),
320 /*NumValueSites=*/{maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)},
321 // TODO: MC/DC is not yet supported.
322 /*NumBitmapBytes=*/maybeSwap<uint32_t>(0),
323 });
324}
325
326template <class IntPtrT>
327std::optional<uint64_t>
328DwarfInstrProfCorrelator<IntPtrT>::getLocation(const DWARFDie &Die) const {
329 auto Locations = Die.getLocations(Attr: dwarf::DW_AT_location);
330 if (!Locations) {
331 consumeError(Err: Locations.takeError());
332 return {};
333 }
334 auto &DU = *Die.getDwarfUnit();
335 auto AddressSize = DU.getAddressByteSize();
336 for (auto &Location : *Locations) {
337 DataExtractor Data(Location.Expr, DICtx->isLittleEndian(), AddressSize);
338 DWARFExpression Expr(Data, AddressSize);
339 for (auto &Op : Expr) {
340 if (Op.getCode() == dwarf::DW_OP_addr)
341 return Op.getRawOperand(Idx: 0);
342 if (Op.getCode() == dwarf::DW_OP_addrx) {
343 uint64_t Index = Op.getRawOperand(Idx: 0);
344 if (auto SA = DU.getAddrOffsetSectionItem(Index))
345 return SA->Address;
346 }
347 }
348 }
349 return {};
350}
351
352template <class IntPtrT>
353bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(const DWARFDie &Die) {
354 const auto &ParentDie = Die.getParent();
355 if (!Die.isValid() || !ParentDie.isValid() || Die.isNULL())
356 return false;
357 if (Die.getTag() != dwarf::DW_TAG_variable)
358 return false;
359 if (!ParentDie.isSubprogramDIE())
360 return false;
361 if (!Die.hasChildren())
362 return false;
363 if (const char *Name = Die.getName(Kind: DINameKind::ShortName))
364 return StringRef(Name).starts_with(Prefix: getInstrProfCountersVarPrefix());
365 return false;
366}
367
368template <class IntPtrT>
369void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
370 int MaxWarnings, InstrProfCorrelator::CorrelationData *Data) {
371 bool UnlimitedWarnings = (MaxWarnings == 0);
372 // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
373 int NumSuppressedWarnings = -MaxWarnings;
374 auto MaybeAddProbe = [&](DWARFDie Die) {
375 if (!isDIEOfProbe(Die))
376 return;
377 std::optional<const char *> FunctionName;
378 std::optional<uint64_t> CFGHash;
379 std::optional<uint64_t> CounterPtr = getLocation(Die);
380 auto FnDie = Die.getParent();
381 auto FunctionPtr = dwarf::toAddress(V: FnDie.find(Attr: dwarf::DW_AT_low_pc));
382 std::optional<uint64_t> NumCounters;
383 for (const DWARFDie &Child : Die.children()) {
384 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
385 continue;
386 auto AnnotationFormName = Child.find(Attr: dwarf::DW_AT_name);
387 auto AnnotationFormValue = Child.find(Attr: dwarf::DW_AT_const_value);
388 if (!AnnotationFormName || !AnnotationFormValue)
389 continue;
390 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
391 if (auto Err = AnnotationNameOrErr.takeError()) {
392 consumeError(Err: std::move(Err));
393 continue;
394 }
395 StringRef AnnotationName = *AnnotationNameOrErr;
396 if (AnnotationName == InstrProfCorrelator::FunctionNameAttributeName) {
397 if (auto EC =
398 AnnotationFormValue->getAsCString().moveInto(Value&: FunctionName))
399 consumeError(Err: std::move(EC));
400 } else if (AnnotationName == InstrProfCorrelator::CFGHashAttributeName) {
401 CFGHash = AnnotationFormValue->getAsUnsignedConstant();
402 } else if (AnnotationName ==
403 InstrProfCorrelator::NumCountersAttributeName) {
404 NumCounters = AnnotationFormValue->getAsUnsignedConstant();
405 }
406 }
407 // If there is no function and no counter, assume it was dead-stripped
408 if (!FunctionPtr && !CounterPtr)
409 return;
410 if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
411 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
412 WithColor::warning()
413 << "Incomplete DIE for function " << FunctionName
414 << ": CFGHash=" << CFGHash << " CounterPtr=" << CounterPtr
415 << " NumCounters=" << NumCounters << "\n";
416 LLVM_DEBUG(Die.dump(dbgs()));
417 }
418 return;
419 }
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) {
424 WithColor::warning()
425 << format(Fmt: "CounterPtr out of range for function %s: Actual=0x%x "
426 "Expected=[0x%x, 0x%x)\n",
427 Vals: *FunctionName, Vals: *CounterPtr, Vals: CountersStart, Vals: CountersEnd);
428 LLVM_DEBUG(Die.dump(dbgs()));
429 }
430 return;
431 }
432 if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
433 WithColor::warning() << format(Fmt: "Could not find address of function %s\n",
434 Vals: *FunctionName);
435 LLVM_DEBUG(Die.dump(dbgs()));
436 }
437 // In debug info correlation mode, the CounterPtr is an absolute address of
438 // the counter, but it's expected to be relative later when iterating Data.
439 IntPtrT CounterOffset = *CounterPtr - CountersStart;
440 if (Data) {
441 InstrProfCorrelator::Probe P;
442 P.FunctionName = *FunctionName;
443 if (const char *Name = FnDie.getName(Kind: DINameKind::LinkageName))
444 P.LinkageName = Name;
445 P.CFGHash = *CFGHash;
446 P.CounterOffset = CounterOffset;
447 P.NumCounters = *NumCounters;
448 auto FilePath = FnDie.getDeclFile(
449 Kind: DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath);
450 if (!FilePath.empty())
451 P.FilePath = FilePath;
452 if (auto LineNumber = FnDie.getDeclLine())
453 P.LineNumber = LineNumber;
454 Data->Probes.push_back(x: P);
455 } else {
456 this->addDataProbe(IndexedInstrProf::ComputeHash(K: *FunctionName), *CFGHash,
457 CounterOffset, FunctionPtr.value_or(u: 0), *NumCounters);
458 this->NamesVec.push_back(*FunctionName);
459 }
460 };
461 for (auto &CU : DICtx->normal_units())
462 for (const auto &Entry : CU->dies())
463 MaybeAddProbe(DWARFDie(CU.get(), &Entry));
464 for (auto &CU : DICtx->dwo_units())
465 for (const auto &Entry : CU->dies())
466 MaybeAddProbe(DWARFDie(CU.get(), &Entry));
467
468 if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
469 WithColor::warning() << format(Fmt: "Suppressed %d additional warnings\n",
470 Vals: NumSuppressedWarnings);
471}
472
473template <class IntPtrT>
474Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
475 if (this->NamesVec.empty()) {
476 return make_error<InstrProfError>(
477 Args: instrprof_error::unable_to_correlate_profile,
478 Args: "could not find any profile name metadata in debug info");
479 }
480 auto Result =
481 collectGlobalObjectNameStrings(this->NamesVec,
482 /*doCompression=*/false, this->Names);
483 return Result;
484}
485
486template <class IntPtrT>
487void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
488 int MaxWarnings, InstrProfCorrelator::CorrelationData *CorrelateData) {
489 using RawProfData = RawInstrProf::ProfileData<IntPtrT>;
490 bool UnlimitedWarnings = (MaxWarnings == 0);
491 // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
492 int NumSuppressedWarnings = -MaxWarnings;
493
494 const RawProfData *DataStart = (const RawProfData *)this->Ctx->DataStart;
495 const RawProfData *DataEnd = (const RawProfData *)this->Ctx->DataEnd;
496 // We need to use < here because the last data record may have no padding.
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()) {
502 uint64_t Offset = (uint64_t)&I->CounterPtr - (uint64_t)DataStart;
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) {
507 WithColor::warning() << format(
508 Fmt: "Mach-O fixup not found for covdata offset 0x%llx\n", Vals: Offset);
509 }
510 }
511 if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) {
512 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
513 WithColor::warning()
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));
518 }
519 }
520 // In binary correlation mode, the CounterPtr is an absolute address of the
521 // counter, but it's expected to be relative later when iterating Data.
522 IntPtrT CounterOffset = CounterPtr - CountersStart;
523 this->addDataProbe(I->NameRef, I->FuncHash, CounterOffset,
524 I->FunctionPointer, I->NumCounters);
525 }
526}
527
528template <class IntPtrT>
529Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
530 if (this->Ctx->NameSize == 0) {
531 return make_error<InstrProfError>(
532 Args: instrprof_error::unable_to_correlate_profile,
533 Args: "could not find any profile data metadata in object file");
534 }
535 this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize);
536 return Error::success();
537}
538