1 //===- BlockVerifier.cpp - FDR Block Verifier -----------------------------===//
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
7 //===----------------------------------------------------------------------===//
8 #include "llvm/XRay/BlockVerifier.h"
9 #include "llvm/Support/Error.h"
17 constexpr unsigned long long mask(BlockVerifier::State S
) {
18 return 1uLL << static_cast<std::size_t>(S
);
21 constexpr std::size_t number(BlockVerifier::State S
) {
22 return static_cast<std::size_t>(S
);
25 StringRef
recordToString(BlockVerifier::State R
) {
27 case BlockVerifier::State::BufferExtents
:
28 return "BufferExtents";
29 case BlockVerifier::State::NewBuffer
:
31 case BlockVerifier::State::WallClockTime
:
32 return "WallClockTime";
33 case BlockVerifier::State::PIDEntry
:
35 case BlockVerifier::State::NewCPUId
:
37 case BlockVerifier::State::TSCWrap
:
39 case BlockVerifier::State::CustomEvent
:
41 case BlockVerifier::State::Function
:
43 case BlockVerifier::State::CallArg
:
45 case BlockVerifier::State::EndOfBuffer
:
47 case BlockVerifier::State::TypedEvent
:
49 case BlockVerifier::State::StateMax
:
50 case BlockVerifier::State::Unknown
:
53 llvm_unreachable("Unkown state!");
57 BlockVerifier::State From
;
58 std::bitset
<number(BlockVerifier::State::StateMax
)> ToStates
;
63 Error
BlockVerifier::transition(State To
) {
64 using ToSet
= std::bitset
<number(State::StateMax
)>;
65 static constexpr std::array
<const Transition
, number(State::StateMax
)>
66 TransitionTable
{{{State::Unknown
,
67 {mask(State::BufferExtents
) | mask(State::NewBuffer
)}},
69 {State::BufferExtents
, {mask(State::NewBuffer
)}},
71 {State::NewBuffer
, {mask(State::WallClockTime
)}},
73 {State::WallClockTime
,
74 {mask(State::PIDEntry
) | mask(State::NewCPUId
)}},
76 {State::PIDEntry
, {mask(State::NewCPUId
)}},
79 {mask(State::NewCPUId
) | mask(State::TSCWrap
) |
80 mask(State::CustomEvent
) | mask(State::Function
) |
81 mask(State::EndOfBuffer
) | mask(State::TypedEvent
)}},
84 {mask(State::TSCWrap
) | mask(State::NewCPUId
) |
85 mask(State::CustomEvent
) | mask(State::Function
) |
86 mask(State::EndOfBuffer
) | mask(State::TypedEvent
)}},
89 {mask(State::CustomEvent
) | mask(State::TSCWrap
) |
90 mask(State::NewCPUId
) | mask(State::Function
) |
91 mask(State::EndOfBuffer
) | mask(State::TypedEvent
)}},
94 {mask(State::TypedEvent
) | mask(State::TSCWrap
) |
95 mask(State::NewCPUId
) | mask(State::Function
) |
96 mask(State::EndOfBuffer
) | mask(State::CustomEvent
)}},
99 {mask(State::Function
) | mask(State::TSCWrap
) |
100 mask(State::NewCPUId
) | mask(State::CustomEvent
) |
101 mask(State::CallArg
) | mask(State::EndOfBuffer
) |
102 mask(State::TypedEvent
)}},
105 {mask(State::CallArg
) | mask(State::Function
) |
106 mask(State::TSCWrap
) | mask(State::NewCPUId
) |
107 mask(State::CustomEvent
) | mask(State::EndOfBuffer
) |
108 mask(State::TypedEvent
)}},
110 {State::EndOfBuffer
, {}}}};
112 if (CurrentRecord
>= State::StateMax
)
113 return createStringError(
114 std::make_error_code(std::errc::executable_format_error
),
115 "BUG (BlockVerifier): Cannot find transition table entry for %s, "
116 "transitioning to %s.",
117 recordToString(CurrentRecord
).data(), recordToString(To
).data());
119 // If we're at an EndOfBuffer record, we ignore anything that follows that
120 // isn't a NewBuffer record.
121 if (CurrentRecord
== State::EndOfBuffer
&& To
!= State::NewBuffer
)
122 return Error::success();
124 auto &Mapping
= TransitionTable
[number(CurrentRecord
)];
125 auto &Destinations
= Mapping
.ToStates
;
126 assert(Mapping
.From
== CurrentRecord
&&
127 "BUG: Wrong index for record mapping.");
128 if ((Destinations
& ToSet(mask(To
))) == 0)
129 return createStringError(
130 std::make_error_code(std::errc::executable_format_error
),
131 "BlockVerifier: Invalid transition from %s to %s.",
132 recordToString(CurrentRecord
).data(), recordToString(To
).data());
135 return Error::success();
138 Error
BlockVerifier::visit(BufferExtents
&) {
139 return transition(State::BufferExtents
);
142 Error
BlockVerifier::visit(WallclockRecord
&) {
143 return transition(State::WallClockTime
);
146 Error
BlockVerifier::visit(NewCPUIDRecord
&) {
147 return transition(State::NewCPUId
);
150 Error
BlockVerifier::visit(TSCWrapRecord
&) {
151 return transition(State::TSCWrap
);
154 Error
BlockVerifier::visit(CustomEventRecord
&) {
155 return transition(State::CustomEvent
);
158 Error
BlockVerifier::visit(CustomEventRecordV5
&) {
159 return transition(State::CustomEvent
);
162 Error
BlockVerifier::visit(TypedEventRecord
&) {
163 return transition(State::TypedEvent
);
166 Error
BlockVerifier::visit(CallArgRecord
&) {
167 return transition(State::CallArg
);
170 Error
BlockVerifier::visit(PIDRecord
&) { return transition(State::PIDEntry
); }
172 Error
BlockVerifier::visit(NewBufferRecord
&) {
173 return transition(State::NewBuffer
);
176 Error
BlockVerifier::visit(EndBufferRecord
&) {
177 return transition(State::EndOfBuffer
);
180 Error
BlockVerifier::visit(FunctionRecord
&) {
181 return transition(State::Function
);
184 Error
BlockVerifier::verify() {
185 // The known terminal conditions are the following:
186 switch (CurrentRecord
) {
187 case State::EndOfBuffer
:
188 case State::NewCPUId
:
189 case State::CustomEvent
:
190 case State::TypedEvent
:
191 case State::Function
:
194 return Error::success();
196 return createStringError(
197 std::make_error_code(std::errc::executable_format_error
),
198 "BlockVerifier: Invalid terminal condition %s, malformed block.",
199 recordToString(CurrentRecord
).data());
203 void BlockVerifier::reset() { CurrentRecord
= State::Unknown
; }