1//===- StackMapParser.h - StackMap Parsing Support --------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#ifndef LLVM_CODEGEN_STACKMAPPARSER_H 11#define LLVM_CODEGEN_STACKMAPPARSER_H 12 13#include "llvm/ADT/ArrayRef.h" 14#include "llvm/ADT/iterator_range.h" 15#include "llvm/Support/Endian.h" 16#include <cassert> 17#include <cstddef> 18#include <cstdint> 19#include <vector> 20 21namespace llvm { 22 23template <support::endianness Endianness> 24class StackMapV2Parser { 25public: 26 template <typename AccessorT> 27 class AccessorIterator { 28 public: 29 AccessorIterator(AccessorT A) : A(A) {} 30 31 AccessorIterator& operator++() { A = A.next(); return *this; } 32 AccessorIterator operator++(int) { 33 auto tmp = *this; 34 ++*this; 35 return tmp; 36 } 37 38 bool operator==(const AccessorIterator &Other) { 39 return A.P == Other.A.P; 40 } 41 42 bool operator!=(const AccessorIterator &Other) { return !(*this == Other); } 43 44 AccessorT& operator*() { return A; } 45 AccessorT* operator->() { return &A; } 46 47 private: 48 AccessorT A; 49 }; 50 51 /// Accessor for function records. 52 class FunctionAccessor { 53 friend class StackMapV2Parser; 54 55 public: 56 /// Get the function address. 57 uint64_t getFunctionAddress() const { 58 return read<uint64_t>(P); 59 } 60 61 /// Get the function's stack size. 62 uint64_t getStackSize() const { 63 return read<uint64_t>(P + sizeof(uint64_t)); 64 } 65 66 /// Get the number of callsite records. 67 uint64_t getRecordCount() const { 68 return read<uint64_t>(P + (2 * sizeof(uint64_t))); 69 } 70 71 private: 72 FunctionAccessor(const uint8_t *P) : P(P) {} 73 74 const static int FunctionAccessorSize = 3 * sizeof(uint64_t); 75 76 FunctionAccessor next() const { 77 return FunctionAccessor(P + FunctionAccessorSize); 78 } 79 80 const uint8_t *P; 81 }; 82 83 /// Accessor for constants. 84 class ConstantAccessor { 85 friend class StackMapV2Parser; 86 87 public: 88 /// Return the value of this constant. 89 uint64_t getValue() const { return read<uint64_t>(P); } 90 91 private: 92 ConstantAccessor(const uint8_t *P) : P(P) {} 93 94 const static int ConstantAccessorSize = sizeof(uint64_t); 95 96 ConstantAccessor next() const { 97 return ConstantAccessor(P + ConstantAccessorSize); 98 } 99 100 const uint8_t *P; 101 }; 102 103 enum class LocationKind : uint8_t { 104 Register = 1, Direct = 2, Indirect = 3, Constant = 4, ConstantIndex = 5 105 }; 106 107 /// Accessor for location records. 108 class LocationAccessor { 109 friend class StackMapV2Parser; 110 friend class RecordAccessor; 111 112 public: 113 /// Get the Kind for this location. 114 LocationKind getKind() const { 115 return LocationKind(P[KindOffset]); 116 } 117 118 /// Get the Dwarf register number for this location. 119 uint16_t getDwarfRegNum() const { 120 return read<uint16_t>(P + DwarfRegNumOffset); 121 } 122 123 /// Get the small-constant for this location. (Kind must be Constant). 124 uint32_t getSmallConstant() const { 125 assert(getKind() == LocationKind::Constant && "Not a small constant."); 126 return read<uint32_t>(P + SmallConstantOffset); 127 } 128 129 /// Get the constant-index for this location. (Kind must be ConstantIndex). 130 uint32_t getConstantIndex() const { 131 assert(getKind() == LocationKind::ConstantIndex && 132 "Not a constant-index."); 133 return read<uint32_t>(P + SmallConstantOffset); 134 } 135 136 /// Get the offset for this location. (Kind must be Direct or Indirect). 137 int32_t getOffset() const { 138 assert((getKind() == LocationKind::Direct || 139 getKind() == LocationKind::Indirect) && 140 "Not direct or indirect."); 141 return read<int32_t>(P + SmallConstantOffset); 142 } 143 144 private: 145 LocationAccessor(const uint8_t *P) : P(P) {} 146 147 LocationAccessor next() const { 148 return LocationAccessor(P + LocationAccessorSize); 149 } 150 151 static const int KindOffset = 0; 152 static const int DwarfRegNumOffset = KindOffset + sizeof(uint16_t); 153 static const int SmallConstantOffset = DwarfRegNumOffset + sizeof(uint16_t); 154 static const int LocationAccessorSize = sizeof(uint64_t); 155 156 const uint8_t *P; 157 }; 158 159 /// Accessor for stackmap live-out fields. 160 class LiveOutAccessor { 161 friend class StackMapV2Parser; 162 friend class RecordAccessor; 163 164 public: 165 /// Get the Dwarf register number for this live-out. 166 uint16_t getDwarfRegNum() const { 167 return read<uint16_t>(P + DwarfRegNumOffset); 168 } 169 170 /// Get the size in bytes of live [sub]register. 171 unsigned getSizeInBytes() const { 172 return read<uint8_t>(P + SizeOffset); 173 } 174 175 private: 176 LiveOutAccessor(const uint8_t *P) : P(P) {} 177 178 LiveOutAccessor next() const { 179 return LiveOutAccessor(P + LiveOutAccessorSize); 180 } 181 182 static const int DwarfRegNumOffset = 0; 183 static const int SizeOffset = 184 DwarfRegNumOffset + sizeof(uint16_t) + sizeof(uint8_t); 185 static const int LiveOutAccessorSize = sizeof(uint32_t); 186 187 const uint8_t *P; 188 }; 189 190 /// Accessor for stackmap records. 191 class RecordAccessor { 192 friend class StackMapV2Parser; 193 194 public: 195 using location_iterator = AccessorIterator<LocationAccessor>; 196 using liveout_iterator = AccessorIterator<LiveOutAccessor>; 197 198 /// Get the patchpoint/stackmap ID for this record. 199 uint64_t getID() const { 200 return read<uint64_t>(P + PatchpointIDOffset); 201 } 202 203 /// Get the instruction offset (from the start of the containing function) 204 /// for this record. 205 uint32_t getInstructionOffset() const { 206 return read<uint32_t>(P + InstructionOffsetOffset); 207 } 208 209 /// Get the number of locations contained in this record. 210 uint16_t getNumLocations() const { 211 return read<uint16_t>(P + NumLocationsOffset); 212 } 213 214 /// Get the location with the given index. 215 LocationAccessor getLocation(unsigned LocationIndex) const { 216 unsigned LocationOffset = 217 LocationListOffset + LocationIndex * LocationSize; 218 return LocationAccessor(P + LocationOffset); 219 } 220 221 /// Begin iterator for locations. 222 location_iterator location_begin() const { 223 return location_iterator(getLocation(0)); 224 } 225 226 /// End iterator for locations. 227 location_iterator location_end() const { 228 return location_iterator(getLocation(getNumLocations())); 229 } 230 231 /// Iterator range for locations. 232 iterator_range<location_iterator> locations() const { 233 return make_range(location_begin(), location_end()); 234 } 235 236 /// Get the number of liveouts contained in this record. 237 uint16_t getNumLiveOuts() const { 238 return read<uint16_t>(P + getNumLiveOutsOffset()); 239 } 240 241 /// Get the live-out with the given index. 242 LiveOutAccessor getLiveOut(unsigned LiveOutIndex) const { 243 unsigned LiveOutOffset = 244 getNumLiveOutsOffset() + sizeof(uint16_t) + LiveOutIndex * LiveOutSize; 245 return LiveOutAccessor(P + LiveOutOffset); 246 } 247 248 /// Begin iterator for live-outs. 249 liveout_iterator liveouts_begin() const { 250 return liveout_iterator(getLiveOut(0)); 251 } 252 253 /// End iterator for live-outs. 254 liveout_iterator liveouts_end() const { 255 return liveout_iterator(getLiveOut(getNumLiveOuts())); 256 } 257 258 /// Iterator range for live-outs. 259 iterator_range<liveout_iterator> liveouts() const { 260 return make_range(liveouts_begin(), liveouts_end()); 261 } 262 263 private: 264 RecordAccessor(const uint8_t *P) : P(P) {} 265 266 unsigned getNumLiveOutsOffset() const { 267 return LocationListOffset + LocationSize * getNumLocations() + 268 sizeof(uint16_t); 269 } 270 271 unsigned getSizeInBytes() const { 272 unsigned RecordSize = 273 getNumLiveOutsOffset() + sizeof(uint16_t) + getNumLiveOuts() * LiveOutSize; 274 return (RecordSize + 7) & ~0x7; 275 } 276 277 RecordAccessor next() const { 278 return RecordAccessor(P + getSizeInBytes()); 279 } 280 281 static const unsigned PatchpointIDOffset = 0; 282 static const unsigned InstructionOffsetOffset = 283 PatchpointIDOffset + sizeof(uint64_t); 284 static const unsigned NumLocationsOffset = 285 InstructionOffsetOffset + sizeof(uint32_t) + sizeof(uint16_t); 286 static const unsigned LocationListOffset = 287 NumLocationsOffset + sizeof(uint16_t); 288 static const unsigned LocationSize = sizeof(uint64_t); 289 static const unsigned LiveOutSize = sizeof(uint32_t); 290 291 const uint8_t *P; 292 }; 293 294 /// Construct a parser for a version-2 stackmap. StackMap data will be read 295 /// from the given array. 296 StackMapV2Parser(ArrayRef<uint8_t> StackMapSection) 297 : StackMapSection(StackMapSection) { 298 ConstantsListOffset = FunctionListOffset + getNumFunctions() * FunctionSize; 299 300 assert(StackMapSection[0] == 2 && 301 "StackMapV2Parser can only parse version 2 stackmaps"); 302 303 unsigned CurrentRecordOffset = 304 ConstantsListOffset + getNumConstants() * ConstantSize; 305 306 for (unsigned I = 0, E = getNumRecords(); I != E; ++I) { 307 StackMapRecordOffsets.push_back(CurrentRecordOffset); 308 CurrentRecordOffset += 309 RecordAccessor(&StackMapSection[CurrentRecordOffset]).getSizeInBytes(); 310 } 311 } 312 313 using function_iterator = AccessorIterator<FunctionAccessor>; 314 using constant_iterator = AccessorIterator<ConstantAccessor>; 315 using record_iterator = AccessorIterator<RecordAccessor>; 316 317 /// Get the version number of this stackmap. (Always returns 2). 318 unsigned getVersion() const { return 2; } 319 320 /// Get the number of functions in the stack map. 321 uint32_t getNumFunctions() const { 322 return read<uint32_t>(&StackMapSection[NumFunctionsOffset]); 323 } 324 325 /// Get the number of large constants in the stack map. 326 uint32_t getNumConstants() const { 327 return read<uint32_t>(&StackMapSection[NumConstantsOffset]); 328 } 329 330 /// Get the number of stackmap records in the stackmap. 331 uint32_t getNumRecords() const { 332 return read<uint32_t>(&StackMapSection[NumRecordsOffset]); 333 } 334 335 /// Return an FunctionAccessor for the given function index. 336 FunctionAccessor getFunction(unsigned FunctionIndex) const { 337 return FunctionAccessor(StackMapSection.data() + 338 getFunctionOffset(FunctionIndex)); 339 } 340 341 /// Begin iterator for functions. 342 function_iterator functions_begin() const { 343 return function_iterator(getFunction(0)); 344 } 345 346 /// End iterator for functions. 347 function_iterator functions_end() const { 348 return function_iterator( 349 FunctionAccessor(StackMapSection.data() + 350 getFunctionOffset(getNumFunctions()))); 351 } 352 353 /// Iterator range for functions. 354 iterator_range<function_iterator> functions() const { 355 return make_range(functions_begin(), functions_end()); 356 } 357 358 /// Return the large constant at the given index. 359 ConstantAccessor getConstant(unsigned ConstantIndex) const { 360 return ConstantAccessor(StackMapSection.data() + 361 getConstantOffset(ConstantIndex)); 362 } 363 364 /// Begin iterator for constants. 365 constant_iterator constants_begin() const { 366 return constant_iterator(getConstant(0)); 367 } 368 369 /// End iterator for constants. 370 constant_iterator constants_end() const { 371 return constant_iterator( 372 ConstantAccessor(StackMapSection.data() + 373 getConstantOffset(getNumConstants()))); 374 } 375 376 /// Iterator range for constants. 377 iterator_range<constant_iterator> constants() const { 378 return make_range(constants_begin(), constants_end()); 379 } 380 381 /// Return a RecordAccessor for the given record index. 382 RecordAccessor getRecord(unsigned RecordIndex) const { 383 std::size_t RecordOffset = StackMapRecordOffsets[RecordIndex]; 384 return RecordAccessor(StackMapSection.data() + RecordOffset); 385 } 386 387 /// Begin iterator for records. 388 record_iterator records_begin() const { 389 if (getNumRecords() == 0) 390 return record_iterator(RecordAccessor(nullptr)); 391 return record_iterator(getRecord(0)); 392 } 393 394 /// End iterator for records. 395 record_iterator records_end() const { 396 // Records need to be handled specially, since we cache the start addresses 397 // for them: We can't just compute the 1-past-the-end address, we have to 398 // look at the last record and use the 'next' method. 399 if (getNumRecords() == 0) 400 return record_iterator(RecordAccessor(nullptr)); 401 return record_iterator(getRecord(getNumRecords() - 1).next()); 402 } 403 404 /// Iterator range for records. 405 iterator_range<record_iterator> records() const { 406 return make_range(records_begin(), records_end()); 407 } 408 409private: 410 template <typename T> 411 static T read(const uint8_t *P) { 412 return support::endian::read<T, Endianness, 1>(P); 413 } 414 415 static const unsigned HeaderOffset = 0; 416 static const unsigned NumFunctionsOffset = HeaderOffset + sizeof(uint32_t); 417 static const unsigned NumConstantsOffset = NumFunctionsOffset + sizeof(uint32_t); 418 static const unsigned NumRecordsOffset = NumConstantsOffset + sizeof(uint32_t); 419 static const unsigned FunctionListOffset = NumRecordsOffset + sizeof(uint32_t); 420 421 static const unsigned FunctionSize = 3 * sizeof(uint64_t); 422 static const unsigned ConstantSize = sizeof(uint64_t); 423 424 std::size_t getFunctionOffset(unsigned FunctionIndex) const { 425 return FunctionListOffset + FunctionIndex * FunctionSize; 426 } 427 428 std::size_t getConstantOffset(unsigned ConstantIndex) const { 429 return ConstantsListOffset + ConstantIndex * ConstantSize; 430 } 431 432 ArrayRef<uint8_t> StackMapSection; 433 unsigned ConstantsListOffset; 434 std::vector<unsigned> StackMapRecordOffsets; 435}; 436 437} // end namespace llvm 438 439#endif // LLVM_CODEGEN_STACKMAPPARSER_H 440