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::StateMax
:
47 case BlockVerifier::State::Unknown
:
50 llvm_unreachable("Unkown state!");
54 BlockVerifier::State From
;
55 std::bitset
<number(BlockVerifier::State::StateMax
)> ToStates
;
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
)}},
66 {State::BufferExtents
, {mask(State::NewBuffer
)}},
68 {State::NewBuffer
, {mask(State::WallClockTime
)}},
70 {State::WallClockTime
,
71 {mask(State::PIDEntry
) | mask(State::NewCPUId
)}},
73 {State::PIDEntry
, {mask(State::NewCPUId
)}},
76 {mask(State::NewCPUId
) | mask(State::TSCWrap
) |
77 mask(State::CustomEvent
) | mask(State::Function
) |
78 mask(State::EndOfBuffer
)}},
81 {mask(State::TSCWrap
) | mask(State::NewCPUId
) |
82 mask(State::CustomEvent
) | mask(State::Function
) |
83 mask(State::EndOfBuffer
)}},
86 {mask(State::CustomEvent
) | mask(State::TSCWrap
) |
87 mask(State::NewCPUId
) | mask(State::Function
) |
88 mask(State::EndOfBuffer
)}},
91 {mask(State::Function
) | mask(State::TSCWrap
) |
92 mask(State::NewCPUId
) | mask(State::CustomEvent
) |
93 mask(State::CallArg
) | mask(State::EndOfBuffer
)}},
96 {mask(State::CallArg
) | mask(State::Function
) |
97 mask(State::TSCWrap
) | mask(State::NewCPUId
) |
98 mask(State::CustomEvent
) | mask(State::EndOfBuffer
)}},
100 {State::EndOfBuffer
, {}}}};
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());
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();
114 auto &Mapping
= TransitionTable
[number(CurrentRecord
)];
115 auto &Destinations
= Mapping
.ToStates
;
116 assert(Mapping
.From
== CurrentRecord
&&
117 "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());
125 return Error::success();
128 Error
BlockVerifier::visit(BufferExtents
&) {
129 return transition(State::BufferExtents
);
132 Error
BlockVerifier::visit(WallclockRecord
&) {
133 return transition(State::WallClockTime
);
136 Error
BlockVerifier::visit(NewCPUIDRecord
&) {
137 return transition(State::NewCPUId
);
140 Error
BlockVerifier::visit(TSCWrapRecord
&) {
141 return transition(State::TSCWrap
);
144 Error
BlockVerifier::visit(CustomEventRecord
&) {
145 return transition(State::CustomEvent
);
148 Error
BlockVerifier::visit(CallArgRecord
&) {
149 return transition(State::CallArg
);
152 Error
BlockVerifier::visit(PIDRecord
&) { return transition(State::PIDEntry
); }
154 Error
BlockVerifier::visit(NewBufferRecord
&) {
155 return transition(State::NewBuffer
);
158 Error
BlockVerifier::visit(EndBufferRecord
&) {
159 return transition(State::EndOfBuffer
);
162 Error
BlockVerifier::visit(FunctionRecord
&) {
163 return transition(State::Function
);
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
:
175 return Error::success();
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());
184 void BlockVerifier::reset() { CurrentRecord
= State::Unknown
; }