FDRRecordProducer.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. //===- FDRRecordProducer.cpp - XRay FDR Mode Record Producer --------------===//
  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/XRay/FDRRecordProducer.h"
  9. #include "llvm/Support/DataExtractor.h"
  10. #include <cstdint>
  11. namespace llvm {
  12. namespace xray {
  13. namespace {
  14. // Keep this in sync with the values written in the XRay FDR mode runtime in
  15. // compiler-rt.
  16. enum MetadataRecordKinds : uint8_t {
  17. NewBufferKind,
  18. EndOfBufferKind,
  19. NewCPUIdKind,
  20. TSCWrapKind,
  21. WalltimeMarkerKind,
  22. CustomEventMarkerKind,
  23. CallArgumentKind,
  24. BufferExtentsKind,
  25. TypedEventMarkerKind,
  26. PidKind,
  27. // This is an end marker, used to identify the upper bound for this enum.
  28. EnumEndMarker,
  29. };
  30. Expected<std::unique_ptr<Record>>
  31. metadataRecordType(const XRayFileHeader &Header, uint8_t T) {
  32. if (T >= static_cast<uint8_t>(MetadataRecordKinds::EnumEndMarker))
  33. return createStringError(std::make_error_code(std::errc::invalid_argument),
  34. "Invalid metadata record type: %d", T);
  35. switch (T) {
  36. case MetadataRecordKinds::NewBufferKind:
  37. return std::make_unique<NewBufferRecord>();
  38. case MetadataRecordKinds::EndOfBufferKind:
  39. if (Header.Version >= 2)
  40. return createStringError(
  41. std::make_error_code(std::errc::executable_format_error),
  42. "End of buffer records are no longer supported starting version "
  43. "2 of the log.");
  44. return std::make_unique<EndBufferRecord>();
  45. case MetadataRecordKinds::NewCPUIdKind:
  46. return std::make_unique<NewCPUIDRecord>();
  47. case MetadataRecordKinds::TSCWrapKind:
  48. return std::make_unique<TSCWrapRecord>();
  49. case MetadataRecordKinds::WalltimeMarkerKind:
  50. return std::make_unique<WallclockRecord>();
  51. case MetadataRecordKinds::CustomEventMarkerKind:
  52. if (Header.Version >= 5)
  53. return std::make_unique<CustomEventRecordV5>();
  54. return std::make_unique<CustomEventRecord>();
  55. case MetadataRecordKinds::CallArgumentKind:
  56. return std::make_unique<CallArgRecord>();
  57. case MetadataRecordKinds::BufferExtentsKind:
  58. return std::make_unique<BufferExtents>();
  59. case MetadataRecordKinds::TypedEventMarkerKind:
  60. return std::make_unique<TypedEventRecord>();
  61. case MetadataRecordKinds::PidKind:
  62. return std::make_unique<PIDRecord>();
  63. case MetadataRecordKinds::EnumEndMarker:
  64. llvm_unreachable("Invalid MetadataRecordKind");
  65. }
  66. llvm_unreachable("Unhandled MetadataRecordKinds enum value");
  67. }
  68. constexpr bool isMetadataIntroducer(uint8_t FirstByte) {
  69. return FirstByte & 0x01u;
  70. }
  71. } // namespace
  72. Expected<std::unique_ptr<Record>>
  73. FileBasedRecordProducer::findNextBufferExtent() {
  74. // We seek one byte at a time until we find a suitable buffer extents metadata
  75. // record introducer.
  76. std::unique_ptr<Record> R;
  77. while (!R) {
  78. auto PreReadOffset = OffsetPtr;
  79. uint8_t FirstByte = E.getU8(&OffsetPtr);
  80. if (OffsetPtr == PreReadOffset)
  81. return createStringError(
  82. std::make_error_code(std::errc::executable_format_error),
  83. "Failed reading one byte from offset %" PRId64 ".", OffsetPtr);
  84. if (isMetadataIntroducer(FirstByte)) {
  85. auto LoadedType = FirstByte >> 1;
  86. if (LoadedType == MetadataRecordKinds::BufferExtentsKind) {
  87. auto MetadataRecordOrErr = metadataRecordType(Header, LoadedType);
  88. if (!MetadataRecordOrErr)
  89. return MetadataRecordOrErr.takeError();
  90. R = std::move(MetadataRecordOrErr.get());
  91. RecordInitializer RI(E, OffsetPtr);
  92. if (auto Err = R->apply(RI))
  93. return std::move(Err);
  94. return std::move(R);
  95. }
  96. }
  97. }
  98. llvm_unreachable("Must always terminate with either an error or a record.");
  99. }
  100. Expected<std::unique_ptr<Record>> FileBasedRecordProducer::produce() {
  101. // First, we set up our result record.
  102. std::unique_ptr<Record> R;
  103. // Before we do any further reading, we should check whether we're at the end
  104. // of the current buffer we're been consuming. In FDR logs version >= 3, we
  105. // rely on the buffer extents record to determine how many bytes we should be
  106. // considering as valid records.
  107. if (Header.Version >= 3 && CurrentBufferBytes == 0) {
  108. // Find the next buffer extents record.
  109. auto BufferExtentsOrError = findNextBufferExtent();
  110. if (!BufferExtentsOrError)
  111. return joinErrors(
  112. BufferExtentsOrError.takeError(),
  113. createStringError(
  114. std::make_error_code(std::errc::executable_format_error),
  115. "Failed to find the next BufferExtents record."));
  116. R = std::move(BufferExtentsOrError.get());
  117. assert(R != nullptr);
  118. assert(isa<BufferExtents>(R.get()));
  119. auto BE = cast<BufferExtents>(R.get());
  120. CurrentBufferBytes = BE->size();
  121. return std::move(R);
  122. }
  123. //
  124. // At the top level, we read one byte to determine the type of the record to
  125. // create. This byte will comprise of the following bits:
  126. //
  127. // - offset 0: A '1' indicates a metadata record, a '0' indicates a function
  128. // record.
  129. // - offsets 1-7: For metadata records, this will indicate the kind of
  130. // metadata record should be loaded.
  131. //
  132. // We read first byte, then create the appropriate type of record to consume
  133. // the rest of the bytes.
  134. auto PreReadOffset = OffsetPtr;
  135. uint8_t FirstByte = E.getU8(&OffsetPtr);
  136. if (OffsetPtr == PreReadOffset)
  137. return createStringError(
  138. std::make_error_code(std::errc::executable_format_error),
  139. "Failed reading one byte from offset %" PRId64 ".", OffsetPtr);
  140. // For metadata records, handle especially here.
  141. if (isMetadataIntroducer(FirstByte)) {
  142. auto LoadedType = FirstByte >> 1;
  143. auto MetadataRecordOrErr = metadataRecordType(Header, LoadedType);
  144. if (!MetadataRecordOrErr)
  145. return joinErrors(
  146. MetadataRecordOrErr.takeError(),
  147. createStringError(
  148. std::make_error_code(std::errc::executable_format_error),
  149. "Encountered an unsupported metadata record (%d) "
  150. "at offset %" PRId64 ".",
  151. LoadedType, PreReadOffset));
  152. R = std::move(MetadataRecordOrErr.get());
  153. } else {
  154. R = std::make_unique<FunctionRecord>();
  155. }
  156. RecordInitializer RI(E, OffsetPtr);
  157. if (auto Err = R->apply(RI))
  158. return std::move(Err);
  159. // If we encountered a BufferExtents record, we should record the remaining
  160. // bytes for the current buffer, to determine when we should start ignoring
  161. // potentially malformed data and looking for buffer extents records.
  162. if (auto BE = dyn_cast<BufferExtents>(R.get())) {
  163. CurrentBufferBytes = BE->size();
  164. } else if (Header.Version >= 3) {
  165. if (OffsetPtr - PreReadOffset > CurrentBufferBytes)
  166. return createStringError(
  167. std::make_error_code(std::errc::executable_format_error),
  168. "Buffer over-read at offset %" PRId64 " (over-read by %" PRId64
  169. " bytes); Record Type = %s.",
  170. OffsetPtr, (OffsetPtr - PreReadOffset) - CurrentBufferBytes,
  171. Record::kindToString(R->getRecordType()).data());
  172. CurrentBufferBytes -= OffsetPtr - PreReadOffset;
  173. }
  174. assert(R != nullptr);
  175. return std::move(R);
  176. }
  177. } // namespace xray
  178. } // namespace llvm