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