Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:20

0001 //===- StackMapParser.h - StackMap Parsing Support --------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
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 /// A parser for the latest stackmap format.  At the moment, latest=V3.
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   /// Accessor for function records.
0054   class FunctionAccessor {
0055     friend class StackMapParser;
0056 
0057   public:
0058     /// Get the function address.
0059     uint64_t getFunctionAddress() const {
0060       return read<uint64_t>(P);
0061     }
0062 
0063     /// Get the function's stack size.
0064     uint64_t getStackSize() const {
0065       return read<uint64_t>(P + sizeof(uint64_t));
0066     }
0067 
0068     /// Get the number of callsite records.
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   /// Accessor for constants.
0086   class ConstantAccessor {
0087     friend class StackMapParser;
0088 
0089   public:
0090     /// Return the value of this constant.
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   /// Accessor for location records.
0110   class LocationAccessor {
0111     friend class StackMapParser;
0112     friend class RecordAccessor;
0113 
0114   public:
0115     /// Get the Kind for this location.
0116     LocationKind getKind() const {
0117       return LocationKind(P[KindOffset]);
0118     }
0119 
0120     /// Get the Size for this location.
0121     unsigned getSizeInBytes() const {
0122         return read<uint16_t>(P + SizeOffset);
0123 
0124     }
0125 
0126     /// Get the Dwarf register number for this location.
0127     uint16_t getDwarfRegNum() const {
0128       return read<uint16_t>(P + DwarfRegNumOffset);
0129     }
0130 
0131     /// Get the small-constant for this location. (Kind must be Constant).
0132     uint32_t getSmallConstant() const {
0133       assert(getKind() == LocationKind::Constant && "Not a small constant.");
0134       return read<uint32_t>(P + SmallConstantOffset);
0135     }
0136 
0137     /// Get the constant-index for this location. (Kind must be ConstantIndex).
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     /// Get the offset for this location. (Kind must be Direct or Indirect).
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   /// Accessor for stackmap live-out fields.
0169   class LiveOutAccessor {
0170     friend class StackMapParser;
0171     friend class RecordAccessor;
0172 
0173   public:
0174     /// Get the Dwarf register number for this live-out.
0175     uint16_t getDwarfRegNum() const {
0176       return read<uint16_t>(P + DwarfRegNumOffset);
0177     }
0178 
0179     /// Get the size in bytes of live [sub]register.
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   /// Accessor for stackmap records.
0200   class RecordAccessor {
0201     friend class StackMapParser;
0202 
0203   public:
0204     using location_iterator = AccessorIterator<LocationAccessor>;
0205     using liveout_iterator = AccessorIterator<LiveOutAccessor>;
0206 
0207     /// Get the patchpoint/stackmap ID for this record.
0208     uint64_t getID() const {
0209       return read<uint64_t>(P + PatchpointIDOffset);
0210     }
0211 
0212     /// Get the instruction offset (from the start of the containing function)
0213     /// for this record.
0214     uint32_t getInstructionOffset() const {
0215       return read<uint32_t>(P + InstructionOffsetOffset);
0216     }
0217 
0218     /// Get the number of locations contained in this record.
0219     uint16_t getNumLocations() const {
0220       return read<uint16_t>(P + NumLocationsOffset);
0221     }
0222 
0223     /// Get the location with the given index.
0224     LocationAccessor getLocation(unsigned LocationIndex) const {
0225       unsigned LocationOffset =
0226         LocationListOffset + LocationIndex * LocationSize;
0227       return LocationAccessor(P + LocationOffset);
0228     }
0229 
0230     /// Begin iterator for locations.
0231     location_iterator location_begin() const {
0232       return location_iterator(getLocation(0));
0233     }
0234 
0235     /// End iterator for locations.
0236     location_iterator location_end() const {
0237       return location_iterator(getLocation(getNumLocations()));
0238     }
0239 
0240     /// Iterator range for locations.
0241     iterator_range<location_iterator> locations() const {
0242       return make_range(location_begin(), location_end());
0243     }
0244 
0245     /// Get the number of liveouts contained in this record.
0246     uint16_t getNumLiveOuts() const {
0247       return read<uint16_t>(P + getNumLiveOutsOffset());
0248     }
0249 
0250     /// Get the live-out with the given index.
0251     LiveOutAccessor getLiveOut(unsigned LiveOutIndex) const {
0252       unsigned LiveOutOffset =
0253         getNumLiveOutsOffset() + sizeof(uint16_t) + LiveOutIndex * LiveOutSize;
0254       return LiveOutAccessor(P + LiveOutOffset);
0255     }
0256 
0257     /// Begin iterator for live-outs.
0258     liveout_iterator liveouts_begin() const {
0259       return liveout_iterator(getLiveOut(0));
0260     }
0261 
0262     /// End iterator for live-outs.
0263     liveout_iterator liveouts_end() const {
0264       return liveout_iterator(getLiveOut(getNumLiveOuts()));
0265     }
0266 
0267     /// Iterator range for live-outs.
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   /// Construct a parser for a version-3 stackmap. StackMap data will be read
0305   /// from the given array.
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   /// Validates the header of the specified stack map section.
0324   static Error validateHeader(ArrayRef<uint8_t> StackMapSection) {
0325     // See the comment for StackMaps::emitStackmapHeader().
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   /// Get the version number of this stackmap. (Always returns 3).
0345   unsigned getVersion() const { return 3; }
0346 
0347   /// Get the number of functions in the stack map.
0348   uint32_t getNumFunctions() const {
0349     return read<uint32_t>(&StackMapSection[NumFunctionsOffset]);
0350   }
0351 
0352   /// Get the number of large constants in the stack map.
0353   uint32_t getNumConstants() const {
0354     return read<uint32_t>(&StackMapSection[NumConstantsOffset]);
0355   }
0356 
0357   /// Get the number of stackmap records in the stackmap.
0358   uint32_t getNumRecords() const {
0359     return read<uint32_t>(&StackMapSection[NumRecordsOffset]);
0360   }
0361 
0362   /// Return an FunctionAccessor for the given function index.
0363   FunctionAccessor getFunction(unsigned FunctionIndex) const {
0364     return FunctionAccessor(StackMapSection.data() +
0365                             getFunctionOffset(FunctionIndex));
0366   }
0367 
0368   /// Begin iterator for functions.
0369   function_iterator functions_begin() const {
0370     return function_iterator(getFunction(0));
0371   }
0372 
0373   /// End iterator for functions.
0374   function_iterator functions_end() const {
0375     return function_iterator(
0376              FunctionAccessor(StackMapSection.data() +
0377                               getFunctionOffset(getNumFunctions())));
0378   }
0379 
0380   /// Iterator range for functions.
0381   iterator_range<function_iterator> functions() const {
0382     return make_range(functions_begin(), functions_end());
0383   }
0384 
0385   /// Return the large constant at the given index.
0386   ConstantAccessor getConstant(unsigned ConstantIndex) const {
0387     return ConstantAccessor(StackMapSection.data() +
0388                             getConstantOffset(ConstantIndex));
0389   }
0390 
0391   /// Begin iterator for constants.
0392   constant_iterator constants_begin() const {
0393     return constant_iterator(getConstant(0));
0394   }
0395 
0396   /// End iterator for constants.
0397   constant_iterator constants_end() const {
0398     return constant_iterator(
0399              ConstantAccessor(StackMapSection.data() +
0400                               getConstantOffset(getNumConstants())));
0401   }
0402 
0403   /// Iterator range for constants.
0404   iterator_range<constant_iterator> constants() const {
0405     return make_range(constants_begin(), constants_end());
0406   }
0407 
0408   /// Return a RecordAccessor for the given record index.
0409   RecordAccessor getRecord(unsigned RecordIndex) const {
0410     std::size_t RecordOffset = StackMapRecordOffsets[RecordIndex];
0411     return RecordAccessor(StackMapSection.data() + RecordOffset);
0412   }
0413 
0414   /// Begin iterator for records.
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   /// End iterator for records.
0422   record_iterator records_end() const {
0423     // Records need to be handled specially, since we cache the start addresses
0424     // for them: We can't just compute the 1-past-the-end address, we have to
0425     // look at the last record and use the 'next' method.
0426     if (getNumRecords() == 0)
0427       return record_iterator(RecordAccessor(nullptr));
0428     return record_iterator(getRecord(getNumRecords() - 1).next());
0429   }
0430 
0431   /// Iterator range for records.
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 } // end namespace llvm
0465 
0466 #endif // LLVM_OBJECT_STACKMAPPARSER_H