1 //===- BlockVerifier.cpp - FDR Block Verifier -----------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
9 #include "llvm/XRay/BlockVerifier.h"
10 #include "llvm/Support/Error.h"
16 constexpr unsigned long long mask(BlockVerifier::State S) {
17 return 1uLL << static_cast<std::size_t>(S);
20 constexpr std::size_t number(BlockVerifier::State S) {
21 return static_cast<std::size_t>(S);
24 StringRef recordToString(BlockVerifier::State R) {
26 case BlockVerifier::State::BufferExtents:
27 return "BufferExtents";
28 case BlockVerifier::State::NewBuffer:
30 case BlockVerifier::State::WallClockTime:
31 return "WallClockTime";
32 case BlockVerifier::State::PIDEntry:
34 case BlockVerifier::State::NewCPUId:
36 case BlockVerifier::State::TSCWrap:
38 case BlockVerifier::State::CustomEvent:
40 case BlockVerifier::State::Function:
42 case BlockVerifier::State::CallArg:
44 case BlockVerifier::State::EndOfBuffer:
46 case BlockVerifier::State::TypedEvent:
48 case BlockVerifier::State::StateMax:
49 case BlockVerifier::State::Unknown:
52 llvm_unreachable("Unkown state!");
56 BlockVerifier::State From;
57 std::bitset<number(BlockVerifier::State::StateMax)> ToStates;
62 Error BlockVerifier::transition(State To) {
63 using ToSet = std::bitset<number(State::StateMax)>;
64 static constexpr std::array<const Transition, number(State::StateMax)>
65 TransitionTable{{{State::Unknown,
66 {mask(State::BufferExtents) | mask(State::NewBuffer)}},
68 {State::BufferExtents, {mask(State::NewBuffer)}},
70 {State::NewBuffer, {mask(State::WallClockTime)}},
72 {State::WallClockTime,
73 {mask(State::PIDEntry) | mask(State::NewCPUId)}},
75 {State::PIDEntry, {mask(State::NewCPUId)}},
78 {mask(State::NewCPUId) | mask(State::TSCWrap) |
79 mask(State::CustomEvent) | mask(State::Function) |
80 mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
83 {mask(State::TSCWrap) | mask(State::NewCPUId) |
84 mask(State::CustomEvent) | mask(State::Function) |
85 mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
88 {mask(State::CustomEvent) | mask(State::TSCWrap) |
89 mask(State::NewCPUId) | mask(State::Function) |
90 mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
93 {mask(State::TypedEvent) | mask(State::TSCWrap) |
94 mask(State::NewCPUId) | mask(State::Function) |
95 mask(State::EndOfBuffer) | mask(State::CustomEvent)}},
98 {mask(State::Function) | mask(State::TSCWrap) |
99 mask(State::NewCPUId) | mask(State::CustomEvent) |
100 mask(State::CallArg) | mask(State::EndOfBuffer) |
101 mask(State::TypedEvent)}},
104 {mask(State::CallArg) | mask(State::Function) |
105 mask(State::TSCWrap) | mask(State::NewCPUId) |
106 mask(State::CustomEvent) | mask(State::EndOfBuffer) |
107 mask(State::TypedEvent)}},
109 {State::EndOfBuffer, {}}}};
111 if (CurrentRecord >= State::StateMax)
112 return createStringError(
113 std::make_error_code(std::errc::executable_format_error),
114 "BUG (BlockVerifier): Cannot find transition table entry for %s, "
115 "transitioning to %s.",
116 recordToString(CurrentRecord).data(), recordToString(To).data());
118 // If we're at an EndOfBuffer record, we ignore anything that follows that
119 // isn't a NewBuffer record.
120 if (CurrentRecord == State::EndOfBuffer && To != State::NewBuffer)
121 return Error::success();
123 auto &Mapping = TransitionTable[number(CurrentRecord)];
124 auto &Destinations = Mapping.ToStates;
125 assert(Mapping.From == CurrentRecord &&
126 "BUG: Wrong index for record mapping.");
127 if ((Destinations & ToSet(mask(To))) == 0)
128 return createStringError(
129 std::make_error_code(std::errc::executable_format_error),
130 "BlockVerifier: Invalid transition from %s to %s.",
131 recordToString(CurrentRecord).data(), recordToString(To).data());
134 return Error::success();
137 Error BlockVerifier::visit(BufferExtents &) {
138 return transition(State::BufferExtents);
141 Error BlockVerifier::visit(WallclockRecord &) {
142 return transition(State::WallClockTime);
145 Error BlockVerifier::visit(NewCPUIDRecord &) {
146 return transition(State::NewCPUId);
149 Error BlockVerifier::visit(TSCWrapRecord &) {
150 return transition(State::TSCWrap);
153 Error BlockVerifier::visit(CustomEventRecord &) {
154 return transition(State::CustomEvent);
157 Error BlockVerifier::visit(CustomEventRecordV5 &) {
158 return transition(State::CustomEvent);
161 Error BlockVerifier::visit(TypedEventRecord &) {
162 return transition(State::TypedEvent);
165 Error BlockVerifier::visit(CallArgRecord &) {
166 return transition(State::CallArg);
169 Error BlockVerifier::visit(PIDRecord &) { return transition(State::PIDEntry); }
171 Error BlockVerifier::visit(NewBufferRecord &) {
172 return transition(State::NewBuffer);
175 Error BlockVerifier::visit(EndBufferRecord &) {
176 return transition(State::EndOfBuffer);
179 Error BlockVerifier::visit(FunctionRecord &) {
180 return transition(State::Function);
183 Error BlockVerifier::verify() {
184 // The known terminal conditions are the following:
185 switch (CurrentRecord) {
186 case State::EndOfBuffer:
187 case State::NewCPUId:
188 case State::CustomEvent:
189 case State::TypedEvent:
190 case State::Function:
193 return Error::success();
195 return createStringError(
196 std::make_error_code(std::errc::executable_format_error),
197 "BlockVerifier: Invalid terminal condition %s, malformed block.",
198 recordToString(CurrentRecord).data());
202 void BlockVerifier::reset() { CurrentRecord = State::Unknown; }