xref: /llvm-project/llvm/lib/XRay/BlockVerifier.cpp (revision b082c36061d68ce983885e5f8a1452e69da4e965)
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   llvm_unreachable("Unkown state!");
51 }
52 
53 struct Transition {
54   BlockVerifier::State From;
55   std::bitset<number(BlockVerifier::State::StateMax)> ToStates;
56 };
57 
58 } // namespace
59 
60 Error BlockVerifier::transition(State To) {
61   using ToSet = std::bitset<number(State::StateMax)>;
62   static constexpr std::array<const Transition, number(State::StateMax)>
63       TransitionTable{{{State::Unknown,
64                         {mask(State::BufferExtents) | mask(State::NewBuffer)}},
65 
66                        {State::BufferExtents, {mask(State::NewBuffer)}},
67 
68                        {State::NewBuffer, {mask(State::WallClockTime)}},
69 
70                        {State::WallClockTime,
71                         {mask(State::PIDEntry) | mask(State::NewCPUId)}},
72 
73                        {State::PIDEntry, {mask(State::NewCPUId)}},
74 
75                        {State::NewCPUId,
76                         {mask(State::NewCPUId) | mask(State::TSCWrap) |
77                          mask(State::CustomEvent) | mask(State::Function) |
78                          mask(State::EndOfBuffer)}},
79 
80                        {State::TSCWrap,
81                         {mask(State::TSCWrap) | mask(State::NewCPUId) |
82                          mask(State::CustomEvent) | mask(State::Function) |
83                          mask(State::EndOfBuffer)}},
84 
85                        {State::CustomEvent,
86                         {mask(State::CustomEvent) | mask(State::TSCWrap) |
87                          mask(State::NewCPUId) | mask(State::Function) |
88                          mask(State::EndOfBuffer)}},
89 
90                        {State::Function,
91                         {mask(State::Function) | mask(State::TSCWrap) |
92                          mask(State::NewCPUId) | mask(State::CustomEvent) |
93                          mask(State::CallArg) | mask(State::EndOfBuffer)}},
94 
95                        {State::CallArg,
96                         {mask(State::CallArg) | mask(State::Function) |
97                          mask(State::TSCWrap) | mask(State::NewCPUId) |
98                          mask(State::CustomEvent) | mask(State::EndOfBuffer)}},
99 
100                        {State::EndOfBuffer, {}}}};
101 
102   if (CurrentRecord >= State::StateMax)
103     return createStringError(
104         std::make_error_code(std::errc::executable_format_error),
105         "BUG (BlockVerifier): Cannot find transition table entry for %s, "
106         "transitioning to %s.",
107         recordToString(CurrentRecord).data(), recordToString(To).data());
108 
109   // If we're at an EndOfBuffer record, we ignore anything that follows that
110   // isn't a NewBuffer record.
111   if (CurrentRecord == State::EndOfBuffer && To != State::NewBuffer)
112     return Error::success();
113 
114   auto &Mapping = TransitionTable[number(CurrentRecord)];
115   auto &From = Mapping.From;
116   auto &Destinations = Mapping.ToStates;
117   assert(From == CurrentRecord && "BUG: Wrong index for record mapping.");
118   if ((Destinations & ToSet(mask(To))) == 0)
119     return createStringError(
120         std::make_error_code(std::errc::executable_format_error),
121         "BlockVerifier: Invalid transition from %s to %s.",
122         recordToString(CurrentRecord).data(), recordToString(To).data());
123 
124   CurrentRecord = To;
125   return Error::success();
126 } // namespace xray
127 
128 Error BlockVerifier::visit(BufferExtents &) {
129   return transition(State::BufferExtents);
130 }
131 
132 Error BlockVerifier::visit(WallclockRecord &) {
133   return transition(State::WallClockTime);
134 }
135 
136 Error BlockVerifier::visit(NewCPUIDRecord &) {
137   return transition(State::NewCPUId);
138 }
139 
140 Error BlockVerifier::visit(TSCWrapRecord &) {
141   return transition(State::TSCWrap);
142 }
143 
144 Error BlockVerifier::visit(CustomEventRecord &) {
145   return transition(State::CustomEvent);
146 }
147 
148 Error BlockVerifier::visit(CallArgRecord &) {
149   return transition(State::CallArg);
150 }
151 
152 Error BlockVerifier::visit(PIDRecord &) { return transition(State::PIDEntry); }
153 
154 Error BlockVerifier::visit(NewBufferRecord &) {
155   return transition(State::NewBuffer);
156 }
157 
158 Error BlockVerifier::visit(EndBufferRecord &) {
159   return transition(State::EndOfBuffer);
160 }
161 
162 Error BlockVerifier::visit(FunctionRecord &) {
163   return transition(State::Function);
164 }
165 
166 Error BlockVerifier::verify() {
167   // The known terminal conditions are the following:
168   switch (CurrentRecord) {
169   case State::EndOfBuffer:
170   case State::NewCPUId:
171   case State::CustomEvent:
172   case State::Function:
173   case State::CallArg:
174   case State::TSCWrap:
175     return Error::success();
176   default:
177     return createStringError(
178         std::make_error_code(std::errc::executable_format_error),
179         "BlockVerifier: Invalid terminal condition %s, malformed block.",
180         recordToString(CurrentRecord).data());
181   }
182 }
183 
184 void BlockVerifier::reset() { CurrentRecord = State::Unknown; }
185 
186 } // namespace xray
187 } // namespace llvm
188