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