Bug Summary

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