DWARFDebugAranges.cpp 4.3 KB

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