DWARFDebugAddr.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. //===- DWARFDebugAddr.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/DWARFDebugAddr.h"
  9. #include "llvm/BinaryFormat/Dwarf.h"
  10. #include "llvm/DebugInfo/DWARF/DWARFContext.h"
  11. #include "llvm/Support/Errc.h"
  12. using namespace llvm;
  13. Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data,
  14. uint64_t *OffsetPtr,
  15. uint64_t EndOffset) {
  16. assert(EndOffset >= *OffsetPtr);
  17. uint64_t DataSize = EndOffset - *OffsetPtr;
  18. assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize));
  19. if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
  20. AddrSize, errc::not_supported, "address table at offset 0x%" PRIx64,
  21. Offset))
  22. return SizeErr;
  23. if (DataSize % AddrSize != 0) {
  24. invalidateLength();
  25. return createStringError(errc::invalid_argument,
  26. "address table at offset 0x%" PRIx64
  27. " contains data of size 0x%" PRIx64
  28. " which is not a multiple of addr size %" PRIu8,
  29. Offset, DataSize, AddrSize);
  30. }
  31. Addrs.clear();
  32. size_t Count = DataSize / AddrSize;
  33. Addrs.reserve(Count);
  34. while (Count--)
  35. Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr));
  36. return Error::success();
  37. }
  38. Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data,
  39. uint64_t *OffsetPtr, uint8_t CUAddrSize,
  40. std::function<void(Error)> WarnCallback) {
  41. Offset = *OffsetPtr;
  42. llvm::Error Err = Error::success();
  43. std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err);
  44. if (Err) {
  45. invalidateLength();
  46. return createStringError(errc::invalid_argument,
  47. "parsing address table at offset 0x%" PRIx64
  48. ": %s",
  49. Offset, toString(std::move(Err)).c_str());
  50. }
  51. if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) {
  52. uint64_t DiagnosticLength = Length;
  53. invalidateLength();
  54. return createStringError(
  55. errc::invalid_argument,
  56. "section is not large enough to contain an address table "
  57. "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64,
  58. Offset, DiagnosticLength);
  59. }
  60. uint64_t EndOffset = *OffsetPtr + Length;
  61. // Ensure that we can read the remaining header fields.
  62. if (Length < 4) {
  63. uint64_t DiagnosticLength = Length;
  64. invalidateLength();
  65. return createStringError(
  66. errc::invalid_argument,
  67. "address table at offset 0x%" PRIx64
  68. " has a unit_length value of 0x%" PRIx64
  69. ", which is too small to contain a complete header",
  70. Offset, DiagnosticLength);
  71. }
  72. Version = Data.getU16(OffsetPtr);
  73. AddrSize = Data.getU8(OffsetPtr);
  74. SegSize = Data.getU8(OffsetPtr);
  75. // Perform a basic validation of the header fields.
  76. if (Version != 5)
  77. return createStringError(errc::not_supported,
  78. "address table at offset 0x%" PRIx64
  79. " has unsupported version %" PRIu16,
  80. Offset, Version);
  81. // TODO: add support for non-zero segment selector size.
  82. if (SegSize != 0)
  83. return createStringError(errc::not_supported,
  84. "address table at offset 0x%" PRIx64
  85. " has unsupported segment selector size %" PRIu8,
  86. Offset, SegSize);
  87. if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset))
  88. return Err;
  89. if (CUAddrSize && AddrSize != CUAddrSize) {
  90. WarnCallback(createStringError(
  91. errc::invalid_argument,
  92. "address table at offset 0x%" PRIx64 " has address size %" PRIu8
  93. " which is different from CU address size %" PRIu8,
  94. Offset, AddrSize, CUAddrSize));
  95. }
  96. return Error::success();
  97. }
  98. Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data,
  99. uint64_t *OffsetPtr,
  100. uint16_t CUVersion,
  101. uint8_t CUAddrSize) {
  102. assert(CUVersion > 0 && CUVersion < 5);
  103. Offset = *OffsetPtr;
  104. Length = 0;
  105. Version = CUVersion;
  106. AddrSize = CUAddrSize;
  107. SegSize = 0;
  108. return extractAddresses(Data, OffsetPtr, Data.size());
  109. }
  110. Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data,
  111. uint64_t *OffsetPtr,
  112. uint16_t CUVersion,
  113. uint8_t CUAddrSize,
  114. std::function<void(Error)> WarnCallback) {
  115. if (CUVersion > 0 && CUVersion < 5)
  116. return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize);
  117. if (CUVersion == 0)
  118. WarnCallback(createStringError(errc::invalid_argument,
  119. "DWARF version is not defined in CU,"
  120. " assuming version 5"));
  121. return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback);
  122. }
  123. void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
  124. if (DumpOpts.Verbose)
  125. OS << format("0x%8.8" PRIx64 ": ", Offset);
  126. if (Length) {
  127. int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format);
  128. OS << "Address table header: "
  129. << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length)
  130. << ", format = " << dwarf::FormatString(Format)
  131. << format(", version = 0x%4.4" PRIx16, Version)
  132. << format(", addr_size = 0x%2.2" PRIx8, AddrSize)
  133. << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n";
  134. }
  135. if (Addrs.size() > 0) {
  136. const char *AddrFmt;
  137. switch (AddrSize) {
  138. case 2:
  139. AddrFmt = "0x%4.4" PRIx64 "\n";
  140. break;
  141. case 4:
  142. AddrFmt = "0x%8.8" PRIx64 "\n";
  143. break;
  144. case 8:
  145. AddrFmt = "0x%16.16" PRIx64 "\n";
  146. break;
  147. default:
  148. llvm_unreachable("unsupported address size");
  149. }
  150. OS << "Addrs: [\n";
  151. for (uint64_t Addr : Addrs)
  152. OS << format(AddrFmt, Addr);
  153. OS << "]\n";
  154. }
  155. }
  156. Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
  157. if (Index < Addrs.size())
  158. return Addrs[Index];
  159. return createStringError(errc::invalid_argument,
  160. "Index %" PRIu32 " is out of range of the "
  161. "address table at offset 0x%" PRIx64,
  162. Index, Offset);
  163. }
  164. std::optional<uint64_t> DWARFDebugAddrTable::getFullLength() const {
  165. if (Length == 0)
  166. return std::nullopt;
  167. return Length + dwarf::getUnitLengthFieldByteSize(Format);
  168. }