| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef TOOLS_CLANG_STACK_MAPS_GC_STACK_MAP_PARSER_H_ |
| #define TOOLS_CLANG_STACK_MAPS_GC_STACK_MAP_PARSER_H_ |
| |
| #include "gc_api.h" |
| |
| // The stackmap section in the binary has a non-trivial layout. We give it a |
| // char type so it can be iterated byte-by-byte, and re-cast as necessary by the |
| // parser. |
| extern const char __LLVM_StackMaps; |
| |
| namespace stackmap { |
| |
| // These structs group together fields in the stackmap section to be used by the |
| // parser. They are packed to prevent clang adding its own alignment. We don't |
| // care about constants. The LLVM docs for stackmaps can be found here: |
| // https://llvm.org/docs/StackMaps.html#stack-map-format |
| // |
| // As per the docs, a version 3 stackmap has the following layout: |
| // |
| // Header { |
| // uint8 : Stack Map Version (current version is 3) |
| // uint8 : Reserved (expected to be 0) |
| // uint16 : Reserved (expected to be 0) |
| // } |
| // uint32 : NumFunctions |
| // uint32 : NumConstants |
| // uint32 : NumRecords |
| // StkSizeRecord[NumFunctions] { |
| // uint64 : Function Address |
| // uint64 : Stack Size |
| // uint64 : Record Count |
| // } |
| // Constants[NumConstants] { |
| // uint64 : LargeConstant |
| // } |
| // StkMapRecord[NumRecords] { |
| // uint64 : PatchPoint ID |
| // uint32 : Instruction Offset |
| // uint16 : Reserved (record flags) |
| // uint16 : NumLocations |
| // Location[NumLocations] { |
| // uint8 : Register | Direct | Indirect | Constant | ConstantIndex |
| // uint8 : Reserved (expected to be 0) |
| // uint16 : Location Size |
| // uint16 : Dwarf RegNum |
| // uint16 : Reserved (expected to be 0) |
| // int32 : Offset or SmallConstant |
| // } |
| // uint32 : Padding (only if required to align to 8 byte) |
| // uint16 : Padding |
| // uint16 : NumLiveOuts |
| // LiveOuts[NumLiveOuts] |
| // uint16 : Dwarf RegNum |
| // uint8 : Reserved |
| // uint8 : Size in Bytes |
| // } |
| // uint32 : Padding (only if required to align to 8 byte) |
| // } |
| |
| struct __attribute__((packed)) StkMapHeader { |
| uint8_t version; |
| uint8_t reserved1; |
| uint16_t reserved2; |
| uint32_t num_functions; |
| uint32_t num_constants; |
| uint32_t num_records; |
| }; |
| |
| struct __attribute__((packed)) StkSizeRecord { |
| uint64_t address; |
| uint64_t stack_size; |
| uint64_t record_count; // see https://reviews.llvm.org/D23487 |
| }; |
| |
| struct __attribute__((packed)) StkMapRecordHeader { |
| uint64_t patchpoint_id; |
| uint32_t return_addr; // from the entry of the function |
| uint16_t flags; |
| uint16_t num_locations; |
| }; |
| |
| enum LocationKind { |
| kRegister = 0x1, |
| kDirect = 0x2, |
| kIndirect = 0x3, |
| kConstant = 0x4, |
| kConstIndex = 0x5 |
| }; |
| |
| struct __attribute__((packed)) StkMapLocation { |
| uint8_t kind; // 1 byte sized `LocationKind` variant |
| uint8_t flags; // expected to be 0 |
| uint16_t location_size; |
| uint16_t reg_num; // Dwarf register num |
| uint16_t reserved; // expected to be 0 |
| int32_t offset; // either an offset or a "Small Constant" |
| }; |
| |
| struct __attribute__((packed)) LiveOutsHeader { |
| uint16_t padding; |
| uint16_t num_liveouts; |
| }; |
| |
| struct __attribute__((packed)) LiveOut { |
| uint16_t reg_num; // Dwarf register num |
| uint8_t flags; |
| uint8_t size; // in bytes |
| }; |
| |
| // A StackmapV3Parser encapsulates the parsing logic for reading from an |
| // .llvm_stackmap section in the ELF file. The .llvm_stackmap section is |
| // versioned and *not* backwards compatible. |
| class StackmapV3Parser { |
| public: |
| StackmapV3Parser() : cursor_(&__LLVM_StackMaps) {} |
| |
| SafepointTable Parse(); |
| |
| private: |
| static constexpr uint8_t kStackmapVersion = 3; |
| static constexpr uint8_t kSizeConstantEntry = 8; // size in bytes |
| static constexpr uint8_t kSkipLocs = 2; |
| |
| const char* cursor_; |
| const StkMapRecordHeader* cur_frame_; |
| |
| // Get a new pointer of the same type to the one passed in arg0 + some byte(s) |
| // offset. Useful to prevent littering code with constant char* casting when |
| // all that's needed is to bump the ptr by a set amount of bytes. Note this |
| // *does not* perform any alignment. |
| template <typename T, typename U> |
| inline T ptr_offset(U ptr, int bytes) { |
| auto* newptr = reinterpret_cast<const char*>(ptr); |
| newptr += bytes; |
| return reinterpret_cast<T>(newptr); |
| } |
| |
| // Align a pointer to the next 8 byte boundary |
| template <typename T> |
| inline T* align_8(T* ptr) { |
| auto* c = reinterpret_cast<const char*>(ptr); |
| return reinterpret_cast<T*>(((uintptr_t)c + 7) & ~7); |
| } |
| |
| // Creates a FrameRoot entry for a callsite's stack map record. This jumps |
| // over and ignores a bunch of values in the stack map record that are not of |
| // interest to precise stack scanning in V8 / Blink. Stack map records make up |
| // the bulk of the .llvm_stackmap section. For reference, the format is shown |
| // below: |
| // StkMapRecord[NumRecords] { |
| // uint64 : PatchPoint ID |
| // uint32 : Instruction Offset |
| // uint16 : Reserved (record flags) |
| // uint16 : NumLocations |
| // Location[NumLocations] { |
| // uint8 : Register | Direct | Indirect | Constant | ConstantIndex |
| // uint8 : Reserved (expected to be 0) |
| // uint16 : Location Size |
| // uint16 : Dwarf RegNum |
| // uint16 : Reserved (expected to be 0) |
| // int32 : Offset or SmallConstant |
| // } |
| // uint32 : Padding (only if required to align to 8 byte) |
| // uint16 : Padding |
| // uint16 : NumLiveOuts |
| // LiveOuts[NumLiveOuts] |
| // uint16 : Dwarf RegNum |
| // uint8 : Reserved |
| // uint8 : Size in Bytes |
| // } |
| FrameRoots ParseFrame(); |
| }; |
| |
| } // namespace stackmap |
| |
| #endif // TOOLS_CLANG_STACK_MAPS_GC_STACK_MAP_PARSER_H_ |