TypeIndexDiscovery.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. //===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
  10. #include "llvm/ADT/ArrayRef.h"
  11. #include "llvm/Support/Endian.h"
  12. using namespace llvm;
  13. using namespace llvm::codeview;
  14. static inline MethodKind getMethodKind(uint16_t Attrs) {
  15. Attrs &= uint16_t(MethodOptions::MethodKindMask);
  16. Attrs >>= 2;
  17. return MethodKind(Attrs);
  18. }
  19. static inline bool isIntroVirtual(uint16_t Attrs) {
  20. MethodKind MK = getMethodKind(Attrs);
  21. return MK == MethodKind::IntroducingVirtual ||
  22. MK == MethodKind::PureIntroducingVirtual;
  23. }
  24. static inline PointerMode getPointerMode(uint32_t Attrs) {
  25. return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) &
  26. PointerRecord::PointerModeMask);
  27. }
  28. static inline bool isMemberPointer(uint32_t Attrs) {
  29. PointerMode Mode = getPointerMode(Attrs);
  30. return Mode == PointerMode::PointerToDataMember ||
  31. Mode == PointerMode::PointerToDataMember;
  32. }
  33. static inline uint32_t getEncodedIntegerLength(ArrayRef<uint8_t> Data) {
  34. uint16_t N = support::endian::read16le(Data.data());
  35. if (N < LF_NUMERIC)
  36. return 2;
  37. assert(N <= LF_UQUADWORD);
  38. constexpr uint32_t Sizes[] = {
  39. 1, // LF_CHAR
  40. 2, // LF_SHORT
  41. 2, // LF_USHORT
  42. 4, // LF_LONG
  43. 4, // LF_ULONG
  44. 4, // LF_REAL32
  45. 8, // LF_REAL64
  46. 10, // LF_REAL80
  47. 16, // LF_REAL128
  48. 8, // LF_QUADWORD
  49. 8, // LF_UQUADWORD
  50. };
  51. return Sizes[N - LF_NUMERIC];
  52. }
  53. static inline uint32_t getCStringLength(ArrayRef<uint8_t> Data) {
  54. const char *S = reinterpret_cast<const char *>(Data.data());
  55. return strlen(S) + 1;
  56. }
  57. static void handleMethodOverloadList(ArrayRef<uint8_t> Content,
  58. SmallVectorImpl<TiReference> &Refs) {
  59. uint32_t Offset = 0;
  60. while (!Content.empty()) {
  61. // Array of:
  62. // 0: Attrs
  63. // 2: Padding
  64. // 4: TypeIndex
  65. // if (isIntroVirtual())
  66. // 8: VFTableOffset
  67. // At least 8 bytes are guaranteed. 4 extra bytes come iff function is an
  68. // intro virtual.
  69. uint32_t Len = 8;
  70. uint16_t Attrs = support::endian::read16le(Content.data());
  71. Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
  72. if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
  73. Len += 4;
  74. Offset += Len;
  75. Content = Content.drop_front(Len);
  76. }
  77. }
  78. static uint32_t handleBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
  79. SmallVectorImpl<TiReference> &Refs) {
  80. // 0: Kind
  81. // 2: Padding
  82. // 4: TypeIndex
  83. // 8: Encoded Integer
  84. Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
  85. return 8 + getEncodedIntegerLength(Data.drop_front(8));
  86. }
  87. static uint32_t handleEnumerator(ArrayRef<uint8_t> Data, uint32_t Offset,
  88. SmallVectorImpl<TiReference> &Refs) {
  89. // 0: Kind
  90. // 2: Padding
  91. // 4: Encoded Integer
  92. // <next>: Name
  93. uint32_t Size = 4 + getEncodedIntegerLength(Data.drop_front(4));
  94. return Size + getCStringLength(Data.drop_front(Size));
  95. }
  96. static uint32_t handleDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
  97. SmallVectorImpl<TiReference> &Refs) {
  98. // 0: Kind
  99. // 2: Padding
  100. // 4: TypeIndex
  101. // 8: Encoded Integer
  102. // <next>: Name
  103. Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
  104. uint32_t Size = 8 + getEncodedIntegerLength(Data.drop_front(8));
  105. return Size + getCStringLength(Data.drop_front(Size));
  106. }
  107. static uint32_t handleOverloadedMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
  108. SmallVectorImpl<TiReference> &Refs) {
  109. // 0: Kind
  110. // 2: Padding
  111. // 4: TypeIndex
  112. // 8: Name
  113. Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
  114. return 8 + getCStringLength(Data.drop_front(8));
  115. }
  116. static uint32_t handleOneMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
  117. SmallVectorImpl<TiReference> &Refs) {
  118. // 0: Kind
  119. // 2: Attributes
  120. // 4: Type
  121. // if (isIntroVirtual)
  122. // 8: VFTableOffset
  123. // <next>: Name
  124. uint32_t Size = 8;
  125. Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
  126. uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data());
  127. if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
  128. Size += 4;
  129. return Size + getCStringLength(Data.drop_front(Size));
  130. }
  131. static uint32_t handleNestedType(ArrayRef<uint8_t> Data, uint32_t Offset,
  132. SmallVectorImpl<TiReference> &Refs) {
  133. // 0: Kind
  134. // 2: Padding
  135. // 4: TypeIndex
  136. // 8: Name
  137. Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
  138. return 8 + getCStringLength(Data.drop_front(8));
  139. }
  140. static uint32_t handleStaticDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
  141. SmallVectorImpl<TiReference> &Refs) {
  142. // 0: Kind
  143. // 2: Padding
  144. // 4: TypeIndex
  145. // 8: Name
  146. Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
  147. return 8 + getCStringLength(Data.drop_front(8));
  148. }
  149. static uint32_t handleVirtualBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
  150. bool IsIndirect,
  151. SmallVectorImpl<TiReference> &Refs) {
  152. // 0: Kind
  153. // 2: Attrs
  154. // 4: TypeIndex
  155. // 8: TypeIndex
  156. // 12: Encoded Integer
  157. // <next>: Encoded Integer
  158. uint32_t Size = 12;
  159. Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2});
  160. Size += getEncodedIntegerLength(Data.drop_front(Size));
  161. Size += getEncodedIntegerLength(Data.drop_front(Size));
  162. return Size;
  163. }
  164. static uint32_t handleVFPtr(ArrayRef<uint8_t> Data, uint32_t Offset,
  165. SmallVectorImpl<TiReference> &Refs) {
  166. // 0: Kind
  167. // 2: Padding
  168. // 4: TypeIndex
  169. Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
  170. return 8;
  171. }
  172. static uint32_t handleListContinuation(ArrayRef<uint8_t> Data, uint32_t Offset,
  173. SmallVectorImpl<TiReference> &Refs) {
  174. // 0: Kind
  175. // 2: Padding
  176. // 4: TypeIndex
  177. Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
  178. return 8;
  179. }
  180. static void handleFieldList(ArrayRef<uint8_t> Content,
  181. SmallVectorImpl<TiReference> &Refs) {
  182. uint32_t Offset = 0;
  183. uint32_t ThisLen = 0;
  184. while (!Content.empty()) {
  185. TypeLeafKind Kind =
  186. static_cast<TypeLeafKind>(support::endian::read16le(Content.data()));
  187. switch (Kind) {
  188. case LF_BCLASS:
  189. ThisLen = handleBaseClass(Content, Offset, Refs);
  190. break;
  191. case LF_ENUMERATE:
  192. ThisLen = handleEnumerator(Content, Offset, Refs);
  193. break;
  194. case LF_MEMBER:
  195. ThisLen = handleDataMember(Content, Offset, Refs);
  196. break;
  197. case LF_METHOD:
  198. ThisLen = handleOverloadedMethod(Content, Offset, Refs);
  199. break;
  200. case LF_ONEMETHOD:
  201. ThisLen = handleOneMethod(Content, Offset, Refs);
  202. break;
  203. case LF_NESTTYPE:
  204. ThisLen = handleNestedType(Content, Offset, Refs);
  205. break;
  206. case LF_STMEMBER:
  207. ThisLen = handleStaticDataMember(Content, Offset, Refs);
  208. break;
  209. case LF_VBCLASS:
  210. case LF_IVBCLASS:
  211. ThisLen =
  212. handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs);
  213. break;
  214. case LF_VFUNCTAB:
  215. ThisLen = handleVFPtr(Content, Offset, Refs);
  216. break;
  217. case LF_INDEX:
  218. ThisLen = handleListContinuation(Content, Offset, Refs);
  219. break;
  220. default:
  221. return;
  222. }
  223. Content = Content.drop_front(ThisLen);
  224. Offset += ThisLen;
  225. if (!Content.empty()) {
  226. uint8_t Pad = Content.front();
  227. if (Pad >= LF_PAD0) {
  228. uint32_t Skip = Pad & 0x0F;
  229. Content = Content.drop_front(Skip);
  230. Offset += Skip;
  231. }
  232. }
  233. }
  234. }
  235. static void handlePointer(ArrayRef<uint8_t> Content,
  236. SmallVectorImpl<TiReference> &Refs) {
  237. Refs.push_back({TiRefKind::TypeRef, 0, 1});
  238. uint32_t Attrs = support::endian::read32le(Content.drop_front(4).data());
  239. if (isMemberPointer(Attrs))
  240. Refs.push_back({TiRefKind::TypeRef, 8, 1});
  241. }
  242. static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind,
  243. SmallVectorImpl<TiReference> &Refs) {
  244. uint32_t Count;
  245. // FIXME: In the future it would be nice if we could avoid hardcoding these
  246. // values. One idea is to define some structures representing these types
  247. // that would allow the use of offsetof().
  248. switch (Kind) {
  249. case TypeLeafKind::LF_FUNC_ID:
  250. Refs.push_back({TiRefKind::IndexRef, 0, 1});
  251. Refs.push_back({TiRefKind::TypeRef, 4, 1});
  252. break;
  253. case TypeLeafKind::LF_MFUNC_ID:
  254. Refs.push_back({TiRefKind::TypeRef, 0, 2});
  255. break;
  256. case TypeLeafKind::LF_STRING_ID:
  257. Refs.push_back({TiRefKind::IndexRef, 0, 1});
  258. break;
  259. case TypeLeafKind::LF_SUBSTR_LIST:
  260. Count = support::endian::read32le(Content.data());
  261. if (Count > 0)
  262. Refs.push_back({TiRefKind::IndexRef, 4, Count});
  263. break;
  264. case TypeLeafKind::LF_BUILDINFO:
  265. Count = support::endian::read16le(Content.data());
  266. if (Count > 0)
  267. Refs.push_back({TiRefKind::IndexRef, 2, Count});
  268. break;
  269. case TypeLeafKind::LF_UDT_SRC_LINE:
  270. Refs.push_back({TiRefKind::TypeRef, 0, 1});
  271. Refs.push_back({TiRefKind::IndexRef, 4, 1});
  272. break;
  273. case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
  274. Refs.push_back({TiRefKind::TypeRef, 0, 1});
  275. break;
  276. case TypeLeafKind::LF_MODIFIER:
  277. Refs.push_back({TiRefKind::TypeRef, 0, 1});
  278. break;
  279. case TypeLeafKind::LF_PROCEDURE:
  280. Refs.push_back({TiRefKind::TypeRef, 0, 1});
  281. Refs.push_back({TiRefKind::TypeRef, 8, 1});
  282. break;
  283. case TypeLeafKind::LF_MFUNCTION:
  284. Refs.push_back({TiRefKind::TypeRef, 0, 3});
  285. Refs.push_back({TiRefKind::TypeRef, 16, 1});
  286. break;
  287. case TypeLeafKind::LF_ARGLIST:
  288. Count = support::endian::read32le(Content.data());
  289. if (Count > 0)
  290. Refs.push_back({TiRefKind::TypeRef, 4, Count});
  291. break;
  292. case TypeLeafKind::LF_ARRAY:
  293. Refs.push_back({TiRefKind::TypeRef, 0, 2});
  294. break;
  295. case TypeLeafKind::LF_CLASS:
  296. case TypeLeafKind::LF_STRUCTURE:
  297. case TypeLeafKind::LF_INTERFACE:
  298. Refs.push_back({TiRefKind::TypeRef, 4, 3});
  299. break;
  300. case TypeLeafKind::LF_UNION:
  301. Refs.push_back({TiRefKind::TypeRef, 4, 1});
  302. break;
  303. case TypeLeafKind::LF_ENUM:
  304. Refs.push_back({TiRefKind::TypeRef, 4, 2});
  305. break;
  306. case TypeLeafKind::LF_BITFIELD:
  307. Refs.push_back({TiRefKind::TypeRef, 0, 1});
  308. break;
  309. case TypeLeafKind::LF_VFTABLE:
  310. Refs.push_back({TiRefKind::TypeRef, 0, 2});
  311. break;
  312. case TypeLeafKind::LF_VTSHAPE:
  313. break;
  314. case TypeLeafKind::LF_METHODLIST:
  315. handleMethodOverloadList(Content, Refs);
  316. break;
  317. case TypeLeafKind::LF_FIELDLIST:
  318. handleFieldList(Content, Refs);
  319. break;
  320. case TypeLeafKind::LF_POINTER:
  321. handlePointer(Content, Refs);
  322. break;
  323. default:
  324. break;
  325. }
  326. }
  327. void llvm::codeview::discoverTypeIndices(const CVType &Type,
  328. SmallVectorImpl<TiReference> &Refs) {
  329. ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
  330. }
  331. void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
  332. SmallVectorImpl<TiReference> &Refs) {
  333. const RecordPrefix *P =
  334. reinterpret_cast<const RecordPrefix *>(RecordData.data());
  335. TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
  336. ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);
  337. }