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