LLVM 17.0.0git
StackMapParser.h
Go to the documentation of this file.
1//===- StackMapParser.h - StackMap Parsing Support --------------*- C++ -*-===//
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#ifndef LLVM_OBJECT_STACKMAPPARSER_H
10#define LLVM_OBJECT_STACKMAPPARSER_H
11
12#include "llvm/ADT/ArrayRef.h"
14#include "llvm/Object/ELF.h"
15#include "llvm/Support/Endian.h"
16#include <cassert>
17#include <cstddef>
18#include <cstdint>
19#include <vector>
20
21namespace llvm {
22
23/// A parser for the latest stackmap format. At the moment, latest=V3.
24template <support::endianness Endianness>
26public:
27 template <typename AccessorT>
29 public:
30 AccessorIterator(AccessorT A) : A(A) {}
31
32 AccessorIterator& operator++() { A = A.next(); return *this; }
34 auto tmp = *this;
35 ++*this;
36 return tmp;
37 }
38
39 bool operator==(const AccessorIterator &Other) const {
40 return A.P == Other.A.P;
41 }
42
43 bool operator!=(const AccessorIterator &Other) const {
44 return !(*this == Other);
45 }
46
47 AccessorT& operator*() { return A; }
48 AccessorT* operator->() { return &A; }
49
50 private:
51 AccessorT A;
52 };
53
54 /// Accessor for function records.
56 friend class StackMapParser;
57
58 public:
59 /// Get the function address.
61 return read<uint64_t>(P);
62 }
63
64 /// Get the function's stack size.
66 return read<uint64_t>(P + sizeof(uint64_t));
67 }
68
69 /// Get the number of callsite records.
71 return read<uint64_t>(P + (2 * sizeof(uint64_t)));
72 }
73
74 private:
75 FunctionAccessor(const uint8_t *P) : P(P) {}
76
77 const static int FunctionAccessorSize = 3 * sizeof(uint64_t);
78
79 FunctionAccessor next() const {
80 return FunctionAccessor(P + FunctionAccessorSize);
81 }
82
83 const uint8_t *P;
84 };
85
86 /// Accessor for constants.
88 friend class StackMapParser;
89
90 public:
91 /// Return the value of this constant.
92 uint64_t getValue() const { return read<uint64_t>(P); }
93
94 private:
95 ConstantAccessor(const uint8_t *P) : P(P) {}
96
97 const static int ConstantAccessorSize = sizeof(uint64_t);
98
99 ConstantAccessor next() const {
100 return ConstantAccessor(P + ConstantAccessorSize);
101 }
102
103 const uint8_t *P;
104 };
105
106 enum class LocationKind : uint8_t {
107 Register = 1, Direct = 2, Indirect = 3, Constant = 4, ConstantIndex = 5
108 };
109
110 /// Accessor for location records.
112 friend class StackMapParser;
113 friend class RecordAccessor;
114
115 public:
116 /// Get the Kind for this location.
118 return LocationKind(P[KindOffset]);
119 }
120
121 /// Get the Size for this location.
122 unsigned getSizeInBytes() const {
123 return read<uint16_t>(P + SizeOffset);
124
125 }
126
127 /// Get the Dwarf register number for this location.
129 return read<uint16_t>(P + DwarfRegNumOffset);
130 }
131
132 /// Get the small-constant for this location. (Kind must be Constant).
134 assert(getKind() == LocationKind::Constant && "Not a small constant.");
135 return read<uint32_t>(P + SmallConstantOffset);
136 }
137
138 /// Get the constant-index for this location. (Kind must be ConstantIndex).
141 "Not a constant-index.");
142 return read<uint32_t>(P + SmallConstantOffset);
143 }
144
145 /// Get the offset for this location. (Kind must be Direct or Indirect).
146 int32_t getOffset() const {
149 "Not direct or indirect.");
150 return read<int32_t>(P + SmallConstantOffset);
151 }
152
153 private:
154 LocationAccessor(const uint8_t *P) : P(P) {}
155
156 LocationAccessor next() const {
157 return LocationAccessor(P + LocationAccessorSize);
158 }
159
160 static const int KindOffset = 0;
161 static const int SizeOffset = KindOffset + sizeof(uint16_t);
162 static const int DwarfRegNumOffset = SizeOffset + sizeof(uint16_t);
163 static const int SmallConstantOffset = DwarfRegNumOffset + sizeof(uint32_t);
164 static const int LocationAccessorSize = sizeof(uint64_t) + sizeof(uint32_t);
165
166 const uint8_t *P;
167 };
168
169 /// Accessor for stackmap live-out fields.
171 friend class StackMapParser;
172 friend class RecordAccessor;
173
174 public:
175 /// Get the Dwarf register number for this live-out.
177 return read<uint16_t>(P + DwarfRegNumOffset);
178 }
179
180 /// Get the size in bytes of live [sub]register.
181 unsigned getSizeInBytes() const {
182 return read<uint8_t>(P + SizeOffset);
183 }
184
185 private:
186 LiveOutAccessor(const uint8_t *P) : P(P) {}
187
188 LiveOutAccessor next() const {
189 return LiveOutAccessor(P + LiveOutAccessorSize);
190 }
191
192 static const int DwarfRegNumOffset = 0;
193 static const int SizeOffset =
194 DwarfRegNumOffset + sizeof(uint16_t) + sizeof(uint8_t);
195 static const int LiveOutAccessorSize = sizeof(uint32_t);
196
197 const uint8_t *P;
198 };
199
200 /// Accessor for stackmap records.
202 friend class StackMapParser;
203
204 public:
207
208 /// Get the patchpoint/stackmap ID for this record.
209 uint64_t getID() const {
210 return read<uint64_t>(P + PatchpointIDOffset);
211 }
212
213 /// Get the instruction offset (from the start of the containing function)
214 /// for this record.
216 return read<uint32_t>(P + InstructionOffsetOffset);
217 }
218
219 /// Get the number of locations contained in this record.
221 return read<uint16_t>(P + NumLocationsOffset);
222 }
223
224 /// Get the location with the given index.
225 LocationAccessor getLocation(unsigned LocationIndex) const {
226 unsigned LocationOffset =
227 LocationListOffset + LocationIndex * LocationSize;
228 return LocationAccessor(P + LocationOffset);
229 }
230
231 /// Begin iterator for locations.
234 }
235
236 /// End iterator for locations.
239 }
240
241 /// Iterator range for locations.
244 }
245
246 /// Get the number of liveouts contained in this record.
248 return read<uint16_t>(P + getNumLiveOutsOffset());
249 }
250
251 /// Get the live-out with the given index.
252 LiveOutAccessor getLiveOut(unsigned LiveOutIndex) const {
253 unsigned LiveOutOffset =
254 getNumLiveOutsOffset() + sizeof(uint16_t) + LiveOutIndex * LiveOutSize;
255 return LiveOutAccessor(P + LiveOutOffset);
256 }
257
258 /// Begin iterator for live-outs.
260 return liveout_iterator(getLiveOut(0));
261 }
262
263 /// End iterator for live-outs.
266 }
267
268 /// Iterator range for live-outs.
271 }
272
273 private:
274 RecordAccessor(const uint8_t *P) : P(P) {}
275
276 unsigned getNumLiveOutsOffset() const {
277 unsigned LocOffset =
278 ((LocationListOffset + LocationSize * getNumLocations()) + 7) & ~0x7;
279 return LocOffset + sizeof(uint16_t);
280 }
281
282 unsigned getSizeInBytes() const {
283 unsigned RecordSize =
284 getNumLiveOutsOffset() + sizeof(uint16_t) + getNumLiveOuts() * LiveOutSize;
285 return (RecordSize + 7) & ~0x7;
286 }
287
288 RecordAccessor next() const {
289 return RecordAccessor(P + getSizeInBytes());
290 }
291
292 static const unsigned PatchpointIDOffset = 0;
293 static const unsigned InstructionOffsetOffset =
294 PatchpointIDOffset + sizeof(uint64_t);
295 static const unsigned NumLocationsOffset =
296 InstructionOffsetOffset + sizeof(uint32_t) + sizeof(uint16_t);
297 static const unsigned LocationListOffset =
298 NumLocationsOffset + sizeof(uint16_t);
299 static const unsigned LocationSize = sizeof(uint64_t) + sizeof(uint32_t);
300 static const unsigned LiveOutSize = sizeof(uint32_t);
301
302 const uint8_t *P;
303 };
304
305 /// Construct a parser for a version-3 stackmap. StackMap data will be read
306 /// from the given array.
308 : StackMapSection(StackMapSection) {
309 ConstantsListOffset = FunctionListOffset + getNumFunctions() * FunctionSize;
310
311 assert(StackMapSection[0] == 3 &&
312 "StackMapParser can only parse version 3 stackmaps");
313
314 unsigned CurrentRecordOffset =
315 ConstantsListOffset + getNumConstants() * ConstantSize;
316
317 for (unsigned I = 0, E = getNumRecords(); I != E; ++I) {
318 StackMapRecordOffsets.push_back(CurrentRecordOffset);
319 CurrentRecordOffset +=
320 RecordAccessor(&StackMapSection[CurrentRecordOffset]).getSizeInBytes();
321 }
322 }
323
324 /// Validates the header of the specified stack map section.
325 static Error validateHeader(ArrayRef<uint8_t> StackMapSection) {
326 // See the comment for StackMaps::emitStackmapHeader().
327 if (StackMapSection.size() < 16)
328 return object::createError(
329 "the stack map section size (" + Twine(StackMapSection.size()) +
330 ") is less than the minimum possible size of its header (16)");
331
332 unsigned Version = StackMapSection[0];
333 if (Version != 3)
334 return object::createError(
335 "the version (" + Twine(Version) +
336 ") of the stack map section is unsupported, the "
337 "supported version is 3");
338 return Error::success();
339 }
340
344
345 /// Get the version number of this stackmap. (Always returns 3).
346 unsigned getVersion() const { return 3; }
347
348 /// Get the number of functions in the stack map.
350 return read<uint32_t>(&StackMapSection[NumFunctionsOffset]);
351 }
352
353 /// Get the number of large constants in the stack map.
355 return read<uint32_t>(&StackMapSection[NumConstantsOffset]);
356 }
357
358 /// Get the number of stackmap records in the stackmap.
360 return read<uint32_t>(&StackMapSection[NumRecordsOffset]);
361 }
362
363 /// Return an FunctionAccessor for the given function index.
364 FunctionAccessor getFunction(unsigned FunctionIndex) const {
365 return FunctionAccessor(StackMapSection.data() +
366 getFunctionOffset(FunctionIndex));
367 }
368
369 /// Begin iterator for functions.
372 }
373
374 /// End iterator for functions.
376 return function_iterator(
377 FunctionAccessor(StackMapSection.data() +
378 getFunctionOffset(getNumFunctions())));
379 }
380
381 /// Iterator range for functions.
384 }
385
386 /// Return the large constant at the given index.
388 return ConstantAccessor(StackMapSection.data() +
389 getConstantOffset(ConstantIndex));
390 }
391
392 /// Begin iterator for constants.
395 }
396
397 /// End iterator for constants.
399 return constant_iterator(
400 ConstantAccessor(StackMapSection.data() +
401 getConstantOffset(getNumConstants())));
402 }
403
404 /// Iterator range for constants.
407 }
408
409 /// Return a RecordAccessor for the given record index.
410 RecordAccessor getRecord(unsigned RecordIndex) const {
411 std::size_t RecordOffset = StackMapRecordOffsets[RecordIndex];
412 return RecordAccessor(StackMapSection.data() + RecordOffset);
413 }
414
415 /// Begin iterator for records.
417 if (getNumRecords() == 0)
418 return record_iterator(RecordAccessor(nullptr));
419 return record_iterator(getRecord(0));
420 }
421
422 /// End iterator for records.
424 // Records need to be handled specially, since we cache the start addresses
425 // for them: We can't just compute the 1-past-the-end address, we have to
426 // look at the last record and use the 'next' method.
427 if (getNumRecords() == 0)
428 return record_iterator(RecordAccessor(nullptr));
429 return record_iterator(getRecord(getNumRecords() - 1).next());
430 }
431
432 /// Iterator range for records.
435 }
436
437private:
438 template <typename T>
439 static T read(const uint8_t *P) {
440 return support::endian::read<T, Endianness, 1>(P);
441 }
442
443 static const unsigned HeaderOffset = 0;
444 static const unsigned NumFunctionsOffset = HeaderOffset + sizeof(uint32_t);
445 static const unsigned NumConstantsOffset = NumFunctionsOffset + sizeof(uint32_t);
446 static const unsigned NumRecordsOffset = NumConstantsOffset + sizeof(uint32_t);
447 static const unsigned FunctionListOffset = NumRecordsOffset + sizeof(uint32_t);
448
449 static const unsigned FunctionSize = 3 * sizeof(uint64_t);
450 static const unsigned ConstantSize = sizeof(uint64_t);
451
452 std::size_t getFunctionOffset(unsigned FunctionIndex) const {
453 return FunctionListOffset + FunctionIndex * FunctionSize;
454 }
455
456 std::size_t getConstantOffset(unsigned ConstantIndex) const {
457 return ConstantsListOffset + ConstantIndex * ConstantSize;
458 }
459
460 ArrayRef<uint8_t> StackMapSection;
461 unsigned ConstantsListOffset;
462 std::vector<unsigned> StackMapRecordOffsets;
463};
464
465} // end namespace llvm
466
467#endif // LLVM_OBJECT_STACKMAPPARSER_H
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define I(x, y, z)
Definition: MD5.cpp:58
static std::optional< uint64_t > getSizeInBytes(std::optional< uint64_t > SizeInBits)
#define P(N)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:163
const T * data() const
Definition: ArrayRef.h:160
This is an important base class in LLVM.
Definition: Constant.h:41
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
static ErrorSuccess success()
Create a success value.
Definition: Error.h:330
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
bool operator==(const AccessorIterator &Other) const
bool operator!=(const AccessorIterator &Other) const
uint64_t getValue() const
Return the value of this constant.
Accessor for function records.
uint64_t getRecordCount() const
Get the number of callsite records.
uint64_t getFunctionAddress() const
Get the function address.
uint64_t getStackSize() const
Get the function's stack size.
Accessor for stackmap live-out fields.
uint16_t getDwarfRegNum() const
Get the Dwarf register number for this live-out.
unsigned getSizeInBytes() const
Get the size in bytes of live [sub]register.
Accessor for location records.
unsigned getSizeInBytes() const
Get the Size for this location.
uint16_t getDwarfRegNum() const
Get the Dwarf register number for this location.
LocationKind getKind() const
Get the Kind for this location.
int32_t getOffset() const
Get the offset for this location. (Kind must be Direct or Indirect).
uint32_t getConstantIndex() const
Get the constant-index for this location. (Kind must be ConstantIndex).
uint32_t getSmallConstant() const
Get the small-constant for this location. (Kind must be Constant).
Accessor for stackmap records.
iterator_range< liveout_iterator > liveouts() const
Iterator range for live-outs.
uint16_t getNumLocations() const
Get the number of locations contained in this record.
LocationAccessor getLocation(unsigned LocationIndex) const
Get the location with the given index.
uint32_t getInstructionOffset() const
Get the instruction offset (from the start of the containing function) for this record.
liveout_iterator liveouts_end() const
End iterator for live-outs.
iterator_range< location_iterator > locations() const
Iterator range for locations.
LiveOutAccessor getLiveOut(unsigned LiveOutIndex) const
Get the live-out with the given index.
AccessorIterator< LiveOutAccessor > liveout_iterator
AccessorIterator< LocationAccessor > location_iterator
location_iterator location_begin() const
Begin iterator for locations.
uint64_t getID() const
Get the patchpoint/stackmap ID for this record.
uint16_t getNumLiveOuts() const
Get the number of liveouts contained in this record.
liveout_iterator liveouts_begin() const
Begin iterator for live-outs.
location_iterator location_end() const
End iterator for locations.
A parser for the latest stackmap format. At the moment, latest=V3.
constant_iterator constants_end() const
End iterator for constants.
record_iterator records_end() const
End iterator for records.
FunctionAccessor getFunction(unsigned FunctionIndex) const
Return an FunctionAccessor for the given function index.
AccessorIterator< FunctionAccessor > function_iterator
AccessorIterator< ConstantAccessor > constant_iterator
function_iterator functions_end() const
End iterator for functions.
iterator_range< record_iterator > records() const
Iterator range for records.
iterator_range< constant_iterator > constants() const
Iterator range for constants.
unsigned getVersion() const
Get the version number of this stackmap. (Always returns 3).
uint32_t getNumConstants() const
Get the number of large constants in the stack map.
function_iterator functions_begin() const
Begin iterator for functions.
record_iterator records_begin() const
Begin iterator for records.
uint32_t getNumRecords() const
Get the number of stackmap records in the stackmap.
constant_iterator constants_begin() const
Begin iterator for constants.
iterator_range< function_iterator > functions() const
Iterator range for functions.
AccessorIterator< RecordAccessor > record_iterator
ConstantAccessor getConstant(unsigned ConstantIndex) const
Return the large constant at the given index.
StackMapParser(ArrayRef< uint8_t > StackMapSection)
Construct a parser for a version-3 stackmap.
RecordAccessor getRecord(unsigned RecordIndex) const
Return a RecordAccessor for the given record index.
static Error validateHeader(ArrayRef< uint8_t > StackMapSection)
Validates the header of the specified stack map section.
uint32_t getNumFunctions() const
Get the number of functions in the stack map.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
A range adaptor for a pair of iterators.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
Error createError(const Twine &Err)
Definition: Error.h:84
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.