DWARFDebugAranges.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. //===- DWARFDebugAranges.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/DWARFDebugAranges.h"
  9. #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
  10. #include "llvm/DebugInfo/DWARF/DWARFContext.h"
  11. #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
  12. #include "llvm/Support/DataExtractor.h"
  13. #include <algorithm>
  14. #include <cassert>
  15. #include <cstdint>
  16. #include <set>
  17. using namespace llvm;
  18. void DWARFDebugAranges::extract(
  19. DWARFDataExtractor DebugArangesData,
  20. function_ref<void(Error)> RecoverableErrorHandler) {
  21. if (!DebugArangesData.isValidOffset(0))
  22. return;
  23. uint64_t Offset = 0;
  24. DWARFDebugArangeSet Set;
  25. while (DebugArangesData.isValidOffset(Offset)) {
  26. if (Error E =
  27. Set.extract(DebugArangesData, &Offset, RecoverableErrorHandler)) {
  28. RecoverableErrorHandler(std::move(E));
  29. return;
  30. }
  31. uint64_t CUOffset = Set.getCompileUnitDIEOffset();
  32. for (const auto &Desc : Set.descriptors()) {
  33. uint64_t LowPC = Desc.Address;
  34. uint64_t HighPC = Desc.getEndAddress();
  35. appendRange(CUOffset, LowPC, HighPC);
  36. }
  37. ParsedCUOffsets.insert(CUOffset);
  38. }
  39. }
  40. void DWARFDebugAranges::generate(DWARFContext *CTX) {
  41. clear();
  42. if (!CTX)
  43. return;
  44. // Extract aranges from .debug_aranges section.
  45. DWARFDataExtractor ArangesData(CTX->getDWARFObj().getArangesSection(),
  46. CTX->isLittleEndian(), 0);
  47. extract(ArangesData, CTX->getRecoverableErrorHandler());
  48. // Generate aranges from DIEs: even if .debug_aranges section is present,
  49. // it may describe only a small subset of compilation units, so we need to
  50. // manually build aranges for the rest of them.
  51. for (const auto &CU : CTX->compile_units()) {
  52. uint64_t CUOffset = CU->getOffset();
  53. if (ParsedCUOffsets.insert(CUOffset).second) {
  54. Expected<DWARFAddressRangesVector> CURanges = CU->collectAddressRanges();
  55. if (!CURanges)
  56. CTX->getRecoverableErrorHandler()(CURanges.takeError());
  57. else
  58. for (const auto &R : *CURanges)
  59. appendRange(CUOffset, R.LowPC, R.HighPC);
  60. }
  61. }
  62. construct();
  63. }
  64. void DWARFDebugAranges::clear() {
  65. Endpoints.clear();
  66. Aranges.clear();
  67. ParsedCUOffsets.clear();
  68. }
  69. void DWARFDebugAranges::appendRange(uint64_t CUOffset, uint64_t LowPC,
  70. uint64_t HighPC) {
  71. if (LowPC >= HighPC)
  72. return;
  73. Endpoints.emplace_back(LowPC, CUOffset, true);
  74. Endpoints.emplace_back(HighPC, CUOffset, false);
  75. }
  76. void DWARFDebugAranges::construct() {
  77. std::multiset<uint64_t> ValidCUs; // Maintain the set of CUs describing
  78. // a current address range.
  79. llvm::sort(Endpoints);
  80. uint64_t PrevAddress = -1ULL;
  81. for (const auto &E : Endpoints) {
  82. if (PrevAddress < E.Address && !ValidCUs.empty()) {
  83. // If the address range between two endpoints is described by some
  84. // CU, first try to extend the last range in Aranges. If we can't
  85. // do it, start a new range.
  86. if (!Aranges.empty() && Aranges.back().HighPC() == PrevAddress &&
  87. ValidCUs.find(Aranges.back().CUOffset) != ValidCUs.end()) {
  88. Aranges.back().setHighPC(E.Address);
  89. } else {
  90. Aranges.emplace_back(PrevAddress, E.Address, *ValidCUs.begin());
  91. }
  92. }
  93. // Update the set of valid CUs.
  94. if (E.IsRangeStart) {
  95. ValidCUs.insert(E.CUOffset);
  96. } else {
  97. auto CUPos = ValidCUs.find(E.CUOffset);
  98. assert(CUPos != ValidCUs.end());
  99. ValidCUs.erase(CUPos);
  100. }
  101. PrevAddress = E.Address;
  102. }
  103. assert(ValidCUs.empty());
  104. // Endpoints are not needed now.
  105. Endpoints.clear();
  106. Endpoints.shrink_to_fit();
  107. }
  108. uint64_t DWARFDebugAranges::findAddress(uint64_t Address) const {
  109. RangeCollIterator It =
  110. partition_point(Aranges, [=](Range R) { return R.HighPC() <= Address; });
  111. if (It != Aranges.end() && It->LowPC <= Address)
  112. return It->CUOffset;
  113. return -1ULL;
  114. }