1b082c360SDean Michael Berris //===- BlockVerifier.cpp - FDR Block Verifier -----------------------------===//
2b082c360SDean Michael Berris //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b082c360SDean Michael Berris //
7b082c360SDean Michael Berris //===----------------------------------------------------------------------===//
8b082c360SDean Michael Berris #include "llvm/XRay/BlockVerifier.h"
9b082c360SDean Michael Berris #include "llvm/Support/Error.h"
10b082c360SDean Michael Berris
11*a2b71592SKazu Hirata #include <bitset>
12*a2b71592SKazu Hirata
13b082c360SDean Michael Berris namespace llvm {
14b082c360SDean Michael Berris namespace xray {
15b082c360SDean Michael Berris namespace {
16b082c360SDean Michael Berris
mask(BlockVerifier::State S)17b082c360SDean Michael Berris constexpr unsigned long long mask(BlockVerifier::State S) {
18b082c360SDean Michael Berris return 1uLL << static_cast<std::size_t>(S);
19b082c360SDean Michael Berris }
20b082c360SDean Michael Berris
number(BlockVerifier::State S)21b082c360SDean Michael Berris constexpr std::size_t number(BlockVerifier::State S) {
22b082c360SDean Michael Berris return static_cast<std::size_t>(S);
23b082c360SDean Michael Berris }
24b082c360SDean Michael Berris
recordToString(BlockVerifier::State R)25b082c360SDean Michael Berris StringRef recordToString(BlockVerifier::State R) {
26b082c360SDean Michael Berris switch (R) {
27b082c360SDean Michael Berris case BlockVerifier::State::BufferExtents:
28b082c360SDean Michael Berris return "BufferExtents";
29b082c360SDean Michael Berris case BlockVerifier::State::NewBuffer:
30b082c360SDean Michael Berris return "NewBuffer";
31b082c360SDean Michael Berris case BlockVerifier::State::WallClockTime:
32b082c360SDean Michael Berris return "WallClockTime";
33b082c360SDean Michael Berris case BlockVerifier::State::PIDEntry:
34b082c360SDean Michael Berris return "PIDEntry";
35b082c360SDean Michael Berris case BlockVerifier::State::NewCPUId:
36b082c360SDean Michael Berris return "NewCPUId";
37b082c360SDean Michael Berris case BlockVerifier::State::TSCWrap:
38b082c360SDean Michael Berris return "TSCWrap";
39b082c360SDean Michael Berris case BlockVerifier::State::CustomEvent:
40b082c360SDean Michael Berris return "CustomEvent";
41b082c360SDean Michael Berris case BlockVerifier::State::Function:
42b082c360SDean Michael Berris return "Function";
43b082c360SDean Michael Berris case BlockVerifier::State::CallArg:
44b082c360SDean Michael Berris return "CallArg";
45b082c360SDean Michael Berris case BlockVerifier::State::EndOfBuffer:
46b082c360SDean Michael Berris return "EndOfBuffer";
4759439dd0SDean Michael Berris case BlockVerifier::State::TypedEvent:
4859439dd0SDean Michael Berris return "TypedEvent";
49b082c360SDean Michael Berris case BlockVerifier::State::StateMax:
50b082c360SDean Michael Berris case BlockVerifier::State::Unknown:
51b082c360SDean Michael Berris return "Unknown";
52b082c360SDean Michael Berris }
53b082c360SDean Michael Berris llvm_unreachable("Unkown state!");
54b082c360SDean Michael Berris }
55b082c360SDean Michael Berris
56b082c360SDean Michael Berris struct Transition {
57b082c360SDean Michael Berris BlockVerifier::State From;
58b082c360SDean Michael Berris std::bitset<number(BlockVerifier::State::StateMax)> ToStates;
59b082c360SDean Michael Berris };
60b082c360SDean Michael Berris
61b082c360SDean Michael Berris } // namespace
62b082c360SDean Michael Berris
transition(State To)63b082c360SDean Michael Berris Error BlockVerifier::transition(State To) {
64b082c360SDean Michael Berris using ToSet = std::bitset<number(State::StateMax)>;
65b082c360SDean Michael Berris static constexpr std::array<const Transition, number(State::StateMax)>
66b082c360SDean Michael Berris TransitionTable{{{State::Unknown,
67b082c360SDean Michael Berris {mask(State::BufferExtents) | mask(State::NewBuffer)}},
68b082c360SDean Michael Berris
69b082c360SDean Michael Berris {State::BufferExtents, {mask(State::NewBuffer)}},
70b082c360SDean Michael Berris
71b082c360SDean Michael Berris {State::NewBuffer, {mask(State::WallClockTime)}},
72b082c360SDean Michael Berris
73b082c360SDean Michael Berris {State::WallClockTime,
74b082c360SDean Michael Berris {mask(State::PIDEntry) | mask(State::NewCPUId)}},
75b082c360SDean Michael Berris
76b082c360SDean Michael Berris {State::PIDEntry, {mask(State::NewCPUId)}},
77b082c360SDean Michael Berris
78b082c360SDean Michael Berris {State::NewCPUId,
79b082c360SDean Michael Berris {mask(State::NewCPUId) | mask(State::TSCWrap) |
80b082c360SDean Michael Berris mask(State::CustomEvent) | mask(State::Function) |
8159439dd0SDean Michael Berris mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
82b082c360SDean Michael Berris
83b082c360SDean Michael Berris {State::TSCWrap,
84b082c360SDean Michael Berris {mask(State::TSCWrap) | mask(State::NewCPUId) |
85b082c360SDean Michael Berris mask(State::CustomEvent) | mask(State::Function) |
8659439dd0SDean Michael Berris mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
87b082c360SDean Michael Berris
88b082c360SDean Michael Berris {State::CustomEvent,
89b082c360SDean Michael Berris {mask(State::CustomEvent) | mask(State::TSCWrap) |
90b082c360SDean Michael Berris mask(State::NewCPUId) | mask(State::Function) |
9159439dd0SDean Michael Berris mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
9259439dd0SDean Michael Berris
9359439dd0SDean Michael Berris {State::TypedEvent,
9459439dd0SDean Michael Berris {mask(State::TypedEvent) | mask(State::TSCWrap) |
9559439dd0SDean Michael Berris mask(State::NewCPUId) | mask(State::Function) |
9659439dd0SDean Michael Berris mask(State::EndOfBuffer) | mask(State::CustomEvent)}},
97b082c360SDean Michael Berris
98b082c360SDean Michael Berris {State::Function,
99b082c360SDean Michael Berris {mask(State::Function) | mask(State::TSCWrap) |
100b082c360SDean Michael Berris mask(State::NewCPUId) | mask(State::CustomEvent) |
10159439dd0SDean Michael Berris mask(State::CallArg) | mask(State::EndOfBuffer) |
10259439dd0SDean Michael Berris mask(State::TypedEvent)}},
103b082c360SDean Michael Berris
104b082c360SDean Michael Berris {State::CallArg,
105b082c360SDean Michael Berris {mask(State::CallArg) | mask(State::Function) |
106b082c360SDean Michael Berris mask(State::TSCWrap) | mask(State::NewCPUId) |
10759439dd0SDean Michael Berris mask(State::CustomEvent) | mask(State::EndOfBuffer) |
10859439dd0SDean Michael Berris mask(State::TypedEvent)}},
109b082c360SDean Michael Berris
110b082c360SDean Michael Berris {State::EndOfBuffer, {}}}};
111b082c360SDean Michael Berris
112b082c360SDean Michael Berris if (CurrentRecord >= State::StateMax)
113b082c360SDean Michael Berris return createStringError(
114b082c360SDean Michael Berris std::make_error_code(std::errc::executable_format_error),
115b082c360SDean Michael Berris "BUG (BlockVerifier): Cannot find transition table entry for %s, "
116b082c360SDean Michael Berris "transitioning to %s.",
117b082c360SDean Michael Berris recordToString(CurrentRecord).data(), recordToString(To).data());
118b082c360SDean Michael Berris
119b082c360SDean Michael Berris // If we're at an EndOfBuffer record, we ignore anything that follows that
120b082c360SDean Michael Berris // isn't a NewBuffer record.
121b082c360SDean Michael Berris if (CurrentRecord == State::EndOfBuffer && To != State::NewBuffer)
122b082c360SDean Michael Berris return Error::success();
123b082c360SDean Michael Berris
124b082c360SDean Michael Berris auto &Mapping = TransitionTable[number(CurrentRecord)];
125b082c360SDean Michael Berris auto &Destinations = Mapping.ToStates;
126f3a3679eSDean Michael Berris assert(Mapping.From == CurrentRecord &&
127f3a3679eSDean Michael Berris "BUG: Wrong index for record mapping.");
128b082c360SDean Michael Berris if ((Destinations & ToSet(mask(To))) == 0)
129b082c360SDean Michael Berris return createStringError(
130b082c360SDean Michael Berris std::make_error_code(std::errc::executable_format_error),
131b082c360SDean Michael Berris "BlockVerifier: Invalid transition from %s to %s.",
132b082c360SDean Michael Berris recordToString(CurrentRecord).data(), recordToString(To).data());
133b082c360SDean Michael Berris
134b082c360SDean Michael Berris CurrentRecord = To;
135b082c360SDean Michael Berris return Error::success();
136b082c360SDean Michael Berris } // namespace xray
137b082c360SDean Michael Berris
visit(BufferExtents &)138b082c360SDean Michael Berris Error BlockVerifier::visit(BufferExtents &) {
139b082c360SDean Michael Berris return transition(State::BufferExtents);
140b082c360SDean Michael Berris }
141b082c360SDean Michael Berris
visit(WallclockRecord &)142b082c360SDean Michael Berris Error BlockVerifier::visit(WallclockRecord &) {
143b082c360SDean Michael Berris return transition(State::WallClockTime);
144b082c360SDean Michael Berris }
145b082c360SDean Michael Berris
visit(NewCPUIDRecord &)146b082c360SDean Michael Berris Error BlockVerifier::visit(NewCPUIDRecord &) {
147b082c360SDean Michael Berris return transition(State::NewCPUId);
148b082c360SDean Michael Berris }
149b082c360SDean Michael Berris
visit(TSCWrapRecord &)150b082c360SDean Michael Berris Error BlockVerifier::visit(TSCWrapRecord &) {
151b082c360SDean Michael Berris return transition(State::TSCWrap);
152b082c360SDean Michael Berris }
153b082c360SDean Michael Berris
visit(CustomEventRecord &)154b082c360SDean Michael Berris Error BlockVerifier::visit(CustomEventRecord &) {
155b082c360SDean Michael Berris return transition(State::CustomEvent);
156b082c360SDean Michael Berris }
157b082c360SDean Michael Berris
visit(CustomEventRecordV5 &)15859439dd0SDean Michael Berris Error BlockVerifier::visit(CustomEventRecordV5 &) {
15959439dd0SDean Michael Berris return transition(State::CustomEvent);
16059439dd0SDean Michael Berris }
16159439dd0SDean Michael Berris
visit(TypedEventRecord &)16259439dd0SDean Michael Berris Error BlockVerifier::visit(TypedEventRecord &) {
16359439dd0SDean Michael Berris return transition(State::TypedEvent);
16459439dd0SDean Michael Berris }
16559439dd0SDean Michael Berris
visit(CallArgRecord &)166b082c360SDean Michael Berris Error BlockVerifier::visit(CallArgRecord &) {
167b082c360SDean Michael Berris return transition(State::CallArg);
168b082c360SDean Michael Berris }
169b082c360SDean Michael Berris
visit(PIDRecord &)170b082c360SDean Michael Berris Error BlockVerifier::visit(PIDRecord &) { return transition(State::PIDEntry); }
171b082c360SDean Michael Berris
visit(NewBufferRecord &)172b082c360SDean Michael Berris Error BlockVerifier::visit(NewBufferRecord &) {
173b082c360SDean Michael Berris return transition(State::NewBuffer);
174b082c360SDean Michael Berris }
175b082c360SDean Michael Berris
visit(EndBufferRecord &)176b082c360SDean Michael Berris Error BlockVerifier::visit(EndBufferRecord &) {
177b082c360SDean Michael Berris return transition(State::EndOfBuffer);
178b082c360SDean Michael Berris }
179b082c360SDean Michael Berris
visit(FunctionRecord &)180b082c360SDean Michael Berris Error BlockVerifier::visit(FunctionRecord &) {
181b082c360SDean Michael Berris return transition(State::Function);
182b082c360SDean Michael Berris }
183b082c360SDean Michael Berris
verify()184b082c360SDean Michael Berris Error BlockVerifier::verify() {
185b082c360SDean Michael Berris // The known terminal conditions are the following:
186b082c360SDean Michael Berris switch (CurrentRecord) {
187b082c360SDean Michael Berris case State::EndOfBuffer:
188b082c360SDean Michael Berris case State::NewCPUId:
189b082c360SDean Michael Berris case State::CustomEvent:
19059439dd0SDean Michael Berris case State::TypedEvent:
191b082c360SDean Michael Berris case State::Function:
192b082c360SDean Michael Berris case State::CallArg:
193b082c360SDean Michael Berris case State::TSCWrap:
194b082c360SDean Michael Berris return Error::success();
195b082c360SDean Michael Berris default:
196b082c360SDean Michael Berris return createStringError(
197b082c360SDean Michael Berris std::make_error_code(std::errc::executable_format_error),
198b082c360SDean Michael Berris "BlockVerifier: Invalid terminal condition %s, malformed block.",
199b082c360SDean Michael Berris recordToString(CurrentRecord).data());
200b082c360SDean Michael Berris }
201b082c360SDean Michael Berris }
202b082c360SDean Michael Berris
reset()203b082c360SDean Michael Berris void BlockVerifier::reset() { CurrentRecord = State::Unknown; }
204b082c360SDean Michael Berris
205b082c360SDean Michael Berris } // namespace xray
206b082c360SDean Michael Berris } // namespace llvm
207