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