File indexing completed on 2026-05-10 08:44:20
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LLVM_OBJECT_STACKMAPPARSER_H
0010 #define LLVM_OBJECT_STACKMAPPARSER_H
0011
0012 #include "llvm/ADT/ArrayRef.h"
0013 #include "llvm/ADT/iterator_range.h"
0014 #include "llvm/Object/ELF.h"
0015 #include "llvm/Support/Endian.h"
0016 #include <cassert>
0017 #include <cstddef>
0018 #include <cstdint>
0019 #include <vector>
0020
0021 namespace llvm {
0022
0023
0024 template <llvm::endianness Endianness> class StackMapParser {
0025 public:
0026 template <typename AccessorT>
0027 class AccessorIterator {
0028 public:
0029 AccessorIterator(AccessorT A) : A(A) {}
0030
0031 AccessorIterator& operator++() { A = A.next(); return *this; }
0032 AccessorIterator operator++(int) {
0033 auto tmp = *this;
0034 ++*this;
0035 return tmp;
0036 }
0037
0038 bool operator==(const AccessorIterator &Other) const {
0039 return A.P == Other.A.P;
0040 }
0041
0042 bool operator!=(const AccessorIterator &Other) const {
0043 return !(*this == Other);
0044 }
0045
0046 AccessorT& operator*() { return A; }
0047 AccessorT* operator->() { return &A; }
0048
0049 private:
0050 AccessorT A;
0051 };
0052
0053
0054 class FunctionAccessor {
0055 friend class StackMapParser;
0056
0057 public:
0058
0059 uint64_t getFunctionAddress() const {
0060 return read<uint64_t>(P);
0061 }
0062
0063
0064 uint64_t getStackSize() const {
0065 return read<uint64_t>(P + sizeof(uint64_t));
0066 }
0067
0068
0069 uint64_t getRecordCount() const {
0070 return read<uint64_t>(P + (2 * sizeof(uint64_t)));
0071 }
0072
0073 private:
0074 FunctionAccessor(const uint8_t *P) : P(P) {}
0075
0076 const static int FunctionAccessorSize = 3 * sizeof(uint64_t);
0077
0078 FunctionAccessor next() const {
0079 return FunctionAccessor(P + FunctionAccessorSize);
0080 }
0081
0082 const uint8_t *P;
0083 };
0084
0085
0086 class ConstantAccessor {
0087 friend class StackMapParser;
0088
0089 public:
0090
0091 uint64_t getValue() const { return read<uint64_t>(P); }
0092
0093 private:
0094 ConstantAccessor(const uint8_t *P) : P(P) {}
0095
0096 const static int ConstantAccessorSize = sizeof(uint64_t);
0097
0098 ConstantAccessor next() const {
0099 return ConstantAccessor(P + ConstantAccessorSize);
0100 }
0101
0102 const uint8_t *P;
0103 };
0104
0105 enum class LocationKind : uint8_t {
0106 Register = 1, Direct = 2, Indirect = 3, Constant = 4, ConstantIndex = 5
0107 };
0108
0109
0110 class LocationAccessor {
0111 friend class StackMapParser;
0112 friend class RecordAccessor;
0113
0114 public:
0115
0116 LocationKind getKind() const {
0117 return LocationKind(P[KindOffset]);
0118 }
0119
0120
0121 unsigned getSizeInBytes() const {
0122 return read<uint16_t>(P + SizeOffset);
0123
0124 }
0125
0126
0127 uint16_t getDwarfRegNum() const {
0128 return read<uint16_t>(P + DwarfRegNumOffset);
0129 }
0130
0131
0132 uint32_t getSmallConstant() const {
0133 assert(getKind() == LocationKind::Constant && "Not a small constant.");
0134 return read<uint32_t>(P + SmallConstantOffset);
0135 }
0136
0137
0138 uint32_t getConstantIndex() const {
0139 assert(getKind() == LocationKind::ConstantIndex &&
0140 "Not a constant-index.");
0141 return read<uint32_t>(P + SmallConstantOffset);
0142 }
0143
0144
0145 int32_t getOffset() const {
0146 assert((getKind() == LocationKind::Direct ||
0147 getKind() == LocationKind::Indirect) &&
0148 "Not direct or indirect.");
0149 return read<int32_t>(P + SmallConstantOffset);
0150 }
0151
0152 private:
0153 LocationAccessor(const uint8_t *P) : P(P) {}
0154
0155 LocationAccessor next() const {
0156 return LocationAccessor(P + LocationAccessorSize);
0157 }
0158
0159 static const int KindOffset = 0;
0160 static const int SizeOffset = KindOffset + sizeof(uint16_t);
0161 static const int DwarfRegNumOffset = SizeOffset + sizeof(uint16_t);
0162 static const int SmallConstantOffset = DwarfRegNumOffset + sizeof(uint32_t);
0163 static const int LocationAccessorSize = sizeof(uint64_t) + sizeof(uint32_t);
0164
0165 const uint8_t *P;
0166 };
0167
0168
0169 class LiveOutAccessor {
0170 friend class StackMapParser;
0171 friend class RecordAccessor;
0172
0173 public:
0174
0175 uint16_t getDwarfRegNum() const {
0176 return read<uint16_t>(P + DwarfRegNumOffset);
0177 }
0178
0179
0180 unsigned getSizeInBytes() const {
0181 return read<uint8_t>(P + SizeOffset);
0182 }
0183
0184 private:
0185 LiveOutAccessor(const uint8_t *P) : P(P) {}
0186
0187 LiveOutAccessor next() const {
0188 return LiveOutAccessor(P + LiveOutAccessorSize);
0189 }
0190
0191 static const int DwarfRegNumOffset = 0;
0192 static const int SizeOffset =
0193 DwarfRegNumOffset + sizeof(uint16_t) + sizeof(uint8_t);
0194 static const int LiveOutAccessorSize = sizeof(uint32_t);
0195
0196 const uint8_t *P;
0197 };
0198
0199
0200 class RecordAccessor {
0201 friend class StackMapParser;
0202
0203 public:
0204 using location_iterator = AccessorIterator<LocationAccessor>;
0205 using liveout_iterator = AccessorIterator<LiveOutAccessor>;
0206
0207
0208 uint64_t getID() const {
0209 return read<uint64_t>(P + PatchpointIDOffset);
0210 }
0211
0212
0213
0214 uint32_t getInstructionOffset() const {
0215 return read<uint32_t>(P + InstructionOffsetOffset);
0216 }
0217
0218
0219 uint16_t getNumLocations() const {
0220 return read<uint16_t>(P + NumLocationsOffset);
0221 }
0222
0223
0224 LocationAccessor getLocation(unsigned LocationIndex) const {
0225 unsigned LocationOffset =
0226 LocationListOffset + LocationIndex * LocationSize;
0227 return LocationAccessor(P + LocationOffset);
0228 }
0229
0230
0231 location_iterator location_begin() const {
0232 return location_iterator(getLocation(0));
0233 }
0234
0235
0236 location_iterator location_end() const {
0237 return location_iterator(getLocation(getNumLocations()));
0238 }
0239
0240
0241 iterator_range<location_iterator> locations() const {
0242 return make_range(location_begin(), location_end());
0243 }
0244
0245
0246 uint16_t getNumLiveOuts() const {
0247 return read<uint16_t>(P + getNumLiveOutsOffset());
0248 }
0249
0250
0251 LiveOutAccessor getLiveOut(unsigned LiveOutIndex) const {
0252 unsigned LiveOutOffset =
0253 getNumLiveOutsOffset() + sizeof(uint16_t) + LiveOutIndex * LiveOutSize;
0254 return LiveOutAccessor(P + LiveOutOffset);
0255 }
0256
0257
0258 liveout_iterator liveouts_begin() const {
0259 return liveout_iterator(getLiveOut(0));
0260 }
0261
0262
0263 liveout_iterator liveouts_end() const {
0264 return liveout_iterator(getLiveOut(getNumLiveOuts()));
0265 }
0266
0267
0268 iterator_range<liveout_iterator> liveouts() const {
0269 return make_range(liveouts_begin(), liveouts_end());
0270 }
0271
0272 private:
0273 RecordAccessor(const uint8_t *P) : P(P) {}
0274
0275 unsigned getNumLiveOutsOffset() const {
0276 unsigned LocOffset =
0277 ((LocationListOffset + LocationSize * getNumLocations()) + 7) & ~0x7;
0278 return LocOffset + sizeof(uint16_t);
0279 }
0280
0281 unsigned getSizeInBytes() const {
0282 unsigned RecordSize =
0283 getNumLiveOutsOffset() + sizeof(uint16_t) + getNumLiveOuts() * LiveOutSize;
0284 return (RecordSize + 7) & ~0x7;
0285 }
0286
0287 RecordAccessor next() const {
0288 return RecordAccessor(P + getSizeInBytes());
0289 }
0290
0291 static const unsigned PatchpointIDOffset = 0;
0292 static const unsigned InstructionOffsetOffset =
0293 PatchpointIDOffset + sizeof(uint64_t);
0294 static const unsigned NumLocationsOffset =
0295 InstructionOffsetOffset + sizeof(uint32_t) + sizeof(uint16_t);
0296 static const unsigned LocationListOffset =
0297 NumLocationsOffset + sizeof(uint16_t);
0298 static const unsigned LocationSize = sizeof(uint64_t) + sizeof(uint32_t);
0299 static const unsigned LiveOutSize = sizeof(uint32_t);
0300
0301 const uint8_t *P;
0302 };
0303
0304
0305
0306 StackMapParser(ArrayRef<uint8_t> StackMapSection)
0307 : StackMapSection(StackMapSection) {
0308 ConstantsListOffset = FunctionListOffset + getNumFunctions() * FunctionSize;
0309
0310 assert(StackMapSection[0] == 3 &&
0311 "StackMapParser can only parse version 3 stackmaps");
0312
0313 unsigned CurrentRecordOffset =
0314 ConstantsListOffset + getNumConstants() * ConstantSize;
0315
0316 for (unsigned I = 0, E = getNumRecords(); I != E; ++I) {
0317 StackMapRecordOffsets.push_back(CurrentRecordOffset);
0318 CurrentRecordOffset +=
0319 RecordAccessor(&StackMapSection[CurrentRecordOffset]).getSizeInBytes();
0320 }
0321 }
0322
0323
0324 static Error validateHeader(ArrayRef<uint8_t> StackMapSection) {
0325
0326 if (StackMapSection.size() < 16)
0327 return object::createError(
0328 "the stack map section size (" + Twine(StackMapSection.size()) +
0329 ") is less than the minimum possible size of its header (16)");
0330
0331 unsigned Version = StackMapSection[0];
0332 if (Version != 3)
0333 return object::createError(
0334 "the version (" + Twine(Version) +
0335 ") of the stack map section is unsupported, the "
0336 "supported version is 3");
0337 return Error::success();
0338 }
0339
0340 using function_iterator = AccessorIterator<FunctionAccessor>;
0341 using constant_iterator = AccessorIterator<ConstantAccessor>;
0342 using record_iterator = AccessorIterator<RecordAccessor>;
0343
0344
0345 unsigned getVersion() const { return 3; }
0346
0347
0348 uint32_t getNumFunctions() const {
0349 return read<uint32_t>(&StackMapSection[NumFunctionsOffset]);
0350 }
0351
0352
0353 uint32_t getNumConstants() const {
0354 return read<uint32_t>(&StackMapSection[NumConstantsOffset]);
0355 }
0356
0357
0358 uint32_t getNumRecords() const {
0359 return read<uint32_t>(&StackMapSection[NumRecordsOffset]);
0360 }
0361
0362
0363 FunctionAccessor getFunction(unsigned FunctionIndex) const {
0364 return FunctionAccessor(StackMapSection.data() +
0365 getFunctionOffset(FunctionIndex));
0366 }
0367
0368
0369 function_iterator functions_begin() const {
0370 return function_iterator(getFunction(0));
0371 }
0372
0373
0374 function_iterator functions_end() const {
0375 return function_iterator(
0376 FunctionAccessor(StackMapSection.data() +
0377 getFunctionOffset(getNumFunctions())));
0378 }
0379
0380
0381 iterator_range<function_iterator> functions() const {
0382 return make_range(functions_begin(), functions_end());
0383 }
0384
0385
0386 ConstantAccessor getConstant(unsigned ConstantIndex) const {
0387 return ConstantAccessor(StackMapSection.data() +
0388 getConstantOffset(ConstantIndex));
0389 }
0390
0391
0392 constant_iterator constants_begin() const {
0393 return constant_iterator(getConstant(0));
0394 }
0395
0396
0397 constant_iterator constants_end() const {
0398 return constant_iterator(
0399 ConstantAccessor(StackMapSection.data() +
0400 getConstantOffset(getNumConstants())));
0401 }
0402
0403
0404 iterator_range<constant_iterator> constants() const {
0405 return make_range(constants_begin(), constants_end());
0406 }
0407
0408
0409 RecordAccessor getRecord(unsigned RecordIndex) const {
0410 std::size_t RecordOffset = StackMapRecordOffsets[RecordIndex];
0411 return RecordAccessor(StackMapSection.data() + RecordOffset);
0412 }
0413
0414
0415 record_iterator records_begin() const {
0416 if (getNumRecords() == 0)
0417 return record_iterator(RecordAccessor(nullptr));
0418 return record_iterator(getRecord(0));
0419 }
0420
0421
0422 record_iterator records_end() const {
0423
0424
0425
0426 if (getNumRecords() == 0)
0427 return record_iterator(RecordAccessor(nullptr));
0428 return record_iterator(getRecord(getNumRecords() - 1).next());
0429 }
0430
0431
0432 iterator_range<record_iterator> records() const {
0433 return make_range(records_begin(), records_end());
0434 }
0435
0436 private:
0437 template <typename T>
0438 static T read(const uint8_t *P) {
0439 return support::endian::read<T, Endianness>(P);
0440 }
0441
0442 static const unsigned HeaderOffset = 0;
0443 static const unsigned NumFunctionsOffset = HeaderOffset + sizeof(uint32_t);
0444 static const unsigned NumConstantsOffset = NumFunctionsOffset + sizeof(uint32_t);
0445 static const unsigned NumRecordsOffset = NumConstantsOffset + sizeof(uint32_t);
0446 static const unsigned FunctionListOffset = NumRecordsOffset + sizeof(uint32_t);
0447
0448 static const unsigned FunctionSize = 3 * sizeof(uint64_t);
0449 static const unsigned ConstantSize = sizeof(uint64_t);
0450
0451 std::size_t getFunctionOffset(unsigned FunctionIndex) const {
0452 return FunctionListOffset + FunctionIndex * FunctionSize;
0453 }
0454
0455 std::size_t getConstantOffset(unsigned ConstantIndex) const {
0456 return ConstantsListOffset + ConstantIndex * ConstantSize;
0457 }
0458
0459 ArrayRef<uint8_t> StackMapSection;
0460 unsigned ConstantsListOffset;
0461 std::vector<unsigned> StackMapRecordOffsets;
0462 };
0463
0464 }
0465
0466 #endif