DWARFUnitIndex.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. //===- DWARFUnitIndex.cpp -------------------------------------------------===//
  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. #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
  9. #include "llvm/ADT/STLExtras.h"
  10. #include "llvm/ADT/StringRef.h"
  11. #include "llvm/Support/DataExtractor.h"
  12. #include "llvm/Support/ErrorHandling.h"
  13. #include "llvm/Support/Format.h"
  14. #include "llvm/Support/raw_ostream.h"
  15. #include <cinttypes>
  16. #include <cstdint>
  17. using namespace llvm;
  18. namespace {
  19. enum class DWARFSectionKindV2 {
  20. DW_SECT_INFO = 1,
  21. DW_SECT_TYPES = 2,
  22. DW_SECT_ABBREV = 3,
  23. DW_SECT_LINE = 4,
  24. DW_SECT_LOC = 5,
  25. DW_SECT_STR_OFFSETS = 6,
  26. DW_SECT_MACINFO = 7,
  27. DW_SECT_MACRO = 8,
  28. };
  29. } // namespace
  30. // Return true if the section identifier is defined in the DWARFv5 standard.
  31. constexpr bool isKnownV5SectionID(uint32_t ID) {
  32. return ID >= DW_SECT_INFO && ID <= DW_SECT_RNGLISTS &&
  33. ID != DW_SECT_EXT_TYPES;
  34. }
  35. uint32_t llvm::serializeSectionKind(DWARFSectionKind Kind,
  36. unsigned IndexVersion) {
  37. if (IndexVersion == 5) {
  38. assert(isKnownV5SectionID(Kind));
  39. return static_cast<uint32_t>(Kind);
  40. }
  41. assert(IndexVersion == 2);
  42. switch (Kind) {
  43. #define CASE(S,T) \
  44. case DW_SECT_##S: \
  45. return static_cast<uint32_t>(DWARFSectionKindV2::DW_SECT_##T)
  46. CASE(INFO, INFO);
  47. CASE(EXT_TYPES, TYPES);
  48. CASE(ABBREV, ABBREV);
  49. CASE(LINE, LINE);
  50. CASE(EXT_LOC, LOC);
  51. CASE(STR_OFFSETS, STR_OFFSETS);
  52. CASE(EXT_MACINFO, MACINFO);
  53. CASE(MACRO, MACRO);
  54. #undef CASE
  55. default:
  56. // All other section kinds have no corresponding values in v2 indexes.
  57. llvm_unreachable("Invalid DWARFSectionKind");
  58. }
  59. }
  60. DWARFSectionKind llvm::deserializeSectionKind(uint32_t Value,
  61. unsigned IndexVersion) {
  62. if (IndexVersion == 5)
  63. return isKnownV5SectionID(Value)
  64. ? static_cast<DWARFSectionKind>(Value)
  65. : DW_SECT_EXT_unknown;
  66. assert(IndexVersion == 2);
  67. switch (static_cast<DWARFSectionKindV2>(Value)) {
  68. #define CASE(S,T) \
  69. case DWARFSectionKindV2::DW_SECT_##S: \
  70. return DW_SECT_##T
  71. CASE(INFO, INFO);
  72. CASE(TYPES, EXT_TYPES);
  73. CASE(ABBREV, ABBREV);
  74. CASE(LINE, LINE);
  75. CASE(LOC, EXT_LOC);
  76. CASE(STR_OFFSETS, STR_OFFSETS);
  77. CASE(MACINFO, EXT_MACINFO);
  78. CASE(MACRO, MACRO);
  79. #undef CASE
  80. }
  81. return DW_SECT_EXT_unknown;
  82. }
  83. bool DWARFUnitIndex::Header::parse(DataExtractor IndexData,
  84. uint64_t *OffsetPtr) {
  85. const uint64_t BeginOffset = *OffsetPtr;
  86. if (!IndexData.isValidOffsetForDataOfSize(*OffsetPtr, 16))
  87. return false;
  88. // GCC Debug Fission defines the version as an unsigned 32-bit field
  89. // with value of 2, https://gcc.gnu.org/wiki/DebugFissionDWP.
  90. // DWARFv5 defines the same space as an uhalf version field with value of 5
  91. // and a 2 bytes long padding, see Section 7.3.5.3.
  92. Version = IndexData.getU32(OffsetPtr);
  93. if (Version != 2) {
  94. *OffsetPtr = BeginOffset;
  95. Version = IndexData.getU16(OffsetPtr);
  96. if (Version != 5)
  97. return false;
  98. *OffsetPtr += 2; // Skip padding.
  99. }
  100. NumColumns = IndexData.getU32(OffsetPtr);
  101. NumUnits = IndexData.getU32(OffsetPtr);
  102. NumBuckets = IndexData.getU32(OffsetPtr);
  103. return true;
  104. }
  105. void DWARFUnitIndex::Header::dump(raw_ostream &OS) const {
  106. OS << format("version = %u, units = %u, slots = %u\n\n", Version, NumUnits, NumBuckets);
  107. }
  108. bool DWARFUnitIndex::parse(DataExtractor IndexData) {
  109. bool b = parseImpl(IndexData);
  110. if (!b) {
  111. // Make sure we don't try to dump anything
  112. Header.NumBuckets = 0;
  113. // Release any partially initialized data.
  114. ColumnKinds.reset();
  115. Rows.reset();
  116. }
  117. return b;
  118. }
  119. bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) {
  120. uint64_t Offset = 0;
  121. if (!Header.parse(IndexData, &Offset))
  122. return false;
  123. // Fix InfoColumnKind: in DWARFv5, type units are in .debug_info.dwo.
  124. if (Header.Version == 5)
  125. InfoColumnKind = DW_SECT_INFO;
  126. if (!IndexData.isValidOffsetForDataOfSize(
  127. Offset, Header.NumBuckets * (8 + 4) +
  128. (2 * Header.NumUnits + 1) * 4 * Header.NumColumns))
  129. return false;
  130. Rows = std::make_unique<Entry[]>(Header.NumBuckets);
  131. auto Contribs =
  132. std::make_unique<Entry::SectionContribution *[]>(Header.NumUnits);
  133. ColumnKinds = std::make_unique<DWARFSectionKind[]>(Header.NumColumns);
  134. RawSectionIds = std::make_unique<uint32_t[]>(Header.NumColumns);
  135. // Read Hash Table of Signatures
  136. for (unsigned i = 0; i != Header.NumBuckets; ++i)
  137. Rows[i].Signature = IndexData.getU64(&Offset);
  138. // Read Parallel Table of Indexes
  139. for (unsigned i = 0; i != Header.NumBuckets; ++i) {
  140. auto Index = IndexData.getU32(&Offset);
  141. if (!Index)
  142. continue;
  143. Rows[i].Index = this;
  144. Rows[i].Contributions =
  145. std::make_unique<Entry::SectionContribution[]>(Header.NumColumns);
  146. Contribs[Index - 1] = Rows[i].Contributions.get();
  147. }
  148. // Read the Column Headers
  149. for (unsigned i = 0; i != Header.NumColumns; ++i) {
  150. RawSectionIds[i] = IndexData.getU32(&Offset);
  151. ColumnKinds[i] = deserializeSectionKind(RawSectionIds[i], Header.Version);
  152. if (ColumnKinds[i] == InfoColumnKind) {
  153. if (InfoColumn != -1)
  154. return false;
  155. InfoColumn = i;
  156. }
  157. }
  158. if (InfoColumn == -1)
  159. return false;
  160. // Read Table of Section Offsets
  161. for (unsigned i = 0; i != Header.NumUnits; ++i) {
  162. auto *Contrib = Contribs[i];
  163. for (unsigned i = 0; i != Header.NumColumns; ++i)
  164. Contrib[i].setOffset(IndexData.getU32(&Offset));
  165. }
  166. // Read Table of Section Sizes
  167. for (unsigned i = 0; i != Header.NumUnits; ++i) {
  168. auto *Contrib = Contribs[i];
  169. for (unsigned i = 0; i != Header.NumColumns; ++i)
  170. Contrib[i].setLength(IndexData.getU32(&Offset));
  171. }
  172. return true;
  173. }
  174. StringRef DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS) {
  175. switch (DS) {
  176. #define HANDLE_DW_SECT(ID, NAME) \
  177. case DW_SECT_##NAME: \
  178. return #NAME;
  179. #include "llvm/BinaryFormat/Dwarf.def"
  180. case DW_SECT_EXT_TYPES:
  181. return "TYPES";
  182. case DW_SECT_EXT_LOC:
  183. return "LOC";
  184. case DW_SECT_EXT_MACINFO:
  185. return "MACINFO";
  186. case DW_SECT_EXT_unknown:
  187. return StringRef();
  188. }
  189. llvm_unreachable("Unknown DWARFSectionKind");
  190. }
  191. void DWARFUnitIndex::dump(raw_ostream &OS) const {
  192. if (!*this)
  193. return;
  194. Header.dump(OS);
  195. OS << "Index Signature ";
  196. for (unsigned i = 0; i != Header.NumColumns; ++i) {
  197. DWARFSectionKind Kind = ColumnKinds[i];
  198. StringRef Name = getColumnHeader(Kind);
  199. if (!Name.empty())
  200. OS << ' '
  201. << left_justify(Name,
  202. Kind == DWARFSectionKind::DW_SECT_INFO ? 40 : 24);
  203. else
  204. OS << format(" Unknown: %-15" PRIu32, RawSectionIds[i]);
  205. }
  206. OS << "\n----- ------------------";
  207. for (unsigned i = 0; i != Header.NumColumns; ++i) {
  208. DWARFSectionKind Kind = ColumnKinds[i];
  209. if (Kind == DWARFSectionKind::DW_SECT_INFO ||
  210. Kind == DWARFSectionKind::DW_SECT_EXT_TYPES)
  211. OS << " ----------------------------------------";
  212. else
  213. OS << " ------------------------";
  214. }
  215. OS << '\n';
  216. for (unsigned i = 0; i != Header.NumBuckets; ++i) {
  217. auto &Row = Rows[i];
  218. if (auto *Contribs = Row.Contributions.get()) {
  219. OS << format("%5u 0x%016" PRIx64 " ", i + 1, Row.Signature);
  220. for (unsigned i = 0; i != Header.NumColumns; ++i) {
  221. auto &Contrib = Contribs[i];
  222. DWARFSectionKind Kind = ColumnKinds[i];
  223. if (Kind == DWARFSectionKind::DW_SECT_INFO ||
  224. Kind == DWARFSectionKind::DW_SECT_EXT_TYPES)
  225. OS << format("[0x%016" PRIx64 ", 0x%016" PRIx64 ") ",
  226. Contrib.getOffset(),
  227. Contrib.getOffset() + Contrib.getLength());
  228. else
  229. OS << format("[0x%08" PRIx32 ", 0x%08" PRIx32 ") ",
  230. Contrib.getOffset32(),
  231. Contrib.getOffset32() + Contrib.getLength32());
  232. }
  233. OS << '\n';
  234. }
  235. }
  236. }
  237. const DWARFUnitIndex::Entry::SectionContribution *
  238. DWARFUnitIndex::Entry::getContribution(DWARFSectionKind Sec) const {
  239. uint32_t i = 0;
  240. for (; i != Index->Header.NumColumns; ++i)
  241. if (Index->ColumnKinds[i] == Sec)
  242. return &Contributions[i];
  243. return nullptr;
  244. }
  245. DWARFUnitIndex::Entry::SectionContribution &
  246. DWARFUnitIndex::Entry::getContribution() {
  247. return Contributions[Index->InfoColumn];
  248. }
  249. const DWARFUnitIndex::Entry::SectionContribution *
  250. DWARFUnitIndex::Entry::getContribution() const {
  251. return &Contributions[Index->InfoColumn];
  252. }
  253. const DWARFUnitIndex::Entry *
  254. DWARFUnitIndex::getFromOffset(uint64_t Offset) const {
  255. if (OffsetLookup.empty()) {
  256. for (uint32_t i = 0; i != Header.NumBuckets; ++i)
  257. if (Rows[i].Contributions)
  258. OffsetLookup.push_back(&Rows[i]);
  259. llvm::sort(OffsetLookup, [&](Entry *E1, Entry *E2) {
  260. return E1->Contributions[InfoColumn].getOffset() <
  261. E2->Contributions[InfoColumn].getOffset();
  262. });
  263. }
  264. auto I = partition_point(OffsetLookup, [&](Entry *E2) {
  265. return E2->Contributions[InfoColumn].getOffset() <= Offset;
  266. });
  267. if (I == OffsetLookup.begin())
  268. return nullptr;
  269. --I;
  270. const auto *E = *I;
  271. const auto &InfoContrib = E->Contributions[InfoColumn];
  272. if ((InfoContrib.getOffset() + InfoContrib.getLength()) <= Offset)
  273. return nullptr;
  274. return E;
  275. }
  276. const DWARFUnitIndex::Entry *DWARFUnitIndex::getFromHash(uint64_t S) const {
  277. uint64_t Mask = Header.NumBuckets - 1;
  278. auto H = S & Mask;
  279. auto HP = ((S >> 32) & Mask) | 1;
  280. // The spec says "while 0 is a valid hash value, the row index in a used slot
  281. // will always be non-zero". Loop until we find a match or an empty slot.
  282. while (Rows[H].getSignature() != S && Rows[H].Index != nullptr)
  283. H = (H + HP) & Mask;
  284. // If the slot is empty, we don't care whether the signature matches (it could
  285. // be zero and still match the zeros in the empty slot).
  286. if (Rows[H].Index == nullptr)
  287. return nullptr;
  288. return &Rows[H];
  289. }