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_CODEGEN_STACKMAPPARSER_H 10 #define LLVM_CODEGEN_STACKMAPPARSER_H 11 12 #include "llvm/ADT/ArrayRef.h" 13 #include "llvm/ADT/iterator_range.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 21 namespace llvm { 22 23 /// A parser for the latest stackmap format. At the moment, latest=V3. 24 template <support::endianness Endianness> 25 class StackMapParser { 26 public: 27 template <typename AccessorT> 28 class AccessorIterator { 29 public: 30 AccessorIterator(AccessorT A) : A(A) {} 31 32 AccessorIterator& operator++() { A = A.next(); return *this; } 33 AccessorIterator operator++(int) { 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. 55 class FunctionAccessor { 56 friend class StackMapParser; 57 58 public: 59 /// Get the function address. 60 uint64_t getFunctionAddress() const { 61 return read<uint64_t>(P); 62 } 63 64 /// Get the function's stack size. 65 uint64_t getStackSize() const { 66 return read<uint64_t>(P + sizeof(uint64_t)); 67 } 68 69 /// Get the number of callsite records. 70 uint64_t getRecordCount() const { 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. 87 class ConstantAccessor { 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. 111 class LocationAccessor { 112 friend class StackMapParser; 113 friend class RecordAccessor; 114 115 public: 116 /// Get the Kind for this location. 117 LocationKind getKind() const { 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. 128 uint16_t getDwarfRegNum() const { 129 return read<uint16_t>(P + DwarfRegNumOffset); 130 } 131 132 /// Get the small-constant for this location. (Kind must be Constant). 133 uint32_t getSmallConstant() const { 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). 139 uint32_t getConstantIndex() const { 140 assert(getKind() == LocationKind::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 { 147 assert((getKind() == LocationKind::Direct || 148 getKind() == LocationKind::Indirect) && 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. 170 class LiveOutAccessor { 171 friend class StackMapParser; 172 friend class RecordAccessor; 173 174 public: 175 /// Get the Dwarf register number for this live-out. 176 uint16_t getDwarfRegNum() const { 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. 201 class RecordAccessor { 202 friend class StackMapParser; 203 204 public: 205 using location_iterator = AccessorIterator<LocationAccessor>; 206 using liveout_iterator = AccessorIterator<LiveOutAccessor>; 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. 215 uint32_t getInstructionOffset() const { 216 return read<uint32_t>(P + InstructionOffsetOffset); 217 } 218 219 /// Get the number of locations contained in this record. 220 uint16_t getNumLocations() const { 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. 232 location_iterator location_begin() const { 233 return location_iterator(getLocation(0)); 234 } 235 236 /// End iterator for locations. 237 location_iterator location_end() const { 238 return location_iterator(getLocation(getNumLocations())); 239 } 240 241 /// Iterator range for locations. 242 iterator_range<location_iterator> locations() const { 243 return make_range(location_begin(), location_end()); 244 } 245 246 /// Get the number of liveouts contained in this record. 247 uint16_t getNumLiveOuts() const { 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. 259 liveout_iterator liveouts_begin() const { 260 return liveout_iterator(getLiveOut(0)); 261 } 262 263 /// End iterator for live-outs. 264 liveout_iterator liveouts_end() const { 265 return liveout_iterator(getLiveOut(getNumLiveOuts())); 266 } 267 268 /// Iterator range for live-outs. 269 iterator_range<liveout_iterator> liveouts() const { 270 return make_range(liveouts_begin(), liveouts_end()); 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. 307 StackMapParser(ArrayRef<uint8_t> StackMapSection) 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 341 using function_iterator = AccessorIterator<FunctionAccessor>; 342 using constant_iterator = AccessorIterator<ConstantAccessor>; 343 using record_iterator = AccessorIterator<RecordAccessor>; 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. 349 uint32_t getNumFunctions() const { 350 return read<uint32_t>(&StackMapSection[NumFunctionsOffset]); 351 } 352 353 /// Get the number of large constants in the stack map. 354 uint32_t getNumConstants() const { 355 return read<uint32_t>(&StackMapSection[NumConstantsOffset]); 356 } 357 358 /// Get the number of stackmap records in the stackmap. 359 uint32_t getNumRecords() const { 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. 370 function_iterator functions_begin() const { 371 return function_iterator(getFunction(0)); 372 } 373 374 /// End iterator for functions. 375 function_iterator functions_end() const { 376 return function_iterator( 377 FunctionAccessor(StackMapSection.data() + 378 getFunctionOffset(getNumFunctions()))); 379 } 380 381 /// Iterator range for functions. 382 iterator_range<function_iterator> functions() const { 383 return make_range(functions_begin(), functions_end()); 384 } 385 386 /// Return the large constant at the given index. 387 ConstantAccessor getConstant(unsigned ConstantIndex) const { 388 return ConstantAccessor(StackMapSection.data() + 389 getConstantOffset(ConstantIndex)); 390 } 391 392 /// Begin iterator for constants. 393 constant_iterator constants_begin() const { 394 return constant_iterator(getConstant(0)); 395 } 396 397 /// End iterator for constants. 398 constant_iterator constants_end() const { 399 return constant_iterator( 400 ConstantAccessor(StackMapSection.data() + 401 getConstantOffset(getNumConstants()))); 402 } 403 404 /// Iterator range for constants. 405 iterator_range<constant_iterator> constants() const { 406 return make_range(constants_begin(), constants_end()); 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. 416 record_iterator records_begin() const { 417 if (getNumRecords() == 0) 418 return record_iterator(RecordAccessor(nullptr)); 419 return record_iterator(getRecord(0)); 420 } 421 422 /// End iterator for records. 423 record_iterator records_end() const { 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. 433 iterator_range<record_iterator> records() const { 434 return make_range(records_begin(), records_end()); 435 } 436 437 private: 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_CODEGEN_STACKMAPPARSER_H 468