1 //===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
11 #include "llvm/ADT/ArrayRef.h"
12 #include "llvm/Support/Endian.h"
15 using namespace llvm::codeview;
17 static inline MethodKind getMethodKind(uint16_t Attrs) {
18 Attrs &= uint16_t(MethodOptions::MethodKindMask);
20 return MethodKind(Attrs);
23 static inline bool isIntroVirtual(uint16_t Attrs) {
24 MethodKind MK = getMethodKind(Attrs);
25 return MK == MethodKind::IntroducingVirtual ||
26 MK == MethodKind::PureIntroducingVirtual;
29 static inline PointerMode getPointerMode(uint32_t Attrs) {
30 return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) &
31 PointerRecord::PointerModeMask);
34 static inline bool isMemberPointer(uint32_t Attrs) {
35 PointerMode Mode = getPointerMode(Attrs);
36 return Mode == PointerMode::PointerToDataMember ||
37 Mode == PointerMode::PointerToDataMember;
40 static inline uint32_t getEncodedIntegerLength(ArrayRef<uint8_t> Data) {
41 uint16_t N = support::endian::read16le(Data.data());
45 assert(N <= LF_UQUADWORD);
47 constexpr uint32_t Sizes[] = {
61 return Sizes[N - LF_NUMERIC];
64 static inline uint32_t getCStringLength(ArrayRef<uint8_t> Data) {
65 const char *S = reinterpret_cast<const char *>(Data.data());
69 static void handleMethodOverloadList(ArrayRef<uint8_t> Content,
70 SmallVectorImpl<TiReference> &Refs) {
73 while (!Content.empty()) {
78 // if (isIntroVirtual())
81 // At least 8 bytes are guaranteed. 4 extra bytes come iff function is an
85 uint16_t Attrs = support::endian::read16le(Content.data());
86 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
88 if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
91 Content = Content.drop_front(Len);
95 static uint32_t handleBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
96 SmallVectorImpl<TiReference> &Refs) {
100 // 8: Encoded Integer
101 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
102 return 8 + getEncodedIntegerLength(Data.drop_front(8));
105 static uint32_t handleEnumerator(ArrayRef<uint8_t> Data, uint32_t Offset,
106 SmallVectorImpl<TiReference> &Refs) {
109 // 4: Encoded Integer
111 uint32_t Size = 4 + getEncodedIntegerLength(Data.drop_front(4));
112 return Size + getCStringLength(Data.drop_front(Size));
115 static uint32_t handleDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
116 SmallVectorImpl<TiReference> &Refs) {
120 // 8: Encoded Integer
122 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
123 uint32_t Size = 8 + getEncodedIntegerLength(Data.drop_front(8));
124 return Size + getCStringLength(Data.drop_front(Size));
127 static uint32_t handleOverloadedMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
128 SmallVectorImpl<TiReference> &Refs) {
133 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
134 return 8 + getCStringLength(Data.drop_front(8));
137 static uint32_t handleOneMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
138 SmallVectorImpl<TiReference> &Refs) {
142 // if (isIntroVirtual)
146 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
148 uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data());
149 if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
152 return Size + getCStringLength(Data.drop_front(Size));
155 static uint32_t handleNestedType(ArrayRef<uint8_t> Data, uint32_t Offset,
156 SmallVectorImpl<TiReference> &Refs) {
161 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
162 return 8 + getCStringLength(Data.drop_front(8));
165 static uint32_t handleStaticDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
166 SmallVectorImpl<TiReference> &Refs) {
171 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
172 return 8 + getCStringLength(Data.drop_front(8));
175 static uint32_t handleVirtualBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
177 SmallVectorImpl<TiReference> &Refs) {
182 // 12: Encoded Integer
183 // <next>: Encoded Integer
185 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2});
186 Size += getEncodedIntegerLength(Data.drop_front(Size));
187 Size += getEncodedIntegerLength(Data.drop_front(Size));
191 static uint32_t handleVFPtr(ArrayRef<uint8_t> Data, uint32_t Offset,
192 SmallVectorImpl<TiReference> &Refs) {
196 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
200 static uint32_t handleListContinuation(ArrayRef<uint8_t> Data, uint32_t Offset,
201 SmallVectorImpl<TiReference> &Refs) {
205 Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
209 static void handleFieldList(ArrayRef<uint8_t> Content,
210 SmallVectorImpl<TiReference> &Refs) {
212 uint32_t ThisLen = 0;
213 while (!Content.empty()) {
215 static_cast<TypeLeafKind>(support::endian::read16le(Content.data()));
218 ThisLen = handleBaseClass(Content, Offset, Refs);
221 ThisLen = handleEnumerator(Content, Offset, Refs);
224 ThisLen = handleDataMember(Content, Offset, Refs);
227 ThisLen = handleOverloadedMethod(Content, Offset, Refs);
230 ThisLen = handleOneMethod(Content, Offset, Refs);
233 ThisLen = handleNestedType(Content, Offset, Refs);
236 ThisLen = handleStaticDataMember(Content, Offset, Refs);
241 handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs);
244 ThisLen = handleVFPtr(Content, Offset, Refs);
247 ThisLen = handleListContinuation(Content, Offset, Refs);
252 Content = Content.drop_front(ThisLen);
254 if (!Content.empty()) {
255 uint8_t Pad = Content.front();
256 if (Pad >= LF_PAD0) {
257 uint32_t Skip = Pad & 0x0F;
258 Content = Content.drop_front(Skip);
265 static void handlePointer(ArrayRef<uint8_t> Content,
266 SmallVectorImpl<TiReference> &Refs) {
267 Refs.push_back({TiRefKind::TypeRef, 0, 1});
269 uint32_t Attrs = support::endian::read32le(Content.drop_front(4).data());
270 if (isMemberPointer(Attrs))
271 Refs.push_back({TiRefKind::TypeRef, 8, 1});
274 static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind,
275 SmallVectorImpl<TiReference> &Refs) {
277 // FIXME: In the future it would be nice if we could avoid hardcoding these
278 // values. One idea is to define some structures representing these types
279 // that would allow the use of offsetof().
281 case TypeLeafKind::LF_FUNC_ID:
282 Refs.push_back({TiRefKind::IndexRef, 0, 1});
283 Refs.push_back({TiRefKind::TypeRef, 4, 1});
285 case TypeLeafKind::LF_MFUNC_ID:
286 Refs.push_back({TiRefKind::TypeRef, 0, 2});
288 case TypeLeafKind::LF_STRING_ID:
289 Refs.push_back({TiRefKind::IndexRef, 0, 1});
291 case TypeLeafKind::LF_SUBSTR_LIST:
292 Count = support::endian::read32le(Content.data());
294 Refs.push_back({TiRefKind::IndexRef, 4, Count});
296 case TypeLeafKind::LF_BUILDINFO:
297 Count = support::endian::read16le(Content.data());
299 Refs.push_back({TiRefKind::IndexRef, 2, Count});
301 case TypeLeafKind::LF_UDT_SRC_LINE:
302 Refs.push_back({TiRefKind::TypeRef, 0, 1});
303 Refs.push_back({TiRefKind::IndexRef, 4, 1});
305 case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
306 Refs.push_back({TiRefKind::TypeRef, 0, 1});
308 case TypeLeafKind::LF_MODIFIER:
309 Refs.push_back({TiRefKind::TypeRef, 0, 1});
311 case TypeLeafKind::LF_PROCEDURE:
312 Refs.push_back({TiRefKind::TypeRef, 0, 1});
313 Refs.push_back({TiRefKind::TypeRef, 8, 1});
315 case TypeLeafKind::LF_MFUNCTION:
316 Refs.push_back({TiRefKind::TypeRef, 0, 3});
317 Refs.push_back({TiRefKind::TypeRef, 16, 1});
319 case TypeLeafKind::LF_ARGLIST:
320 Count = support::endian::read32le(Content.data());
322 Refs.push_back({TiRefKind::TypeRef, 4, Count});
324 case TypeLeafKind::LF_ARRAY:
325 Refs.push_back({TiRefKind::TypeRef, 0, 2});
327 case TypeLeafKind::LF_CLASS:
328 case TypeLeafKind::LF_STRUCTURE:
329 case TypeLeafKind::LF_INTERFACE:
330 Refs.push_back({TiRefKind::TypeRef, 4, 3});
332 case TypeLeafKind::LF_UNION:
333 Refs.push_back({TiRefKind::TypeRef, 4, 1});
335 case TypeLeafKind::LF_ENUM:
336 Refs.push_back({TiRefKind::TypeRef, 4, 2});
338 case TypeLeafKind::LF_BITFIELD:
339 Refs.push_back({TiRefKind::TypeRef, 0, 1});
341 case TypeLeafKind::LF_VFTABLE:
342 Refs.push_back({TiRefKind::TypeRef, 0, 2});
344 case TypeLeafKind::LF_VTSHAPE:
346 case TypeLeafKind::LF_METHODLIST:
347 handleMethodOverloadList(Content, Refs);
349 case TypeLeafKind::LF_FIELDLIST:
350 handleFieldList(Content, Refs);
352 case TypeLeafKind::LF_POINTER:
353 handlePointer(Content, Refs);
360 void llvm::codeview::discoverTypeIndices(const CVType &Type,
361 SmallVectorImpl<TiReference> &Refs) {
362 ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
365 void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
366 SmallVectorImpl<TiReference> &Refs) {
367 const RecordPrefix *P =
368 reinterpret_cast<const RecordPrefix *>(RecordData.data());
369 TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
370 ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);