File: stack_map_parser.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (180 lines) | stat: -rw-r--r-- 5,801 bytes parent folder | download | duplicates (11)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Copyright 2019 The Chromium Authors
// 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_