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"
15 constexpr unsigned long long mask(BlockVerifier::State S
) {
16 return 1uLL << static_cast<std::size_t>(S
);
19 constexpr std::size_t number(BlockVerifier::State S
) {
20 return static_cast<std::size_t>(S
);
23 StringRef
recordToString(BlockVerifier::State R
) {
25 case BlockVerifier::State::BufferExtents
:
26 return "BufferExtents";
27 case BlockVerifier::State::NewBuffer
:
29 case BlockVerifier::State::WallClockTime
:
30 return "WallClockTime";
31 case BlockVerifier::State::PIDEntry
:
33 case BlockVerifier::State::NewCPUId
:
35 case BlockVerifier::State::TSCWrap
:
37 case BlockVerifier::State::CustomEvent
:
39 case BlockVerifier::State::Function
:
41 case BlockVerifier::State::CallArg
:
43 case BlockVerifier::State::EndOfBuffer
:
45 case BlockVerifier::State::TypedEvent
:
47 case BlockVerifier::State::StateMax
:
48 case BlockVerifier::State::Unknown
:
51 llvm_unreachable("Unkown state!");
55 BlockVerifier::State From
;
56 std::bitset
<number(BlockVerifier::State::StateMax
)> ToStates
;
61 Error
BlockVerifier::transition(State To
) {
62 using ToSet
= std::bitset
<number(State::StateMax
)>;
63 static constexpr std::array
<const Transition
, number(State::StateMax
)>
64 TransitionTable
{{{State::Unknown
,
65 {mask(State::BufferExtents
) | mask(State::NewBuffer
)}},
67 {State::BufferExtents
, {mask(State::NewBuffer
)}},
69 {State::NewBuffer
, {mask(State::WallClockTime
)}},
71 {State::WallClockTime
,
72 {mask(State::PIDEntry
) | mask(State::NewCPUId
)}},
74 {State::PIDEntry
, {mask(State::NewCPUId
)}},
77 {mask(State::NewCPUId
) | mask(State::TSCWrap
) |
78 mask(State::CustomEvent
) | mask(State::Function
) |
79 mask(State::EndOfBuffer
) | mask(State::TypedEvent
)}},
82 {mask(State::TSCWrap
) | mask(State::NewCPUId
) |
83 mask(State::CustomEvent
) | mask(State::Function
) |
84 mask(State::EndOfBuffer
) | mask(State::TypedEvent
)}},
87 {mask(State::CustomEvent
) | mask(State::TSCWrap
) |
88 mask(State::NewCPUId
) | mask(State::Function
) |
89 mask(State::EndOfBuffer
) | mask(State::TypedEvent
)}},
92 {mask(State::TypedEvent
) | mask(State::TSCWrap
) |
93 mask(State::NewCPUId
) | mask(State::Function
) |
94 mask(State::EndOfBuffer
) | mask(State::CustomEvent
)}},
97 {mask(State::Function
) | mask(State::TSCWrap
) |
98 mask(State::NewCPUId
) | mask(State::CustomEvent
) |
99 mask(State::CallArg
) | mask(State::EndOfBuffer
) |
100 mask(State::TypedEvent
)}},
103 {mask(State::CallArg
) | mask(State::Function
) |
104 mask(State::TSCWrap
) | mask(State::NewCPUId
) |
105 mask(State::CustomEvent
) | mask(State::EndOfBuffer
) |
106 mask(State::TypedEvent
)}},
108 {State::EndOfBuffer
, {}}}};
110 if (CurrentRecord
>= State::StateMax
)
111 return createStringError(
112 std::make_error_code(std::errc::executable_format_error
),
113 "BUG (BlockVerifier): Cannot find transition table entry for %s, "
114 "transitioning to %s.",
115 recordToString(CurrentRecord
).data(), recordToString(To
).data());
117 // If we're at an EndOfBuffer record, we ignore anything that follows that
118 // isn't a NewBuffer record.
119 if (CurrentRecord
== State::EndOfBuffer
&& To
!= State::NewBuffer
)
120 return Error::success();
122 auto &Mapping
= TransitionTable
[number(CurrentRecord
)];
123 auto &Destinations
= Mapping
.ToStates
;
124 assert(Mapping
.From
== CurrentRecord
&&
125 "BUG: Wrong index for record mapping.");
126 if ((Destinations
& ToSet(mask(To
))) == 0)
127 return createStringError(
128 std::make_error_code(std::errc::executable_format_error
),
129 "BlockVerifier: Invalid transition from %s to %s.",
130 recordToString(CurrentRecord
).data(), recordToString(To
).data());
133 return Error::success();
136 Error
BlockVerifier::visit(BufferExtents
&) {
137 return transition(State::BufferExtents
);
140 Error
BlockVerifier::visit(WallclockRecord
&) {
141 return transition(State::WallClockTime
);
144 Error
BlockVerifier::visit(NewCPUIDRecord
&) {
145 return transition(State::NewCPUId
);
148 Error
BlockVerifier::visit(TSCWrapRecord
&) {
149 return transition(State::TSCWrap
);
152 Error
BlockVerifier::visit(CustomEventRecord
&) {
153 return transition(State::CustomEvent
);
156 Error
BlockVerifier::visit(CustomEventRecordV5
&) {
157 return transition(State::CustomEvent
);
160 Error
BlockVerifier::visit(TypedEventRecord
&) {
161 return transition(State::TypedEvent
);
164 Error
BlockVerifier::visit(CallArgRecord
&) {
165 return transition(State::CallArg
);
168 Error
BlockVerifier::visit(PIDRecord
&) { return transition(State::PIDEntry
); }
170 Error
BlockVerifier::visit(NewBufferRecord
&) {
171 return transition(State::NewBuffer
);
174 Error
BlockVerifier::visit(EndBufferRecord
&) {
175 return transition(State::EndOfBuffer
);
178 Error
BlockVerifier::visit(FunctionRecord
&) {
179 return transition(State::Function
);
182 Error
BlockVerifier::verify() {
183 // The known terminal conditions are the following:
184 switch (CurrentRecord
) {
185 case State::EndOfBuffer
:
186 case State::NewCPUId
:
187 case State::CustomEvent
:
188 case State::TypedEvent
:
189 case State::Function
:
192 return Error::success();
194 return createStringError(
195 std::make_error_code(std::errc::executable_format_error
),
196 "BlockVerifier: Invalid terminal condition %s, malformed block.",
197 recordToString(CurrentRecord
).data());
201 void BlockVerifier::reset() { CurrentRecord
= State::Unknown
; }