Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 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 <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_OBJECT_STACKMAPPARSER_H