Bug Summary

File:build/source/llvm/lib/ProfileData/SampleProfReader.cpp
Warning:line 388, column 21
The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name SampleProfReader.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm -resource-dir /usr/lib/llvm-17/lib/clang/17 -I lib/ProfileData -I /build/source/llvm/lib/ProfileData -I include -I /build/source/llvm/include -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm=build-llvm -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm=build-llvm -fcoverage-prefix-map=/build/source/= -source-date-epoch 1675721604 -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm -fdebug-prefix-map=/build/source/build-llvm=build-llvm -fdebug-prefix-map=/build/source/= -fdebug-prefix-map=/build/source/build-llvm=build-llvm -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-02-07-030702-17298-1 -x c++ /build/source/llvm/lib/ProfileData/SampleProfReader.cpp
1//===- SampleProfReader.cpp - Read LLVM sample profile data ---------------===//
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// This file implements the class that reads LLVM sample profiles. It
10// supports three file formats: text, binary and gcov.
11//
12// The textual representation is useful for debugging and testing purposes. The
13// binary representation is more compact, resulting in smaller file sizes.
14//
15// The gcov encoding is the one generated by GCC's AutoFDO profile creation
16// tool (https://github.com/google/autofdo)
17//
18// All three encodings can be used interchangeably as an input sample profile.
19//
20//===----------------------------------------------------------------------===//
21
22#include "llvm/ProfileData/SampleProfReader.h"
23#include "llvm/ADT/DenseMap.h"
24#include "llvm/ADT/STLExtras.h"
25#include "llvm/ADT/StringRef.h"
26#include "llvm/IR/Module.h"
27#include "llvm/IR/ProfileSummary.h"
28#include "llvm/ProfileData/ProfileCommon.h"
29#include "llvm/ProfileData/SampleProf.h"
30#include "llvm/Support/CommandLine.h"
31#include "llvm/Support/Compression.h"
32#include "llvm/Support/ErrorOr.h"
33#include "llvm/Support/JSON.h"
34#include "llvm/Support/LEB128.h"
35#include "llvm/Support/LineIterator.h"
36#include "llvm/Support/MD5.h"
37#include "llvm/Support/MemoryBuffer.h"
38#include "llvm/Support/VirtualFileSystem.h"
39#include "llvm/Support/raw_ostream.h"
40#include <algorithm>
41#include <cstddef>
42#include <cstdint>
43#include <limits>
44#include <memory>
45#include <system_error>
46#include <vector>
47
48using namespace llvm;
49using namespace sampleprof;
50
51#define DEBUG_TYPE"samplepgo-reader" "samplepgo-reader"
52
53// This internal option specifies if the profile uses FS discriminators.
54// It only applies to text, binary and compact binary format profiles.
55// For ext-binary format profiles, the flag is set in the summary.
56static cl::opt<bool> ProfileIsFSDisciminator(
57 "profile-isfs", cl::Hidden, cl::init(false),
58 cl::desc("Profile uses flow sensitive discriminators"));
59
60/// Dump the function profile for \p FName.
61///
62/// \param FContext Name + context of the function to print.
63/// \param OS Stream to emit the output to.
64void SampleProfileReader::dumpFunctionProfile(SampleContext FContext,
65 raw_ostream &OS) {
66 OS << "Function: " << FContext.toString() << ": " << Profiles[FContext];
67}
68
69/// Dump all the function profiles found on stream \p OS.
70void SampleProfileReader::dump(raw_ostream &OS) {
71 std::vector<NameFunctionSamples> V;
72 sortFuncProfiles(Profiles, V);
73 for (const auto &I : V)
74 dumpFunctionProfile(I.first, OS);
75}
76
77static void dumpFunctionProfileJson(const FunctionSamples &S,
78 json::OStream &JOS, bool TopLevel = false) {
79 auto DumpBody = [&](const BodySampleMap &BodySamples) {
80 for (const auto &I : BodySamples) {
81 const LineLocation &Loc = I.first;
82 const SampleRecord &Sample = I.second;
83 JOS.object([&] {
84 JOS.attribute("line", Loc.LineOffset);
85 if (Loc.Discriminator)
86 JOS.attribute("discriminator", Loc.Discriminator);
87 JOS.attribute("samples", Sample.getSamples());
88
89 auto CallTargets = Sample.getSortedCallTargets();
90 if (!CallTargets.empty()) {
91 JOS.attributeArray("calls", [&] {
92 for (const auto &J : CallTargets) {
93 JOS.object([&] {
94 JOS.attribute("function", J.first);
95 JOS.attribute("samples", J.second);
96 });
97 }
98 });
99 }
100 });
101 }
102 };
103
104 auto DumpCallsiteSamples = [&](const CallsiteSampleMap &CallsiteSamples) {
105 for (const auto &I : CallsiteSamples)
106 for (const auto &FS : I.second) {
107 const LineLocation &Loc = I.first;
108 const FunctionSamples &CalleeSamples = FS.second;
109 JOS.object([&] {
110 JOS.attribute("line", Loc.LineOffset);
111 if (Loc.Discriminator)
112 JOS.attribute("discriminator", Loc.Discriminator);
113 JOS.attributeArray(
114 "samples", [&] { dumpFunctionProfileJson(CalleeSamples, JOS); });
115 });
116 }
117 };
118
119 JOS.object([&] {
120 JOS.attribute("name", S.getName());
121 JOS.attribute("total", S.getTotalSamples());
122 if (TopLevel)
123 JOS.attribute("head", S.getHeadSamples());
124
125 const auto &BodySamples = S.getBodySamples();
126 if (!BodySamples.empty())
127 JOS.attributeArray("body", [&] { DumpBody(BodySamples); });
128
129 const auto &CallsiteSamples = S.getCallsiteSamples();
130 if (!CallsiteSamples.empty())
131 JOS.attributeArray("callsites",
132 [&] { DumpCallsiteSamples(CallsiteSamples); });
133 });
134}
135
136/// Dump all the function profiles found on stream \p OS in the JSON format.
137void SampleProfileReader::dumpJson(raw_ostream &OS) {
138 std::vector<NameFunctionSamples> V;
139 sortFuncProfiles(Profiles, V);
140 json::OStream JOS(OS, 2);
141 JOS.arrayBegin();
142 for (const auto &F : V)
143 dumpFunctionProfileJson(*F.second, JOS, true);
144 JOS.arrayEnd();
145
146 // Emit a newline character at the end as json::OStream doesn't emit one.
147 OS << "\n";
148}
149
150/// Parse \p Input as function head.
151///
152/// Parse one line of \p Input, and update function name in \p FName,
153/// function's total sample count in \p NumSamples, function's entry
154/// count in \p NumHeadSamples.
155///
156/// \returns true if parsing is successful.
157static bool ParseHead(const StringRef &Input, StringRef &FName,
158 uint64_t &NumSamples, uint64_t &NumHeadSamples) {
159 if (Input[0] == ' ')
160 return false;
161 size_t n2 = Input.rfind(':');
162 size_t n1 = Input.rfind(':', n2 - 1);
163 FName = Input.substr(0, n1);
164 if (Input.substr(n1 + 1, n2 - n1 - 1).getAsInteger(10, NumSamples))
165 return false;
166 if (Input.substr(n2 + 1).getAsInteger(10, NumHeadSamples))
167 return false;
168 return true;
169}
170
171/// Returns true if line offset \p L is legal (only has 16 bits).
172static bool isOffsetLegal(unsigned L) { return (L & 0xffff) == L; }
173
174/// Parse \p Input that contains metadata.
175/// Possible metadata:
176/// - CFG Checksum information:
177/// !CFGChecksum: 12345
178/// - CFG Checksum information:
179/// !Attributes: 1
180/// Stores the FunctionHash (a.k.a. CFG Checksum) into \p FunctionHash.
181static bool parseMetadata(const StringRef &Input, uint64_t &FunctionHash,
182 uint32_t &Attributes) {
183 if (Input.startswith("!CFGChecksum:")) {
184 StringRef CFGInfo = Input.substr(strlen("!CFGChecksum:")).trim();
185 return !CFGInfo.getAsInteger(10, FunctionHash);
186 }
187
188 if (Input.startswith("!Attributes:")) {
189 StringRef Attrib = Input.substr(strlen("!Attributes:")).trim();
190 return !Attrib.getAsInteger(10, Attributes);
191 }
192
193 return false;
194}
195
196enum class LineType {
197 CallSiteProfile,
198 BodyProfile,
199 Metadata,
200};
201
202/// Parse \p Input as line sample.
203///
204/// \param Input input line.
205/// \param LineTy Type of this line.
206/// \param Depth the depth of the inline stack.
207/// \param NumSamples total samples of the line/inlined callsite.
208/// \param LineOffset line offset to the start of the function.
209/// \param Discriminator discriminator of the line.
210/// \param TargetCountMap map from indirect call target to count.
211/// \param FunctionHash the function's CFG hash, used by pseudo probe.
212///
213/// returns true if parsing is successful.
214static bool ParseLine(const StringRef &Input, LineType &LineTy, uint32_t &Depth,
215 uint64_t &NumSamples, uint32_t &LineOffset,
216 uint32_t &Discriminator, StringRef &CalleeName,
217 DenseMap<StringRef, uint64_t> &TargetCountMap,
218 uint64_t &FunctionHash, uint32_t &Attributes) {
219 for (Depth = 0; Input[Depth] == ' '; Depth++)
9
Assuming the condition is true
10
Loop condition is true. Entering loop body
11
Assuming the condition is false
12
Loop condition is false. Execution continues on line 221
220 ;
221 if (Depth
12.1
'Depth' is not equal to 0
== 0)
13
Taking false branch
222 return false;
223
224 if (Input[Depth] == '!') {
14
Assuming the condition is true
15
Taking true branch
225 LineTy = LineType::Metadata;
226 return parseMetadata(Input.substr(Depth), FunctionHash, Attributes);
16
Returning without writing to 'Discriminator'
227 }
228
229 size_t n1 = Input.find(':');
230 StringRef Loc = Input.substr(Depth, n1 - Depth);
231 size_t n2 = Loc.find('.');
232 if (n2 == StringRef::npos) {
233 if (Loc.getAsInteger(10, LineOffset) || !isOffsetLegal(LineOffset))
234 return false;
235 Discriminator = 0;
236 } else {
237 if (Loc.substr(0, n2).getAsInteger(10, LineOffset))
238 return false;
239 if (Loc.substr(n2 + 1).getAsInteger(10, Discriminator))
240 return false;
241 }
242
243 StringRef Rest = Input.substr(n1 + 2);
244 if (isDigit(Rest[0])) {
245 LineTy = LineType::BodyProfile;
246 size_t n3 = Rest.find(' ');
247 if (n3 == StringRef::npos) {
248 if (Rest.getAsInteger(10, NumSamples))
249 return false;
250 } else {
251 if (Rest.substr(0, n3).getAsInteger(10, NumSamples))
252 return false;
253 }
254 // Find call targets and their sample counts.
255 // Note: In some cases, there are symbols in the profile which are not
256 // mangled. To accommodate such cases, use colon + integer pairs as the
257 // anchor points.
258 // An example:
259 // _M_construct<char *>:1000 string_view<std::allocator<char> >:437
260 // ":1000" and ":437" are used as anchor points so the string above will
261 // be interpreted as
262 // target: _M_construct<char *>
263 // count: 1000
264 // target: string_view<std::allocator<char> >
265 // count: 437
266 while (n3 != StringRef::npos) {
267 n3 += Rest.substr(n3).find_first_not_of(' ');
268 Rest = Rest.substr(n3);
269 n3 = Rest.find_first_of(':');
270 if (n3 == StringRef::npos || n3 == 0)
271 return false;
272
273 StringRef Target;
274 uint64_t count, n4;
275 while (true) {
276 // Get the segment after the current colon.
277 StringRef AfterColon = Rest.substr(n3 + 1);
278 // Get the target symbol before the current colon.
279 Target = Rest.substr(0, n3);
280 // Check if the word after the current colon is an integer.
281 n4 = AfterColon.find_first_of(' ');
282 n4 = (n4 != StringRef::npos) ? n3 + n4 + 1 : Rest.size();
283 StringRef WordAfterColon = Rest.substr(n3 + 1, n4 - n3 - 1);
284 if (!WordAfterColon.getAsInteger(10, count))
285 break;
286
287 // Try to find the next colon.
288 uint64_t n5 = AfterColon.find_first_of(':');
289 if (n5 == StringRef::npos)
290 return false;
291 n3 += n5 + 1;
292 }
293
294 // An anchor point is found. Save the {target, count} pair
295 TargetCountMap[Target] = count;
296 if (n4 == Rest.size())
297 break;
298 // Change n3 to the next blank space after colon + integer pair.
299 n3 = n4;
300 }
301 } else {
302 LineTy = LineType::CallSiteProfile;
303 size_t n3 = Rest.find_last_of(':');
304 CalleeName = Rest.substr(0, n3);
305 if (Rest.substr(n3 + 1).getAsInteger(10, NumSamples))
306 return false;
307 }
308 return true;
309}
310
311/// Load samples from a text file.
312///
313/// See the documentation at the top of the file for an explanation of
314/// the expected format.
315///
316/// \returns true if the file was loaded successfully, false otherwise.
317std::error_code SampleProfileReaderText::readImpl() {
318 line_iterator LineIt(*Buffer, /*SkipBlanks=*/true, '#');
319 sampleprof_error Result = sampleprof_error::success;
320
321 InlineCallStack InlineStack;
322 uint32_t TopLevelProbeProfileCount = 0;
323
324 // DepthMetadata tracks whether we have processed metadata for the current
325 // top-level or nested function profile.
326 uint32_t DepthMetadata = 0;
327
328 ProfileIsFS = ProfileIsFSDisciminator;
329 FunctionSamples::ProfileIsFS = ProfileIsFS;
330 for (; !LineIt.is_at_eof(); ++LineIt) {
1
Assuming the condition is true
2
Loop condition is true. Entering loop body
331 if ((*LineIt)[(*LineIt).find_first_not_of(' ')] == '#')
3
Assuming the condition is false
4
Taking false branch
332 continue;
333 // Read the header of each function.
334 //
335 // Note that for function identifiers we are actually expecting
336 // mangled names, but we may not always get them. This happens when
337 // the compiler decides not to emit the function (e.g., it was inlined
338 // and removed). In this case, the binary will not have the linkage
339 // name for the function, so the profiler will emit the function's
340 // unmangled name, which may contain characters like ':' and '>' in its
341 // name (member functions, templates, etc).
342 //
343 // The only requirement we place on the identifier, then, is that it
344 // should not begin with a number.
345 if ((*LineIt)[0] != ' ') {
5
Assuming the condition is false
6
Taking false branch
346 uint64_t NumSamples, NumHeadSamples;
347 StringRef FName;
348 if (!ParseHead(*LineIt, FName, NumSamples, NumHeadSamples)) {
349 reportError(LineIt.line_number(),
350 "Expected 'mangled_name:NUM:NUM', found " + *LineIt);
351 return sampleprof_error::malformed;
352 }
353 DepthMetadata = 0;
354 SampleContext FContext(FName, CSNameTable);
355 if (FContext.hasContext())
356 ++CSProfileCount;
357 Profiles[FContext] = FunctionSamples();
358 FunctionSamples &FProfile = Profiles[FContext];
359 FProfile.setContext(FContext);
360 MergeResult(Result, FProfile.addTotalSamples(NumSamples));
361 MergeResult(Result, FProfile.addHeadSamples(NumHeadSamples));
362 InlineStack.clear();
363 InlineStack.push_back(&FProfile);
364 } else {
365 uint64_t NumSamples;
366 StringRef FName;
367 DenseMap<StringRef, uint64_t> TargetCountMap;
368 uint32_t Depth, LineOffset, Discriminator;
7
'Discriminator' declared without an initial value
369 LineType LineTy;
370 uint64_t FunctionHash = 0;
371 uint32_t Attributes = 0;
372 if (!ParseLine(*LineIt, LineTy, Depth, NumSamples, LineOffset,
8
Calling 'ParseLine'
17
Returning from 'ParseLine'
373 Discriminator, FName, TargetCountMap, FunctionHash,
374 Attributes)) {
375 reportError(LineIt.line_number(),
376 "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " +
377 *LineIt);
378 return sampleprof_error::malformed;
379 }
380 if (LineTy
17.1
'LineTy' is equal to Metadata
!= LineType::Metadata && Depth == DepthMetadata) {
381 // Metadata must be put at the end of a function profile.
382 reportError(LineIt.line_number(),
383 "Found non-metadata after metadata: " + *LineIt);
384 return sampleprof_error::malformed;
385 }
386
387 // Here we handle FS discriminators.
388 Discriminator &= getDiscriminatorMask();
18
The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
389
390 while (InlineStack.size() > Depth) {
391 InlineStack.pop_back();
392 }
393 switch (LineTy) {
394 case LineType::CallSiteProfile: {
395 FunctionSamples &FSamples = InlineStack.back()->functionSamplesAt(
396 LineLocation(LineOffset, Discriminator))[std::string(FName)];
397 FSamples.setName(FName);
398 MergeResult(Result, FSamples.addTotalSamples(NumSamples));
399 InlineStack.push_back(&FSamples);
400 DepthMetadata = 0;
401 break;
402 }
403 case LineType::BodyProfile: {
404 while (InlineStack.size() > Depth) {
405 InlineStack.pop_back();
406 }
407 FunctionSamples &FProfile = *InlineStack.back();
408 for (const auto &name_count : TargetCountMap) {
409 MergeResult(Result, FProfile.addCalledTargetSamples(
410 LineOffset, Discriminator, name_count.first,
411 name_count.second));
412 }
413 MergeResult(Result, FProfile.addBodySamples(LineOffset, Discriminator,
414 NumSamples));
415 break;
416 }
417 case LineType::Metadata: {
418 FunctionSamples &FProfile = *InlineStack.back();
419 if (FunctionHash) {
420 FProfile.setFunctionHash(FunctionHash);
421 if (Depth == 1)
422 ++TopLevelProbeProfileCount;
423 }
424 FProfile.getContext().setAllAttributes(Attributes);
425 if (Attributes & (uint32_t)ContextShouldBeInlined)
426 ProfileIsPreInlined = true;
427 DepthMetadata = Depth;
428 break;
429 }
430 }
431 }
432 }
433
434 assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&(static_cast <bool> ((CSProfileCount == 0 || CSProfileCount
== Profiles.size()) && "Cannot have both context-sensitive and regular profile"
) ? void (0) : __assert_fail ("(CSProfileCount == 0 || CSProfileCount == Profiles.size()) && \"Cannot have both context-sensitive and regular profile\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 435, __extension__
__PRETTY_FUNCTION__))
435 "Cannot have both context-sensitive and regular profile")(static_cast <bool> ((CSProfileCount == 0 || CSProfileCount
== Profiles.size()) && "Cannot have both context-sensitive and regular profile"
) ? void (0) : __assert_fail ("(CSProfileCount == 0 || CSProfileCount == Profiles.size()) && \"Cannot have both context-sensitive and regular profile\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 435, __extension__
__PRETTY_FUNCTION__))
;
436 ProfileIsCS = (CSProfileCount > 0);
437 assert((TopLevelProbeProfileCount == 0 ||(static_cast <bool> ((TopLevelProbeProfileCount == 0 ||
TopLevelProbeProfileCount == Profiles.size()) && "Cannot have both probe-based profiles and regular profiles"
) ? void (0) : __assert_fail ("(TopLevelProbeProfileCount == 0 || TopLevelProbeProfileCount == Profiles.size()) && \"Cannot have both probe-based profiles and regular profiles\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 439, __extension__
__PRETTY_FUNCTION__))
438 TopLevelProbeProfileCount == Profiles.size()) &&(static_cast <bool> ((TopLevelProbeProfileCount == 0 ||
TopLevelProbeProfileCount == Profiles.size()) && "Cannot have both probe-based profiles and regular profiles"
) ? void (0) : __assert_fail ("(TopLevelProbeProfileCount == 0 || TopLevelProbeProfileCount == Profiles.size()) && \"Cannot have both probe-based profiles and regular profiles\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 439, __extension__
__PRETTY_FUNCTION__))
439 "Cannot have both probe-based profiles and regular profiles")(static_cast <bool> ((TopLevelProbeProfileCount == 0 ||
TopLevelProbeProfileCount == Profiles.size()) && "Cannot have both probe-based profiles and regular profiles"
) ? void (0) : __assert_fail ("(TopLevelProbeProfileCount == 0 || TopLevelProbeProfileCount == Profiles.size()) && \"Cannot have both probe-based profiles and regular profiles\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 439, __extension__
__PRETTY_FUNCTION__))
;
440 ProfileIsProbeBased = (TopLevelProbeProfileCount > 0);
441 FunctionSamples::ProfileIsProbeBased = ProfileIsProbeBased;
442 FunctionSamples::ProfileIsCS = ProfileIsCS;
443 FunctionSamples::ProfileIsPreInlined = ProfileIsPreInlined;
444
445 if (Result == sampleprof_error::success)
446 computeSummary();
447
448 return Result;
449}
450
451bool SampleProfileReaderText::hasFormat(const MemoryBuffer &Buffer) {
452 bool result = false;
453
454 // Check that the first non-comment line is a valid function header.
455 line_iterator LineIt(Buffer, /*SkipBlanks=*/true, '#');
456 if (!LineIt.is_at_eof()) {
457 if ((*LineIt)[0] != ' ') {
458 uint64_t NumSamples, NumHeadSamples;
459 StringRef FName;
460 result = ParseHead(*LineIt, FName, NumSamples, NumHeadSamples);
461 }
462 }
463
464 return result;
465}
466
467template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() {
468 unsigned NumBytesRead = 0;
469 std::error_code EC;
470 uint64_t Val = decodeULEB128(Data, &NumBytesRead);
471
472 if (Val > std::numeric_limits<T>::max())
473 EC = sampleprof_error::malformed;
474 else if (Data + NumBytesRead > End)
475 EC = sampleprof_error::truncated;
476 else
477 EC = sampleprof_error::success;
478
479 if (EC) {
480 reportError(0, EC.message());
481 return EC;
482 }
483
484 Data += NumBytesRead;
485 return static_cast<T>(Val);
486}
487
488ErrorOr<StringRef> SampleProfileReaderBinary::readString() {
489 std::error_code EC;
490 StringRef Str(reinterpret_cast<const char *>(Data));
491 if (Data + Str.size() + 1 > End) {
492 EC = sampleprof_error::truncated;
493 reportError(0, EC.message());
494 return EC;
495 }
496
497 Data += Str.size() + 1;
498 return Str;
499}
500
501template <typename T>
502ErrorOr<T> SampleProfileReaderBinary::readUnencodedNumber() {
503 std::error_code EC;
504
505 if (Data + sizeof(T) > End) {
506 EC = sampleprof_error::truncated;
507 reportError(0, EC.message());
508 return EC;
509 }
510
511 using namespace support;
512 T Val = endian::readNext<T, little, unaligned>(Data);
513 return Val;
514}
515
516template <typename T>
517inline ErrorOr<uint32_t> SampleProfileReaderBinary::readStringIndex(T &Table) {
518 std::error_code EC;
519 auto Idx = readNumber<uint32_t>();
520 if (std::error_code EC = Idx.getError())
521 return EC;
522 if (*Idx >= Table.size())
523 return sampleprof_error::truncated_name_table;
524 return *Idx;
525}
526
527ErrorOr<StringRef> SampleProfileReaderBinary::readStringFromTable() {
528 auto Idx = readStringIndex(NameTable);
529 if (std::error_code EC = Idx.getError())
530 return EC;
531
532 return NameTable[*Idx];
533}
534
535ErrorOr<SampleContext> SampleProfileReaderBinary::readSampleContextFromTable() {
536 auto FName(readStringFromTable());
537 if (std::error_code EC = FName.getError())
538 return EC;
539 return SampleContext(*FName);
540}
541
542ErrorOr<StringRef> SampleProfileReaderExtBinaryBase::readStringFromTable() {
543 if (!FixedLengthMD5)
544 return SampleProfileReaderBinary::readStringFromTable();
545
546 // read NameTable index.
547 auto Idx = readStringIndex(NameTable);
548 if (std::error_code EC = Idx.getError())
549 return EC;
550
551 // Check whether the name to be accessed has been accessed before,
552 // if not, read it from memory directly.
553 StringRef &SR = NameTable[*Idx];
554 if (SR.empty()) {
555 const uint8_t *SavedData = Data;
556 Data = MD5NameMemStart + ((*Idx) * sizeof(uint64_t));
557 auto FID = readUnencodedNumber<uint64_t>();
558 if (std::error_code EC = FID.getError())
559 return EC;
560 // Save the string converted from uint64_t in MD5StringBuf. All the
561 // references to the name are all StringRefs refering to the string
562 // in MD5StringBuf.
563 MD5StringBuf->push_back(std::to_string(*FID));
564 SR = MD5StringBuf->back();
565 Data = SavedData;
566 }
567 return SR;
568}
569
570ErrorOr<StringRef> SampleProfileReaderCompactBinary::readStringFromTable() {
571 auto Idx = readStringIndex(NameTable);
572 if (std::error_code EC = Idx.getError())
573 return EC;
574
575 return StringRef(NameTable[*Idx]);
576}
577
578std::error_code
579SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
580 auto NumSamples = readNumber<uint64_t>();
581 if (std::error_code EC = NumSamples.getError())
582 return EC;
583 FProfile.addTotalSamples(*NumSamples);
584
585 // Read the samples in the body.
586 auto NumRecords = readNumber<uint32_t>();
587 if (std::error_code EC = NumRecords.getError())
588 return EC;
589
590 for (uint32_t I = 0; I < *NumRecords; ++I) {
591 auto LineOffset = readNumber<uint64_t>();
592 if (std::error_code EC = LineOffset.getError())
593 return EC;
594
595 if (!isOffsetLegal(*LineOffset)) {
596 return std::error_code();
597 }
598
599 auto Discriminator = readNumber<uint64_t>();
600 if (std::error_code EC = Discriminator.getError())
601 return EC;
602
603 auto NumSamples = readNumber<uint64_t>();
604 if (std::error_code EC = NumSamples.getError())
605 return EC;
606
607 auto NumCalls = readNumber<uint32_t>();
608 if (std::error_code EC = NumCalls.getError())
609 return EC;
610
611 // Here we handle FS discriminators:
612 uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
613
614 for (uint32_t J = 0; J < *NumCalls; ++J) {
615 auto CalledFunction(readStringFromTable());
616 if (std::error_code EC = CalledFunction.getError())
617 return EC;
618
619 auto CalledFunctionSamples = readNumber<uint64_t>();
620 if (std::error_code EC = CalledFunctionSamples.getError())
621 return EC;
622
623 FProfile.addCalledTargetSamples(*LineOffset, DiscriminatorVal,
624 *CalledFunction, *CalledFunctionSamples);
625 }
626
627 FProfile.addBodySamples(*LineOffset, DiscriminatorVal, *NumSamples);
628 }
629
630 // Read all the samples for inlined function calls.
631 auto NumCallsites = readNumber<uint32_t>();
632 if (std::error_code EC = NumCallsites.getError())
633 return EC;
634
635 for (uint32_t J = 0; J < *NumCallsites; ++J) {
636 auto LineOffset = readNumber<uint64_t>();
637 if (std::error_code EC = LineOffset.getError())
638 return EC;
639
640 auto Discriminator = readNumber<uint64_t>();
641 if (std::error_code EC = Discriminator.getError())
642 return EC;
643
644 auto FName(readStringFromTable());
645 if (std::error_code EC = FName.getError())
646 return EC;
647
648 // Here we handle FS discriminators:
649 uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
650
651 FunctionSamples &CalleeProfile = FProfile.functionSamplesAt(
652 LineLocation(*LineOffset, DiscriminatorVal))[std::string(*FName)];
653 CalleeProfile.setName(*FName);
654 if (std::error_code EC = readProfile(CalleeProfile))
655 return EC;
656 }
657
658 return sampleprof_error::success;
659}
660
661std::error_code
662SampleProfileReaderBinary::readFuncProfile(const uint8_t *Start) {
663 Data = Start;
664 auto NumHeadSamples = readNumber<uint64_t>();
665 if (std::error_code EC = NumHeadSamples.getError())
666 return EC;
667
668 ErrorOr<SampleContext> FContext(readSampleContextFromTable());
669 if (std::error_code EC = FContext.getError())
670 return EC;
671
672 Profiles[*FContext] = FunctionSamples();
673 FunctionSamples &FProfile = Profiles[*FContext];
674 FProfile.setContext(*FContext);
675 FProfile.addHeadSamples(*NumHeadSamples);
676
677 if (FContext->hasContext())
678 CSProfileCount++;
679
680 if (std::error_code EC = readProfile(FProfile))
681 return EC;
682 return sampleprof_error::success;
683}
684
685std::error_code SampleProfileReaderBinary::readImpl() {
686 ProfileIsFS = ProfileIsFSDisciminator;
687 FunctionSamples::ProfileIsFS = ProfileIsFS;
688 while (!at_eof()) {
689 if (std::error_code EC = readFuncProfile(Data))
690 return EC;
691 }
692
693 return sampleprof_error::success;
694}
695
696ErrorOr<SampleContextFrames>
697SampleProfileReaderExtBinaryBase::readContextFromTable() {
698 auto ContextIdx = readNumber<uint32_t>();
699 if (std::error_code EC = ContextIdx.getError())
700 return EC;
701 if (*ContextIdx >= CSNameTable->size())
702 return sampleprof_error::truncated_name_table;
703 return (*CSNameTable)[*ContextIdx];
704}
705
706ErrorOr<SampleContext>
707SampleProfileReaderExtBinaryBase::readSampleContextFromTable() {
708 if (ProfileIsCS) {
709 auto FContext(readContextFromTable());
710 if (std::error_code EC = FContext.getError())
711 return EC;
712 return SampleContext(*FContext);
713 } else {
714 auto FName(readStringFromTable());
715 if (std::error_code EC = FName.getError())
716 return EC;
717 return SampleContext(*FName);
718 }
719}
720
721std::error_code SampleProfileReaderExtBinaryBase::readOneSection(
722 const uint8_t *Start, uint64_t Size, const SecHdrTableEntry &Entry) {
723 Data = Start;
724 End = Start + Size;
725 switch (Entry.Type) {
726 case SecProfSummary:
727 if (std::error_code EC = readSummary())
728 return EC;
729 if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagPartial))
730 Summary->setPartialProfile(true);
731 if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFullContext))
732 FunctionSamples::ProfileIsCS = ProfileIsCS = true;
733 if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagIsPreInlined))
734 FunctionSamples::ProfileIsPreInlined = ProfileIsPreInlined = true;
735 if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFSDiscriminator))
736 FunctionSamples::ProfileIsFS = ProfileIsFS = true;
737 break;
738 case SecNameTable: {
739 FixedLengthMD5 =
740 hasSecFlag(Entry, SecNameTableFlags::SecFlagFixedLengthMD5);
741 bool UseMD5 = hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name);
742 assert((!FixedLengthMD5 || UseMD5) &&(static_cast <bool> ((!FixedLengthMD5 || UseMD5) &&
"If FixedLengthMD5 is true, UseMD5 has to be true") ? void (
0) : __assert_fail ("(!FixedLengthMD5 || UseMD5) && \"If FixedLengthMD5 is true, UseMD5 has to be true\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 743, __extension__
__PRETTY_FUNCTION__))
743 "If FixedLengthMD5 is true, UseMD5 has to be true")(static_cast <bool> ((!FixedLengthMD5 || UseMD5) &&
"If FixedLengthMD5 is true, UseMD5 has to be true") ? void (
0) : __assert_fail ("(!FixedLengthMD5 || UseMD5) && \"If FixedLengthMD5 is true, UseMD5 has to be true\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 743, __extension__
__PRETTY_FUNCTION__))
;
744 FunctionSamples::HasUniqSuffix =
745 hasSecFlag(Entry, SecNameTableFlags::SecFlagUniqSuffix);
746 if (std::error_code EC = readNameTableSec(UseMD5))
747 return EC;
748 break;
749 }
750 case SecCSNameTable: {
751 if (std::error_code EC = readCSNameTableSec())
752 return EC;
753 break;
754 }
755 case SecLBRProfile:
756 if (std::error_code EC = readFuncProfiles())
757 return EC;
758 break;
759 case SecFuncOffsetTable:
760 FuncOffsetsOrdered = hasSecFlag(Entry, SecFuncOffsetFlags::SecFlagOrdered);
761 if (std::error_code EC = readFuncOffsetTable())
762 return EC;
763 break;
764 case SecFuncMetadata: {
765 ProfileIsProbeBased =
766 hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagIsProbeBased);
767 FunctionSamples::ProfileIsProbeBased = ProfileIsProbeBased;
768 bool HasAttribute =
769 hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagHasAttribute);
770 if (std::error_code EC = readFuncMetadata(HasAttribute))
771 return EC;
772 break;
773 }
774 case SecProfileSymbolList:
775 if (std::error_code EC = readProfileSymbolList())
776 return EC;
777 break;
778 default:
779 if (std::error_code EC = readCustomSection(Entry))
780 return EC;
781 break;
782 }
783 return sampleprof_error::success;
784}
785
786bool SampleProfileReaderExtBinaryBase::collectFuncsFromModule() {
787 if (!M)
788 return false;
789 FuncsToUse.clear();
790 for (auto &F : *M)
791 FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
792 return true;
793}
794
795std::error_code SampleProfileReaderExtBinaryBase::readFuncOffsetTable() {
796 // If there are more than one FuncOffsetTable, the profile read associated
797 // with previous FuncOffsetTable has to be done before next FuncOffsetTable
798 // is read.
799 FuncOffsetTable.clear();
800
801 auto Size = readNumber<uint64_t>();
802 if (std::error_code EC = Size.getError())
803 return EC;
804
805 FuncOffsetTable.reserve(*Size);
806
807 if (FuncOffsetsOrdered) {
808 OrderedFuncOffsets =
809 std::make_unique<std::vector<std::pair<SampleContext, uint64_t>>>();
810 OrderedFuncOffsets->reserve(*Size);
811 }
812
813 for (uint64_t I = 0; I < *Size; ++I) {
814 auto FContext(readSampleContextFromTable());
815 if (std::error_code EC = FContext.getError())
816 return EC;
817
818 auto Offset = readNumber<uint64_t>();
819 if (std::error_code EC = Offset.getError())
820 return EC;
821
822 FuncOffsetTable[*FContext] = *Offset;
823 if (FuncOffsetsOrdered)
824 OrderedFuncOffsets->emplace_back(*FContext, *Offset);
825 }
826
827 return sampleprof_error::success;
828}
829
830std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() {
831 // Collect functions used by current module if the Reader has been
832 // given a module.
833 // collectFuncsFromModule uses FunctionSamples::getCanonicalFnName
834 // which will query FunctionSamples::HasUniqSuffix, so it has to be
835 // called after FunctionSamples::HasUniqSuffix is set, i.e. after
836 // NameTable section is read.
837 bool LoadFuncsToBeUsed = collectFuncsFromModule();
838
839 // When LoadFuncsToBeUsed is false, load all the function profiles.
840 const uint8_t *Start = Data;
841 if (!LoadFuncsToBeUsed) {
842 while (Data < End) {
843 if (std::error_code EC = readFuncProfile(Data))
844 return EC;
845 }
846 assert(Data == End && "More data is read than expected")(static_cast <bool> (Data == End && "More data is read than expected"
) ? void (0) : __assert_fail ("Data == End && \"More data is read than expected\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 846, __extension__
__PRETTY_FUNCTION__))
;
847 } else {
848 // Load function profiles on demand.
849 if (Remapper) {
850 for (auto Name : FuncsToUse) {
851 Remapper->insert(Name);
852 }
853 }
854
855 if (ProfileIsCS) {
856 DenseSet<uint64_t> FuncGuidsToUse;
857 if (useMD5()) {
858 for (auto Name : FuncsToUse)
859 FuncGuidsToUse.insert(Function::getGUID(Name));
860 }
861
862 // For each function in current module, load all context profiles for
863 // the function as well as their callee contexts which can help profile
864 // guided importing for ThinLTO. This can be achieved by walking
865 // through an ordered context container, where contexts are laid out
866 // as if they were walked in preorder of a context trie. While
867 // traversing the trie, a link to the highest common ancestor node is
868 // kept so that all of its decendants will be loaded.
869 assert(OrderedFuncOffsets.get() &&(static_cast <bool> (OrderedFuncOffsets.get() &&
"func offset table should always be sorted in CS profile") ?
void (0) : __assert_fail ("OrderedFuncOffsets.get() && \"func offset table should always be sorted in CS profile\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 870, __extension__
__PRETTY_FUNCTION__))
870 "func offset table should always be sorted in CS profile")(static_cast <bool> (OrderedFuncOffsets.get() &&
"func offset table should always be sorted in CS profile") ?
void (0) : __assert_fail ("OrderedFuncOffsets.get() && \"func offset table should always be sorted in CS profile\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 870, __extension__
__PRETTY_FUNCTION__))
;
871 const SampleContext *CommonContext = nullptr;
872 for (const auto &NameOffset : *OrderedFuncOffsets) {
873 const auto &FContext = NameOffset.first;
874 auto FName = FContext.getName();
875 // For function in the current module, keep its farthest ancestor
876 // context. This can be used to load itself and its child and
877 // sibling contexts.
878 if ((useMD5() && FuncGuidsToUse.count(std::stoull(FName.data()))) ||
879 (!useMD5() && (FuncsToUse.count(FName) ||
880 (Remapper && Remapper->exist(FName))))) {
881 if (!CommonContext || !CommonContext->IsPrefixOf(FContext))
882 CommonContext = &FContext;
883 }
884
885 if (CommonContext == &FContext ||
886 (CommonContext && CommonContext->IsPrefixOf(FContext))) {
887 // Load profile for the current context which originated from
888 // the common ancestor.
889 const uint8_t *FuncProfileAddr = Start + NameOffset.second;
890 assert(FuncProfileAddr < End && "out of LBRProfile section")(static_cast <bool> (FuncProfileAddr < End &&
"out of LBRProfile section") ? void (0) : __assert_fail ("FuncProfileAddr < End && \"out of LBRProfile section\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 890, __extension__
__PRETTY_FUNCTION__))
;
891 if (std::error_code EC = readFuncProfile(FuncProfileAddr))
892 return EC;
893 }
894 }
895 } else {
896 if (useMD5()) {
897 for (auto Name : FuncsToUse) {
898 auto GUID = std::to_string(MD5Hash(Name));
899 auto iter = FuncOffsetTable.find(StringRef(GUID));
900 if (iter == FuncOffsetTable.end())
901 continue;
902 const uint8_t *FuncProfileAddr = Start + iter->second;
903 assert(FuncProfileAddr < End && "out of LBRProfile section")(static_cast <bool> (FuncProfileAddr < End &&
"out of LBRProfile section") ? void (0) : __assert_fail ("FuncProfileAddr < End && \"out of LBRProfile section\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 903, __extension__
__PRETTY_FUNCTION__))
;
904 if (std::error_code EC = readFuncProfile(FuncProfileAddr))
905 return EC;
906 }
907 } else {
908 for (auto NameOffset : FuncOffsetTable) {
909 SampleContext FContext(NameOffset.first);
910 auto FuncName = FContext.getName();
911 if (!FuncsToUse.count(FuncName) &&
912 (!Remapper || !Remapper->exist(FuncName)))
913 continue;
914 const uint8_t *FuncProfileAddr = Start + NameOffset.second;
915 assert(FuncProfileAddr < End && "out of LBRProfile section")(static_cast <bool> (FuncProfileAddr < End &&
"out of LBRProfile section") ? void (0) : __assert_fail ("FuncProfileAddr < End && \"out of LBRProfile section\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 915, __extension__
__PRETTY_FUNCTION__))
;
916 if (std::error_code EC = readFuncProfile(FuncProfileAddr))
917 return EC;
918 }
919 }
920 }
921 Data = End;
922 }
923 assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&(static_cast <bool> ((CSProfileCount == 0 || CSProfileCount
== Profiles.size()) && "Cannot have both context-sensitive and regular profile"
) ? void (0) : __assert_fail ("(CSProfileCount == 0 || CSProfileCount == Profiles.size()) && \"Cannot have both context-sensitive and regular profile\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 924, __extension__
__PRETTY_FUNCTION__))
924 "Cannot have both context-sensitive and regular profile")(static_cast <bool> ((CSProfileCount == 0 || CSProfileCount
== Profiles.size()) && "Cannot have both context-sensitive and regular profile"
) ? void (0) : __assert_fail ("(CSProfileCount == 0 || CSProfileCount == Profiles.size()) && \"Cannot have both context-sensitive and regular profile\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 924, __extension__
__PRETTY_FUNCTION__))
;
925 assert((!CSProfileCount || ProfileIsCS) &&(static_cast <bool> ((!CSProfileCount || ProfileIsCS) &&
"Section flag should be consistent with actual profile") ? void
(0) : __assert_fail ("(!CSProfileCount || ProfileIsCS) && \"Section flag should be consistent with actual profile\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 926, __extension__
__PRETTY_FUNCTION__))
926 "Section flag should be consistent with actual profile")(static_cast <bool> ((!CSProfileCount || ProfileIsCS) &&
"Section flag should be consistent with actual profile") ? void
(0) : __assert_fail ("(!CSProfileCount || ProfileIsCS) && \"Section flag should be consistent with actual profile\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 926, __extension__
__PRETTY_FUNCTION__))
;
927 return sampleprof_error::success;
928}
929
930std::error_code SampleProfileReaderExtBinaryBase::readProfileSymbolList() {
931 if (!ProfSymList)
932 ProfSymList = std::make_unique<ProfileSymbolList>();
933
934 if (std::error_code EC = ProfSymList->read(Data, End - Data))
935 return EC;
936
937 Data = End;
938 return sampleprof_error::success;
939}
940
941std::error_code SampleProfileReaderExtBinaryBase::decompressSection(
942 const uint8_t *SecStart, const uint64_t SecSize,
943 const uint8_t *&DecompressBuf, uint64_t &DecompressBufSize) {
944 Data = SecStart;
945 End = SecStart + SecSize;
946 auto DecompressSize = readNumber<uint64_t>();
947 if (std::error_code EC = DecompressSize.getError())
948 return EC;
949 DecompressBufSize = *DecompressSize;
950
951 auto CompressSize = readNumber<uint64_t>();
952 if (std::error_code EC = CompressSize.getError())
953 return EC;
954
955 if (!llvm::compression::zlib::isAvailable())
956 return sampleprof_error::zlib_unavailable;
957
958 uint8_t *Buffer = Allocator.Allocate<uint8_t>(DecompressBufSize);
959 size_t UCSize = DecompressBufSize;
960 llvm::Error E = compression::zlib::decompress(ArrayRef(Data, *CompressSize),
961 Buffer, UCSize);
962 if (E)
963 return sampleprof_error::uncompress_failed;
964 DecompressBuf = reinterpret_cast<const uint8_t *>(Buffer);
965 return sampleprof_error::success;
966}
967
968std::error_code SampleProfileReaderExtBinaryBase::readImpl() {
969 const uint8_t *BufStart =
970 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
971
972 for (auto &Entry : SecHdrTable) {
973 // Skip empty section.
974 if (!Entry.Size)
975 continue;
976
977 // Skip sections without context when SkipFlatProf is true.
978 if (SkipFlatProf && hasSecFlag(Entry, SecCommonFlags::SecFlagFlat))
979 continue;
980
981 const uint8_t *SecStart = BufStart + Entry.Offset;
982 uint64_t SecSize = Entry.Size;
983
984 // If the section is compressed, decompress it into a buffer
985 // DecompressBuf before reading the actual data. The pointee of
986 // 'Data' will be changed to buffer hold by DecompressBuf
987 // temporarily when reading the actual data.
988 bool isCompressed = hasSecFlag(Entry, SecCommonFlags::SecFlagCompress);
989 if (isCompressed) {
990 const uint8_t *DecompressBuf;
991 uint64_t DecompressBufSize;
992 if (std::error_code EC = decompressSection(
993 SecStart, SecSize, DecompressBuf, DecompressBufSize))
994 return EC;
995 SecStart = DecompressBuf;
996 SecSize = DecompressBufSize;
997 }
998
999 if (std::error_code EC = readOneSection(SecStart, SecSize, Entry))
1000 return EC;
1001 if (Data != SecStart + SecSize)
1002 return sampleprof_error::malformed;
1003
1004 // Change the pointee of 'Data' from DecompressBuf to original Buffer.
1005 if (isCompressed) {
1006 Data = BufStart + Entry.Offset;
1007 End = BufStart + Buffer->getBufferSize();
1008 }
1009 }
1010
1011 return sampleprof_error::success;
1012}
1013
1014std::error_code SampleProfileReaderCompactBinary::readImpl() {
1015 // Collect functions used by current module if the Reader has been
1016 // given a module.
1017 bool LoadFuncsToBeUsed = collectFuncsFromModule();
1018 ProfileIsFS = ProfileIsFSDisciminator;
1019 FunctionSamples::ProfileIsFS = ProfileIsFS;
1020 std::vector<uint64_t> OffsetsToUse;
1021 if (!LoadFuncsToBeUsed) {
1022 // load all the function profiles.
1023 for (auto FuncEntry : FuncOffsetTable) {
1024 OffsetsToUse.push_back(FuncEntry.second);
1025 }
1026 } else {
1027 // load function profiles on demand.
1028 for (auto Name : FuncsToUse) {
1029 auto GUID = std::to_string(MD5Hash(Name));
1030 auto iter = FuncOffsetTable.find(StringRef(GUID));
1031 if (iter == FuncOffsetTable.end())
1032 continue;
1033 OffsetsToUse.push_back(iter->second);
1034 }
1035 }
1036
1037 for (auto Offset : OffsetsToUse) {
1038 const uint8_t *SavedData = Data;
1039 if (std::error_code EC = readFuncProfile(
1040 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()) +
1041 Offset))
1042 return EC;
1043 Data = SavedData;
1044 }
1045 return sampleprof_error::success;
1046}
1047
1048std::error_code SampleProfileReaderRawBinary::verifySPMagic(uint64_t Magic) {
1049 if (Magic == SPMagic())
1050 return sampleprof_error::success;
1051 return sampleprof_error::bad_magic;
1052}
1053
1054std::error_code SampleProfileReaderExtBinary::verifySPMagic(uint64_t Magic) {
1055 if (Magic == SPMagic(SPF_Ext_Binary))
1056 return sampleprof_error::success;
1057 return sampleprof_error::bad_magic;
1058}
1059
1060std::error_code
1061SampleProfileReaderCompactBinary::verifySPMagic(uint64_t Magic) {
1062 if (Magic == SPMagic(SPF_Compact_Binary))
1063 return sampleprof_error::success;
1064 return sampleprof_error::bad_magic;
1065}
1066
1067std::error_code SampleProfileReaderBinary::readNameTable() {
1068 auto Size = readNumber<uint32_t>();
1069 if (std::error_code EC = Size.getError())
1070 return EC;
1071 NameTable.reserve(*Size + NameTable.size());
1072 for (uint32_t I = 0; I < *Size; ++I) {
1073 auto Name(readString());
1074 if (std::error_code EC = Name.getError())
1075 return EC;
1076 NameTable.push_back(*Name);
1077 }
1078
1079 return sampleprof_error::success;
1080}
1081
1082std::error_code SampleProfileReaderExtBinaryBase::readMD5NameTable() {
1083 auto Size = readNumber<uint64_t>();
1084 if (std::error_code EC = Size.getError())
1085 return EC;
1086 MD5StringBuf = std::make_unique<std::vector<std::string>>();
1087 MD5StringBuf->reserve(*Size);
1088 if (FixedLengthMD5) {
1089 // Preallocate and initialize NameTable so we can check whether a name
1090 // index has been read before by checking whether the element in the
1091 // NameTable is empty, meanwhile readStringIndex can do the boundary
1092 // check using the size of NameTable.
1093 NameTable.resize(*Size + NameTable.size());
1094
1095 MD5NameMemStart = Data;
1096 Data = Data + (*Size) * sizeof(uint64_t);
1097 return sampleprof_error::success;
1098 }
1099 NameTable.reserve(*Size);
1100 for (uint64_t I = 0; I < *Size; ++I) {
1101 auto FID = readNumber<uint64_t>();
1102 if (std::error_code EC = FID.getError())
1103 return EC;
1104 MD5StringBuf->push_back(std::to_string(*FID));
1105 // NameTable is a vector of StringRef. Here it is pushing back a
1106 // StringRef initialized with the last string in MD5stringBuf.
1107 NameTable.push_back(MD5StringBuf->back());
1108 }
1109 return sampleprof_error::success;
1110}
1111
1112std::error_code SampleProfileReaderExtBinaryBase::readNameTableSec(bool IsMD5) {
1113 if (IsMD5)
1114 return readMD5NameTable();
1115 return SampleProfileReaderBinary::readNameTable();
1116}
1117
1118// Read in the CS name table section, which basically contains a list of context
1119// vectors. Each element of a context vector, aka a frame, refers to the
1120// underlying raw function names that are stored in the name table, as well as
1121// a callsite identifier that only makes sense for non-leaf frames.
1122std::error_code SampleProfileReaderExtBinaryBase::readCSNameTableSec() {
1123 auto Size = readNumber<uint32_t>();
1124 if (std::error_code EC = Size.getError())
1125 return EC;
1126
1127 std::vector<SampleContextFrameVector> *PNameVec =
1128 new std::vector<SampleContextFrameVector>();
1129 PNameVec->reserve(*Size);
1130 for (uint32_t I = 0; I < *Size; ++I) {
1131 PNameVec->emplace_back(SampleContextFrameVector());
1132 auto ContextSize = readNumber<uint32_t>();
1133 if (std::error_code EC = ContextSize.getError())
1134 return EC;
1135 for (uint32_t J = 0; J < *ContextSize; ++J) {
1136 auto FName(readStringFromTable());
1137 if (std::error_code EC = FName.getError())
1138 return EC;
1139 auto LineOffset = readNumber<uint64_t>();
1140 if (std::error_code EC = LineOffset.getError())
1141 return EC;
1142
1143 if (!isOffsetLegal(*LineOffset))
1144 return std::error_code();
1145
1146 auto Discriminator = readNumber<uint64_t>();
1147 if (std::error_code EC = Discriminator.getError())
1148 return EC;
1149
1150 PNameVec->back().emplace_back(
1151 FName.get(), LineLocation(LineOffset.get(), Discriminator.get()));
1152 }
1153 }
1154
1155 // From this point the underlying object of CSNameTable should be immutable.
1156 CSNameTable.reset(PNameVec);
1157 return sampleprof_error::success;
1158}
1159
1160std::error_code
1161
1162SampleProfileReaderExtBinaryBase::readFuncMetadata(bool ProfileHasAttribute,
1163 FunctionSamples *FProfile) {
1164 if (Data < End) {
1165 if (ProfileIsProbeBased) {
1166 auto Checksum = readNumber<uint64_t>();
1167 if (std::error_code EC = Checksum.getError())
1168 return EC;
1169 if (FProfile)
1170 FProfile->setFunctionHash(*Checksum);
1171 }
1172
1173 if (ProfileHasAttribute) {
1174 auto Attributes = readNumber<uint32_t>();
1175 if (std::error_code EC = Attributes.getError())
1176 return EC;
1177 if (FProfile)
1178 FProfile->getContext().setAllAttributes(*Attributes);
1179 }
1180
1181 if (!ProfileIsCS) {
1182 // Read all the attributes for inlined function calls.
1183 auto NumCallsites = readNumber<uint32_t>();
1184 if (std::error_code EC = NumCallsites.getError())
1185 return EC;
1186
1187 for (uint32_t J = 0; J < *NumCallsites; ++J) {
1188 auto LineOffset = readNumber<uint64_t>();
1189 if (std::error_code EC = LineOffset.getError())
1190 return EC;
1191
1192 auto Discriminator = readNumber<uint64_t>();
1193 if (std::error_code EC = Discriminator.getError())
1194 return EC;
1195
1196 auto FContext(readSampleContextFromTable());
1197 if (std::error_code EC = FContext.getError())
1198 return EC;
1199
1200 FunctionSamples *CalleeProfile = nullptr;
1201 if (FProfile) {
1202 CalleeProfile = const_cast<FunctionSamples *>(
1203 &FProfile->functionSamplesAt(LineLocation(
1204 *LineOffset,
1205 *Discriminator))[std::string(FContext.get().getName())]);
1206 }
1207 if (std::error_code EC =
1208 readFuncMetadata(ProfileHasAttribute, CalleeProfile))
1209 return EC;
1210 }
1211 }
1212 }
1213
1214 return sampleprof_error::success;
1215}
1216
1217std::error_code
1218SampleProfileReaderExtBinaryBase::readFuncMetadata(bool ProfileHasAttribute) {
1219 while (Data < End) {
1220 auto FContext(readSampleContextFromTable());
1221 if (std::error_code EC = FContext.getError())
1222 return EC;
1223 FunctionSamples *FProfile = nullptr;
1224 auto It = Profiles.find(*FContext);
1225 if (It != Profiles.end())
1226 FProfile = &It->second;
1227
1228 if (std::error_code EC = readFuncMetadata(ProfileHasAttribute, FProfile))
1229 return EC;
1230 }
1231
1232 assert(Data == End && "More data is read than expected")(static_cast <bool> (Data == End && "More data is read than expected"
) ? void (0) : __assert_fail ("Data == End && \"More data is read than expected\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 1232, __extension__
__PRETTY_FUNCTION__))
;
1233 return sampleprof_error::success;
1234}
1235
1236std::error_code SampleProfileReaderCompactBinary::readNameTable() {
1237 auto Size = readNumber<uint64_t>();
1238 if (std::error_code EC = Size.getError())
1239 return EC;
1240 NameTable.reserve(*Size);
1241 for (uint64_t I = 0; I < *Size; ++I) {
1242 auto FID = readNumber<uint64_t>();
1243 if (std::error_code EC = FID.getError())
1244 return EC;
1245 NameTable.push_back(std::to_string(*FID));
1246 }
1247 return sampleprof_error::success;
1248}
1249
1250std::error_code
1251SampleProfileReaderExtBinaryBase::readSecHdrTableEntry(uint32_t Idx) {
1252 SecHdrTableEntry Entry;
1253 auto Type = readUnencodedNumber<uint64_t>();
1254 if (std::error_code EC = Type.getError())
1255 return EC;
1256 Entry.Type = static_cast<SecType>(*Type);
1257
1258 auto Flags = readUnencodedNumber<uint64_t>();
1259 if (std::error_code EC = Flags.getError())
1260 return EC;
1261 Entry.Flags = *Flags;
1262
1263 auto Offset = readUnencodedNumber<uint64_t>();
1264 if (std::error_code EC = Offset.getError())
1265 return EC;
1266 Entry.Offset = *Offset;
1267
1268 auto Size = readUnencodedNumber<uint64_t>();
1269 if (std::error_code EC = Size.getError())
1270 return EC;
1271 Entry.Size = *Size;
1272
1273 Entry.LayoutIndex = Idx;
1274 SecHdrTable.push_back(std::move(Entry));
1275 return sampleprof_error::success;
1276}
1277
1278std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTable() {
1279 auto EntryNum = readUnencodedNumber<uint64_t>();
1280 if (std::error_code EC = EntryNum.getError())
1281 return EC;
1282
1283 for (uint64_t i = 0; i < (*EntryNum); i++)
1284 if (std::error_code EC = readSecHdrTableEntry(i))
1285 return EC;
1286
1287 return sampleprof_error::success;
1288}
1289
1290std::error_code SampleProfileReaderExtBinaryBase::readHeader() {
1291 const uint8_t *BufStart =
1292 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1293 Data = BufStart;
1294 End = BufStart + Buffer->getBufferSize();
1295
1296 if (std::error_code EC = readMagicIdent())
1297 return EC;
1298
1299 if (std::error_code EC = readSecHdrTable())
1300 return EC;
1301
1302 return sampleprof_error::success;
1303}
1304
1305uint64_t SampleProfileReaderExtBinaryBase::getSectionSize(SecType Type) {
1306 uint64_t Size = 0;
1307 for (auto &Entry : SecHdrTable) {
1308 if (Entry.Type == Type)
1309 Size += Entry.Size;
1310 }
1311 return Size;
1312}
1313
1314uint64_t SampleProfileReaderExtBinaryBase::getFileSize() {
1315 // Sections in SecHdrTable is not necessarily in the same order as
1316 // sections in the profile because section like FuncOffsetTable needs
1317 // to be written after section LBRProfile but needs to be read before
1318 // section LBRProfile, so we cannot simply use the last entry in
1319 // SecHdrTable to calculate the file size.
1320 uint64_t FileSize = 0;
1321 for (auto &Entry : SecHdrTable) {
1322 FileSize = std::max(Entry.Offset + Entry.Size, FileSize);
1323 }
1324 return FileSize;
1325}
1326
1327static std::string getSecFlagsStr(const SecHdrTableEntry &Entry) {
1328 std::string Flags;
1329 if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress))
1330 Flags.append("{compressed,");
1331 else
1332 Flags.append("{");
1333
1334 if (hasSecFlag(Entry, SecCommonFlags::SecFlagFlat))
1335 Flags.append("flat,");
1336
1337 switch (Entry.Type) {
1338 case SecNameTable:
1339 if (hasSecFlag(Entry, SecNameTableFlags::SecFlagFixedLengthMD5))
1340 Flags.append("fixlenmd5,");
1341 else if (hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name))
1342 Flags.append("md5,");
1343 if (hasSecFlag(Entry, SecNameTableFlags::SecFlagUniqSuffix))
1344 Flags.append("uniq,");
1345 break;
1346 case SecProfSummary:
1347 if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagPartial))
1348 Flags.append("partial,");
1349 if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFullContext))
1350 Flags.append("context,");
1351 if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagIsPreInlined))
1352 Flags.append("preInlined,");
1353 if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFSDiscriminator))
1354 Flags.append("fs-discriminator,");
1355 break;
1356 case SecFuncOffsetTable:
1357 if (hasSecFlag(Entry, SecFuncOffsetFlags::SecFlagOrdered))
1358 Flags.append("ordered,");
1359 break;
1360 case SecFuncMetadata:
1361 if (hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagIsProbeBased))
1362 Flags.append("probe,");
1363 if (hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagHasAttribute))
1364 Flags.append("attr,");
1365 break;
1366 default:
1367 break;
1368 }
1369 char &last = Flags.back();
1370 if (last == ',')
1371 last = '}';
1372 else
1373 Flags.append("}");
1374 return Flags;
1375}
1376
1377bool SampleProfileReaderExtBinaryBase::dumpSectionInfo(raw_ostream &OS) {
1378 uint64_t TotalSecsSize = 0;
1379 for (auto &Entry : SecHdrTable) {
1380 OS << getSecName(Entry.Type) << " - Offset: " << Entry.Offset
1381 << ", Size: " << Entry.Size << ", Flags: " << getSecFlagsStr(Entry)
1382 << "\n";
1383 ;
1384 TotalSecsSize += Entry.Size;
1385 }
1386 uint64_t HeaderSize = SecHdrTable.front().Offset;
1387 assert(HeaderSize + TotalSecsSize == getFileSize() &&(static_cast <bool> (HeaderSize + TotalSecsSize == getFileSize
() && "Size of 'header + sections' doesn't match the total size of profile"
) ? void (0) : __assert_fail ("HeaderSize + TotalSecsSize == getFileSize() && \"Size of 'header + sections' doesn't match the total size of profile\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 1388, __extension__
__PRETTY_FUNCTION__))
1388 "Size of 'header + sections' doesn't match the total size of profile")(static_cast <bool> (HeaderSize + TotalSecsSize == getFileSize
() && "Size of 'header + sections' doesn't match the total size of profile"
) ? void (0) : __assert_fail ("HeaderSize + TotalSecsSize == getFileSize() && \"Size of 'header + sections' doesn't match the total size of profile\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 1388, __extension__
__PRETTY_FUNCTION__))
;
1389
1390 OS << "Header Size: " << HeaderSize << "\n";
1391 OS << "Total Sections Size: " << TotalSecsSize << "\n";
1392 OS << "File Size: " << getFileSize() << "\n";
1393 return true;
1394}
1395
1396std::error_code SampleProfileReaderBinary::readMagicIdent() {
1397 // Read and check the magic identifier.
1398 auto Magic = readNumber<uint64_t>();
1399 if (std::error_code EC = Magic.getError())
1400 return EC;
1401 else if (std::error_code EC = verifySPMagic(*Magic))
1402 return EC;
1403
1404 // Read the version number.
1405 auto Version = readNumber<uint64_t>();
1406 if (std::error_code EC = Version.getError())
1407 return EC;
1408 else if (*Version != SPVersion())
1409 return sampleprof_error::unsupported_version;
1410
1411 return sampleprof_error::success;
1412}
1413
1414std::error_code SampleProfileReaderBinary::readHeader() {
1415 Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
1416 End = Data + Buffer->getBufferSize();
1417
1418 if (std::error_code EC = readMagicIdent())
1419 return EC;
1420
1421 if (std::error_code EC = readSummary())
1422 return EC;
1423
1424 if (std::error_code EC = readNameTable())
1425 return EC;
1426 return sampleprof_error::success;
1427}
1428
1429std::error_code SampleProfileReaderCompactBinary::readHeader() {
1430 SampleProfileReaderBinary::readHeader();
1431 if (std::error_code EC = readFuncOffsetTable())
1432 return EC;
1433 return sampleprof_error::success;
1434}
1435
1436std::error_code SampleProfileReaderCompactBinary::readFuncOffsetTable() {
1437 auto TableOffset = readUnencodedNumber<uint64_t>();
1438 if (std::error_code EC = TableOffset.getError())
1439 return EC;
1440
1441 const uint8_t *SavedData = Data;
1442 const uint8_t *TableStart =
1443 reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()) +
1444 *TableOffset;
1445 Data = TableStart;
1446
1447 auto Size = readNumber<uint64_t>();
1448 if (std::error_code EC = Size.getError())
1449 return EC;
1450
1451 FuncOffsetTable.reserve(*Size);
1452 for (uint64_t I = 0; I < *Size; ++I) {
1453 auto FName(readStringFromTable());
1454 if (std::error_code EC = FName.getError())
1455 return EC;
1456
1457 auto Offset = readNumber<uint64_t>();
1458 if (std::error_code EC = Offset.getError())
1459 return EC;
1460
1461 FuncOffsetTable[*FName] = *Offset;
1462 }
1463 End = TableStart;
1464 Data = SavedData;
1465 return sampleprof_error::success;
1466}
1467
1468bool SampleProfileReaderCompactBinary::collectFuncsFromModule() {
1469 if (!M)
1470 return false;
1471 FuncsToUse.clear();
1472 for (auto &F : *M)
1473 FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
1474 return true;
1475}
1476
1477std::error_code SampleProfileReaderBinary::readSummaryEntry(
1478 std::vector<ProfileSummaryEntry> &Entries) {
1479 auto Cutoff = readNumber<uint64_t>();
1480 if (std::error_code EC = Cutoff.getError())
1481 return EC;
1482
1483 auto MinBlockCount = readNumber<uint64_t>();
1484 if (std::error_code EC = MinBlockCount.getError())
1485 return EC;
1486
1487 auto NumBlocks = readNumber<uint64_t>();
1488 if (std::error_code EC = NumBlocks.getError())
1489 return EC;
1490
1491 Entries.emplace_back(*Cutoff, *MinBlockCount, *NumBlocks);
1492 return sampleprof_error::success;
1493}
1494
1495std::error_code SampleProfileReaderBinary::readSummary() {
1496 auto TotalCount = readNumber<uint64_t>();
1497 if (std::error_code EC = TotalCount.getError())
1498 return EC;
1499
1500 auto MaxBlockCount = readNumber<uint64_t>();
1501 if (std::error_code EC = MaxBlockCount.getError())
1502 return EC;
1503
1504 auto MaxFunctionCount = readNumber<uint64_t>();
1505 if (std::error_code EC = MaxFunctionCount.getError())
1506 return EC;
1507
1508 auto NumBlocks = readNumber<uint64_t>();
1509 if (std::error_code EC = NumBlocks.getError())
1510 return EC;
1511
1512 auto NumFunctions = readNumber<uint64_t>();
1513 if (std::error_code EC = NumFunctions.getError())
1514 return EC;
1515
1516 auto NumSummaryEntries = readNumber<uint64_t>();
1517 if (std::error_code EC = NumSummaryEntries.getError())
1518 return EC;
1519
1520 std::vector<ProfileSummaryEntry> Entries;
1521 for (unsigned i = 0; i < *NumSummaryEntries; i++) {
1522 std::error_code EC = readSummaryEntry(Entries);
1523 if (EC != sampleprof_error::success)
1524 return EC;
1525 }
1526 Summary = std::make_unique<ProfileSummary>(
1527 ProfileSummary::PSK_Sample, Entries, *TotalCount, *MaxBlockCount, 0,
1528 *MaxFunctionCount, *NumBlocks, *NumFunctions);
1529
1530 return sampleprof_error::success;
1531}
1532
1533bool SampleProfileReaderRawBinary::hasFormat(const MemoryBuffer &Buffer) {
1534 const uint8_t *Data =
1535 reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
1536 uint64_t Magic = decodeULEB128(Data);
1537 return Magic == SPMagic();
1538}
1539
1540bool SampleProfileReaderExtBinary::hasFormat(const MemoryBuffer &Buffer) {
1541 const uint8_t *Data =
1542 reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
1543 uint64_t Magic = decodeULEB128(Data);
1544 return Magic == SPMagic(SPF_Ext_Binary);
1545}
1546
1547bool SampleProfileReaderCompactBinary::hasFormat(const MemoryBuffer &Buffer) {
1548 const uint8_t *Data =
1549 reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
1550 uint64_t Magic = decodeULEB128(Data);
1551 return Magic == SPMagic(SPF_Compact_Binary);
1552}
1553
1554std::error_code SampleProfileReaderGCC::skipNextWord() {
1555 uint32_t dummy;
1556 if (!GcovBuffer.readInt(dummy))
1557 return sampleprof_error::truncated;
1558 return sampleprof_error::success;
1559}
1560
1561template <typename T> ErrorOr<T> SampleProfileReaderGCC::readNumber() {
1562 if (sizeof(T) <= sizeof(uint32_t)) {
1563 uint32_t Val;
1564 if (GcovBuffer.readInt(Val) && Val <= std::numeric_limits<T>::max())
1565 return static_cast<T>(Val);
1566 } else if (sizeof(T) <= sizeof(uint64_t)) {
1567 uint64_t Val;
1568 if (GcovBuffer.readInt64(Val) && Val <= std::numeric_limits<T>::max())
1569 return static_cast<T>(Val);
1570 }
1571
1572 std::error_code EC = sampleprof_error::malformed;
1573 reportError(0, EC.message());
1574 return EC;
1575}
1576
1577ErrorOr<StringRef> SampleProfileReaderGCC::readString() {
1578 StringRef Str;
1579 if (!GcovBuffer.readString(Str))
1580 return sampleprof_error::truncated;
1581 return Str;
1582}
1583
1584std::error_code SampleProfileReaderGCC::readHeader() {
1585 // Read the magic identifier.
1586 if (!GcovBuffer.readGCDAFormat())
1587 return sampleprof_error::unrecognized_format;
1588
1589 // Read the version number. Note - the GCC reader does not validate this
1590 // version, but the profile creator generates v704.
1591 GCOV::GCOVVersion version;
1592 if (!GcovBuffer.readGCOVVersion(version))
1593 return sampleprof_error::unrecognized_format;
1594
1595 if (version != GCOV::V407)
1596 return sampleprof_error::unsupported_version;
1597
1598 // Skip the empty integer.
1599 if (std::error_code EC = skipNextWord())
1600 return EC;
1601
1602 return sampleprof_error::success;
1603}
1604
1605std::error_code SampleProfileReaderGCC::readSectionTag(uint32_t Expected) {
1606 uint32_t Tag;
1607 if (!GcovBuffer.readInt(Tag))
1608 return sampleprof_error::truncated;
1609
1610 if (Tag != Expected)
1611 return sampleprof_error::malformed;
1612
1613 if (std::error_code EC = skipNextWord())
1614 return EC;
1615
1616 return sampleprof_error::success;
1617}
1618
1619std::error_code SampleProfileReaderGCC::readNameTable() {
1620 if (std::error_code EC = readSectionTag(GCOVTagAFDOFileNames))
1621 return EC;
1622
1623 uint32_t Size;
1624 if (!GcovBuffer.readInt(Size))
1625 return sampleprof_error::truncated;
1626
1627 for (uint32_t I = 0; I < Size; ++I) {
1628 StringRef Str;
1629 if (!GcovBuffer.readString(Str))
1630 return sampleprof_error::truncated;
1631 Names.push_back(std::string(Str));
1632 }
1633
1634 return sampleprof_error::success;
1635}
1636
1637std::error_code SampleProfileReaderGCC::readFunctionProfiles() {
1638 if (std::error_code EC = readSectionTag(GCOVTagAFDOFunction))
1639 return EC;
1640
1641 uint32_t NumFunctions;
1642 if (!GcovBuffer.readInt(NumFunctions))
1643 return sampleprof_error::truncated;
1644
1645 InlineCallStack Stack;
1646 for (uint32_t I = 0; I < NumFunctions; ++I)
1647 if (std::error_code EC = readOneFunctionProfile(Stack, true, 0))
1648 return EC;
1649
1650 computeSummary();
1651 return sampleprof_error::success;
1652}
1653
1654std::error_code SampleProfileReaderGCC::readOneFunctionProfile(
1655 const InlineCallStack &InlineStack, bool Update, uint32_t Offset) {
1656 uint64_t HeadCount = 0;
1657 if (InlineStack.size() == 0)
1658 if (!GcovBuffer.readInt64(HeadCount))
1659 return sampleprof_error::truncated;
1660
1661 uint32_t NameIdx;
1662 if (!GcovBuffer.readInt(NameIdx))
1663 return sampleprof_error::truncated;
1664
1665 StringRef Name(Names[NameIdx]);
1666
1667 uint32_t NumPosCounts;
1668 if (!GcovBuffer.readInt(NumPosCounts))
1669 return sampleprof_error::truncated;
1670
1671 uint32_t NumCallsites;
1672 if (!GcovBuffer.readInt(NumCallsites))
1673 return sampleprof_error::truncated;
1674
1675 FunctionSamples *FProfile = nullptr;
1676 if (InlineStack.size() == 0) {
1677 // If this is a top function that we have already processed, do not
1678 // update its profile again. This happens in the presence of
1679 // function aliases. Since these aliases share the same function
1680 // body, there will be identical replicated profiles for the
1681 // original function. In this case, we simply not bother updating
1682 // the profile of the original function.
1683 FProfile = &Profiles[Name];
1684 FProfile->addHeadSamples(HeadCount);
1685 if (FProfile->getTotalSamples() > 0)
1686 Update = false;
1687 } else {
1688 // Otherwise, we are reading an inlined instance. The top of the
1689 // inline stack contains the profile of the caller. Insert this
1690 // callee in the caller's CallsiteMap.
1691 FunctionSamples *CallerProfile = InlineStack.front();
1692 uint32_t LineOffset = Offset >> 16;
1693 uint32_t Discriminator = Offset & 0xffff;
1694 FProfile = &CallerProfile->functionSamplesAt(
1695 LineLocation(LineOffset, Discriminator))[std::string(Name)];
1696 }
1697 FProfile->setName(Name);
1698
1699 for (uint32_t I = 0; I < NumPosCounts; ++I) {
1700 uint32_t Offset;
1701 if (!GcovBuffer.readInt(Offset))
1702 return sampleprof_error::truncated;
1703
1704 uint32_t NumTargets;
1705 if (!GcovBuffer.readInt(NumTargets))
1706 return sampleprof_error::truncated;
1707
1708 uint64_t Count;
1709 if (!GcovBuffer.readInt64(Count))
1710 return sampleprof_error::truncated;
1711
1712 // The line location is encoded in the offset as:
1713 // high 16 bits: line offset to the start of the function.
1714 // low 16 bits: discriminator.
1715 uint32_t LineOffset = Offset >> 16;
1716 uint32_t Discriminator = Offset & 0xffff;
1717
1718 InlineCallStack NewStack;
1719 NewStack.push_back(FProfile);
1720 llvm::append_range(NewStack, InlineStack);
1721 if (Update) {
1722 // Walk up the inline stack, adding the samples on this line to
1723 // the total sample count of the callers in the chain.
1724 for (auto *CallerProfile : NewStack)
1725 CallerProfile->addTotalSamples(Count);
1726
1727 // Update the body samples for the current profile.
1728 FProfile->addBodySamples(LineOffset, Discriminator, Count);
1729 }
1730
1731 // Process the list of functions called at an indirect call site.
1732 // These are all the targets that a function pointer (or virtual
1733 // function) resolved at runtime.
1734 for (uint32_t J = 0; J < NumTargets; J++) {
1735 uint32_t HistVal;
1736 if (!GcovBuffer.readInt(HistVal))
1737 return sampleprof_error::truncated;
1738
1739 if (HistVal != HIST_TYPE_INDIR_CALL_TOPN)
1740 return sampleprof_error::malformed;
1741
1742 uint64_t TargetIdx;
1743 if (!GcovBuffer.readInt64(TargetIdx))
1744 return sampleprof_error::truncated;
1745 StringRef TargetName(Names[TargetIdx]);
1746
1747 uint64_t TargetCount;
1748 if (!GcovBuffer.readInt64(TargetCount))
1749 return sampleprof_error::truncated;
1750
1751 if (Update)
1752 FProfile->addCalledTargetSamples(LineOffset, Discriminator,
1753 TargetName, TargetCount);
1754 }
1755 }
1756
1757 // Process all the inlined callers into the current function. These
1758 // are all the callsites that were inlined into this function.
1759 for (uint32_t I = 0; I < NumCallsites; I++) {
1760 // The offset is encoded as:
1761 // high 16 bits: line offset to the start of the function.
1762 // low 16 bits: discriminator.
1763 uint32_t Offset;
1764 if (!GcovBuffer.readInt(Offset))
1765 return sampleprof_error::truncated;
1766 InlineCallStack NewStack;
1767 NewStack.push_back(FProfile);
1768 llvm::append_range(NewStack, InlineStack);
1769 if (std::error_code EC = readOneFunctionProfile(NewStack, Update, Offset))
1770 return EC;
1771 }
1772
1773 return sampleprof_error::success;
1774}
1775
1776/// Read a GCC AutoFDO profile.
1777///
1778/// This format is generated by the Linux Perf conversion tool at
1779/// https://github.com/google/autofdo.
1780std::error_code SampleProfileReaderGCC::readImpl() {
1781 assert(!ProfileIsFSDisciminator && "Gcc profiles not support FSDisciminator")(static_cast <bool> (!ProfileIsFSDisciminator &&
"Gcc profiles not support FSDisciminator") ? void (0) : __assert_fail
("!ProfileIsFSDisciminator && \"Gcc profiles not support FSDisciminator\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 1781, __extension__
__PRETTY_FUNCTION__))
;
1782 // Read the string table.
1783 if (std::error_code EC = readNameTable())
1784 return EC;
1785
1786 // Read the source profile.
1787 if (std::error_code EC = readFunctionProfiles())
1788 return EC;
1789
1790 return sampleprof_error::success;
1791}
1792
1793bool SampleProfileReaderGCC::hasFormat(const MemoryBuffer &Buffer) {
1794 StringRef Magic(reinterpret_cast<const char *>(Buffer.getBufferStart()));
1795 return Magic == "adcg*704";
1796}
1797
1798void SampleProfileReaderItaniumRemapper::applyRemapping(LLVMContext &Ctx) {
1799 // If the reader uses MD5 to represent string, we can't remap it because
1800 // we don't know what the original function names were.
1801 if (Reader.useMD5()) {
1802 Ctx.diagnose(DiagnosticInfoSampleProfile(
1803 Reader.getBuffer()->getBufferIdentifier(),
1804 "Profile data remapping cannot be applied to profile data "
1805 "in compact format (original mangled names are not available).",
1806 DS_Warning));
1807 return;
1808 }
1809
1810 // CSSPGO-TODO: Remapper is not yet supported.
1811 // We will need to remap the entire context string.
1812 assert(Remappings && "should be initialized while creating remapper")(static_cast <bool> (Remappings && "should be initialized while creating remapper"
) ? void (0) : __assert_fail ("Remappings && \"should be initialized while creating remapper\""
, "llvm/lib/ProfileData/SampleProfReader.cpp", 1812, __extension__
__PRETTY_FUNCTION__))
;
1813 for (auto &Sample : Reader.getProfiles()) {
1814 DenseSet<StringRef> NamesInSample;
1815 Sample.second.findAllNames(NamesInSample);
1816 for (auto &Name : NamesInSample)
1817 if (auto Key = Remappings->insert(Name))
1818 NameMap.insert({Key, Name});
1819 }
1820
1821 RemappingApplied = true;
1822}
1823
1824std::optional<StringRef>
1825SampleProfileReaderItaniumRemapper::lookUpNameInProfile(StringRef Fname) {
1826 if (auto Key = Remappings->lookup(Fname))
1827 return NameMap.lookup(Key);
1828 return std::nullopt;
1829}
1830
1831/// Prepare a memory buffer for the contents of \p Filename.
1832///
1833/// \returns an error code indicating the status of the buffer.
1834static ErrorOr<std::unique_ptr<MemoryBuffer>>
1835setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS) {
1836 auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
1837 : FS.getBufferForFile(Filename);
1838 if (std::error_code EC = BufferOrErr.getError())
1839 return EC;
1840 auto Buffer = std::move(BufferOrErr.get());
1841
1842 return std::move(Buffer);
1843}
1844
1845/// Create a sample profile reader based on the format of the input file.
1846///
1847/// \param Filename The file to open.
1848///
1849/// \param C The LLVM context to use to emit diagnostics.
1850///
1851/// \param P The FSDiscriminatorPass.
1852///
1853/// \param RemapFilename The file used for profile remapping.
1854///
1855/// \returns an error code indicating the status of the created reader.
1856ErrorOr<std::unique_ptr<SampleProfileReader>>
1857SampleProfileReader::create(const std::string Filename, LLVMContext &C,
1858 vfs::FileSystem &FS, FSDiscriminatorPass P,
1859 const std::string RemapFilename) {
1860 auto BufferOrError = setupMemoryBuffer(Filename, FS);
1861 if (std::error_code EC = BufferOrError.getError())
1862 return EC;
1863 return create(BufferOrError.get(), C, FS, P, RemapFilename);
1864}
1865
1866/// Create a sample profile remapper from the given input, to remap the
1867/// function names in the given profile data.
1868///
1869/// \param Filename The file to open.
1870///
1871/// \param Reader The profile reader the remapper is going to be applied to.
1872///
1873/// \param C The LLVM context to use to emit diagnostics.
1874///
1875/// \returns an error code indicating the status of the created reader.
1876ErrorOr<std::unique_ptr<SampleProfileReaderItaniumRemapper>>
1877SampleProfileReaderItaniumRemapper::create(const std::string Filename,
1878 vfs::FileSystem &FS,
1879 SampleProfileReader &Reader,
1880 LLVMContext &C) {
1881 auto BufferOrError = setupMemoryBuffer(Filename, FS);
1882 if (std::error_code EC = BufferOrError.getError())
1883 return EC;
1884 return create(BufferOrError.get(), Reader, C);
1885}
1886
1887/// Create a sample profile remapper from the given input, to remap the
1888/// function names in the given profile data.
1889///
1890/// \param B The memory buffer to create the reader from (assumes ownership).
1891///
1892/// \param C The LLVM context to use to emit diagnostics.
1893///
1894/// \param Reader The profile reader the remapper is going to be applied to.
1895///
1896/// \returns an error code indicating the status of the created reader.
1897ErrorOr<std::unique_ptr<SampleProfileReaderItaniumRemapper>>
1898SampleProfileReaderItaniumRemapper::create(std::unique_ptr<MemoryBuffer> &B,
1899 SampleProfileReader &Reader,
1900 LLVMContext &C) {
1901 auto Remappings = std::make_unique<SymbolRemappingReader>();
1902 if (Error E = Remappings->read(*B)) {
1903 handleAllErrors(
1904 std::move(E), [&](const SymbolRemappingParseError &ParseError) {
1905 C.diagnose(DiagnosticInfoSampleProfile(B->getBufferIdentifier(),
1906 ParseError.getLineNum(),
1907 ParseError.getMessage()));
1908 });
1909 return sampleprof_error::malformed;
1910 }
1911
1912 return std::make_unique<SampleProfileReaderItaniumRemapper>(
1913 std::move(B), std::move(Remappings), Reader);
1914}
1915
1916/// Create a sample profile reader based on the format of the input data.
1917///
1918/// \param B The memory buffer to create the reader from (assumes ownership).
1919///
1920/// \param C The LLVM context to use to emit diagnostics.
1921///
1922/// \param P The FSDiscriminatorPass.
1923///
1924/// \param RemapFilename The file used for profile remapping.
1925///
1926/// \returns an error code indicating the status of the created reader.
1927ErrorOr<std::unique_ptr<SampleProfileReader>>
1928SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C,
1929 vfs::FileSystem &FS, FSDiscriminatorPass P,
1930 const std::string RemapFilename) {
1931 std::unique_ptr<SampleProfileReader> Reader;
1932 if (SampleProfileReaderRawBinary::hasFormat(*B))
1933 Reader.reset(new SampleProfileReaderRawBinary(std::move(B), C));
1934 else if (SampleProfileReaderExtBinary::hasFormat(*B))
1935 Reader.reset(new SampleProfileReaderExtBinary(std::move(B), C));
1936 else if (SampleProfileReaderCompactBinary::hasFormat(*B))
1937 Reader.reset(new SampleProfileReaderCompactBinary(std::move(B), C));
1938 else if (SampleProfileReaderGCC::hasFormat(*B))
1939 Reader.reset(new SampleProfileReaderGCC(std::move(B), C));
1940 else if (SampleProfileReaderText::hasFormat(*B))
1941 Reader.reset(new SampleProfileReaderText(std::move(B), C));
1942 else
1943 return sampleprof_error::unrecognized_format;
1944
1945 if (!RemapFilename.empty()) {
1946 auto ReaderOrErr = SampleProfileReaderItaniumRemapper::create(
1947 RemapFilename, FS, *Reader, C);
1948 if (std::error_code EC = ReaderOrErr.getError()) {
1949 std::string Msg = "Could not create remapper: " + EC.message();
1950 C.diagnose(DiagnosticInfoSampleProfile(RemapFilename, Msg));
1951 return EC;
1952 }
1953 Reader->Remapper = std::move(ReaderOrErr.get());
1954 }
1955
1956 if (std::error_code EC = Reader->readHeader()) {
1957 return EC;
1958 }
1959
1960 Reader->setDiscriminatorMaskedBitFrom(P);
1961
1962 return std::move(Reader);
1963}
1964
1965// For text and GCC file formats, we compute the summary after reading the
1966// profile. Binary format has the profile summary in its header.
1967void SampleProfileReader::computeSummary() {
1968 SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
1969 Summary = Builder.computeSummaryForProfiles(Profiles);
1970}