BlockVerifier.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. //===- BlockVerifier.cpp - FDR Block Verifier -----------------------------===//
  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/BlockVerifier.h"
  9. #include "llvm/Support/Error.h"
  10. namespace llvm {
  11. namespace xray {
  12. namespace {
  13. constexpr unsigned long long mask(BlockVerifier::State S) {
  14. return 1uLL << static_cast<std::size_t>(S);
  15. }
  16. constexpr std::size_t number(BlockVerifier::State S) {
  17. return static_cast<std::size_t>(S);
  18. }
  19. StringRef recordToString(BlockVerifier::State R) {
  20. switch (R) {
  21. case BlockVerifier::State::BufferExtents:
  22. return "BufferExtents";
  23. case BlockVerifier::State::NewBuffer:
  24. return "NewBuffer";
  25. case BlockVerifier::State::WallClockTime:
  26. return "WallClockTime";
  27. case BlockVerifier::State::PIDEntry:
  28. return "PIDEntry";
  29. case BlockVerifier::State::NewCPUId:
  30. return "NewCPUId";
  31. case BlockVerifier::State::TSCWrap:
  32. return "TSCWrap";
  33. case BlockVerifier::State::CustomEvent:
  34. return "CustomEvent";
  35. case BlockVerifier::State::Function:
  36. return "Function";
  37. case BlockVerifier::State::CallArg:
  38. return "CallArg";
  39. case BlockVerifier::State::EndOfBuffer:
  40. return "EndOfBuffer";
  41. case BlockVerifier::State::TypedEvent:
  42. return "TypedEvent";
  43. case BlockVerifier::State::StateMax:
  44. case BlockVerifier::State::Unknown:
  45. return "Unknown";
  46. }
  47. llvm_unreachable("Unkown state!");
  48. }
  49. struct Transition {
  50. BlockVerifier::State From;
  51. std::bitset<number(BlockVerifier::State::StateMax)> ToStates;
  52. };
  53. } // namespace
  54. Error BlockVerifier::transition(State To) {
  55. using ToSet = std::bitset<number(State::StateMax)>;
  56. static constexpr std::array<const Transition, number(State::StateMax)>
  57. TransitionTable{{{State::Unknown,
  58. {mask(State::BufferExtents) | mask(State::NewBuffer)}},
  59. {State::BufferExtents, {mask(State::NewBuffer)}},
  60. {State::NewBuffer, {mask(State::WallClockTime)}},
  61. {State::WallClockTime,
  62. {mask(State::PIDEntry) | mask(State::NewCPUId)}},
  63. {State::PIDEntry, {mask(State::NewCPUId)}},
  64. {State::NewCPUId,
  65. {mask(State::NewCPUId) | mask(State::TSCWrap) |
  66. mask(State::CustomEvent) | mask(State::Function) |
  67. mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
  68. {State::TSCWrap,
  69. {mask(State::TSCWrap) | mask(State::NewCPUId) |
  70. mask(State::CustomEvent) | mask(State::Function) |
  71. mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
  72. {State::CustomEvent,
  73. {mask(State::CustomEvent) | mask(State::TSCWrap) |
  74. mask(State::NewCPUId) | mask(State::Function) |
  75. mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
  76. {State::TypedEvent,
  77. {mask(State::TypedEvent) | mask(State::TSCWrap) |
  78. mask(State::NewCPUId) | mask(State::Function) |
  79. mask(State::EndOfBuffer) | mask(State::CustomEvent)}},
  80. {State::Function,
  81. {mask(State::Function) | mask(State::TSCWrap) |
  82. mask(State::NewCPUId) | mask(State::CustomEvent) |
  83. mask(State::CallArg) | mask(State::EndOfBuffer) |
  84. mask(State::TypedEvent)}},
  85. {State::CallArg,
  86. {mask(State::CallArg) | mask(State::Function) |
  87. mask(State::TSCWrap) | mask(State::NewCPUId) |
  88. mask(State::CustomEvent) | mask(State::EndOfBuffer) |
  89. mask(State::TypedEvent)}},
  90. {State::EndOfBuffer, {}}}};
  91. if (CurrentRecord >= State::StateMax)
  92. return createStringError(
  93. std::make_error_code(std::errc::executable_format_error),
  94. "BUG (BlockVerifier): Cannot find transition table entry for %s, "
  95. "transitioning to %s.",
  96. recordToString(CurrentRecord).data(), recordToString(To).data());
  97. // If we're at an EndOfBuffer record, we ignore anything that follows that
  98. // isn't a NewBuffer record.
  99. if (CurrentRecord == State::EndOfBuffer && To != State::NewBuffer)
  100. return Error::success();
  101. auto &Mapping = TransitionTable[number(CurrentRecord)];
  102. auto &Destinations = Mapping.ToStates;
  103. assert(Mapping.From == CurrentRecord &&
  104. "BUG: Wrong index for record mapping.");
  105. if ((Destinations & ToSet(mask(To))) == 0)
  106. return createStringError(
  107. std::make_error_code(std::errc::executable_format_error),
  108. "BlockVerifier: Invalid transition from %s to %s.",
  109. recordToString(CurrentRecord).data(), recordToString(To).data());
  110. CurrentRecord = To;
  111. return Error::success();
  112. } // namespace xray
  113. Error BlockVerifier::visit(BufferExtents &) {
  114. return transition(State::BufferExtents);
  115. }
  116. Error BlockVerifier::visit(WallclockRecord &) {
  117. return transition(State::WallClockTime);
  118. }
  119. Error BlockVerifier::visit(NewCPUIDRecord &) {
  120. return transition(State::NewCPUId);
  121. }
  122. Error BlockVerifier::visit(TSCWrapRecord &) {
  123. return transition(State::TSCWrap);
  124. }
  125. Error BlockVerifier::visit(CustomEventRecord &) {
  126. return transition(State::CustomEvent);
  127. }
  128. Error BlockVerifier::visit(CustomEventRecordV5 &) {
  129. return transition(State::CustomEvent);
  130. }
  131. Error BlockVerifier::visit(TypedEventRecord &) {
  132. return transition(State::TypedEvent);
  133. }
  134. Error BlockVerifier::visit(CallArgRecord &) {
  135. return transition(State::CallArg);
  136. }
  137. Error BlockVerifier::visit(PIDRecord &) { return transition(State::PIDEntry); }
  138. Error BlockVerifier::visit(NewBufferRecord &) {
  139. return transition(State::NewBuffer);
  140. }
  141. Error BlockVerifier::visit(EndBufferRecord &) {
  142. return transition(State::EndOfBuffer);
  143. }
  144. Error BlockVerifier::visit(FunctionRecord &) {
  145. return transition(State::Function);
  146. }
  147. Error BlockVerifier::verify() {
  148. // The known terminal conditions are the following:
  149. switch (CurrentRecord) {
  150. case State::EndOfBuffer:
  151. case State::NewCPUId:
  152. case State::CustomEvent:
  153. case State::TypedEvent:
  154. case State::Function:
  155. case State::CallArg:
  156. case State::TSCWrap:
  157. return Error::success();
  158. default:
  159. return createStringError(
  160. std::make_error_code(std::errc::executable_format_error),
  161. "BlockVerifier: Invalid terminal condition %s, malformed block.",
  162. recordToString(CurrentRecord).data());
  163. }
  164. }
  165. void BlockVerifier::reset() { CurrentRecord = State::Unknown; }
  166. } // namespace xray
  167. } // namespace llvm