blob: 9fb49fa9a8609b7b698b488fc59d6b73eb184c02 [file] [log] [blame]
Dean Michael Berrisb082c362018-09-10 02:35:25 +00001//===- BlockVerifier.cpp - FDR Block Verifier -----------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Dean Michael Berrisb082c362018-09-10 02:35:25 +00006//
7//===----------------------------------------------------------------------===//
8#include "llvm/XRay/BlockVerifier.h"
9#include "llvm/Support/Error.h"
10
11namespace llvm {
12namespace xray {
13namespace {
14
15constexpr unsigned long long mask(BlockVerifier::State S) {
16 return 1uLL << static_cast<std::size_t>(S);
17}
18
19constexpr std::size_t number(BlockVerifier::State S) {
20 return static_cast<std::size_t>(S);
21}
22
23StringRef recordToString(BlockVerifier::State R) {
24 switch (R) {
25 case BlockVerifier::State::BufferExtents:
26 return "BufferExtents";
27 case BlockVerifier::State::NewBuffer:
28 return "NewBuffer";
29 case BlockVerifier::State::WallClockTime:
30 return "WallClockTime";
31 case BlockVerifier::State::PIDEntry:
32 return "PIDEntry";
33 case BlockVerifier::State::NewCPUId:
34 return "NewCPUId";
35 case BlockVerifier::State::TSCWrap:
36 return "TSCWrap";
37 case BlockVerifier::State::CustomEvent:
38 return "CustomEvent";
39 case BlockVerifier::State::Function:
40 return "Function";
41 case BlockVerifier::State::CallArg:
42 return "CallArg";
43 case BlockVerifier::State::EndOfBuffer:
44 return "EndOfBuffer";
Dean Michael Berris59439dd2018-11-07 04:37:42 +000045 case BlockVerifier::State::TypedEvent:
46 return "TypedEvent";
Dean Michael Berrisb082c362018-09-10 02:35:25 +000047 case BlockVerifier::State::StateMax:
48 case BlockVerifier::State::Unknown:
49 return "Unknown";
50 }
51 llvm_unreachable("Unkown state!");
52}
53
54struct Transition {
55 BlockVerifier::State From;
56 std::bitset<number(BlockVerifier::State::StateMax)> ToStates;
57};
58
59} // namespace
60
61Error 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)}},
66
67 {State::BufferExtents, {mask(State::NewBuffer)}},
68
69 {State::NewBuffer, {mask(State::WallClockTime)}},
70
71 {State::WallClockTime,
72 {mask(State::PIDEntry) | mask(State::NewCPUId)}},
73
74 {State::PIDEntry, {mask(State::NewCPUId)}},
75
76 {State::NewCPUId,
77 {mask(State::NewCPUId) | mask(State::TSCWrap) |
78 mask(State::CustomEvent) | mask(State::Function) |
Dean Michael Berris59439dd2018-11-07 04:37:42 +000079 mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
Dean Michael Berrisb082c362018-09-10 02:35:25 +000080
81 {State::TSCWrap,
82 {mask(State::TSCWrap) | mask(State::NewCPUId) |
83 mask(State::CustomEvent) | mask(State::Function) |
Dean Michael Berris59439dd2018-11-07 04:37:42 +000084 mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
Dean Michael Berrisb082c362018-09-10 02:35:25 +000085
86 {State::CustomEvent,
87 {mask(State::CustomEvent) | mask(State::TSCWrap) |
88 mask(State::NewCPUId) | mask(State::Function) |
Dean Michael Berris59439dd2018-11-07 04:37:42 +000089 mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
90
91 {State::TypedEvent,
92 {mask(State::TypedEvent) | mask(State::TSCWrap) |
93 mask(State::NewCPUId) | mask(State::Function) |
94 mask(State::EndOfBuffer) | mask(State::CustomEvent)}},
Dean Michael Berrisb082c362018-09-10 02:35:25 +000095
96 {State::Function,
97 {mask(State::Function) | mask(State::TSCWrap) |
98 mask(State::NewCPUId) | mask(State::CustomEvent) |
Dean Michael Berris59439dd2018-11-07 04:37:42 +000099 mask(State::CallArg) | mask(State::EndOfBuffer) |
100 mask(State::TypedEvent)}},
Dean Michael Berrisb082c362018-09-10 02:35:25 +0000101
102 {State::CallArg,
103 {mask(State::CallArg) | mask(State::Function) |
104 mask(State::TSCWrap) | mask(State::NewCPUId) |
Dean Michael Berris59439dd2018-11-07 04:37:42 +0000105 mask(State::CustomEvent) | mask(State::EndOfBuffer) |
106 mask(State::TypedEvent)}},
Dean Michael Berrisb082c362018-09-10 02:35:25 +0000107
108 {State::EndOfBuffer, {}}}};
109
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());
116
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();
121
122 auto &Mapping = TransitionTable[number(CurrentRecord)];
Dean Michael Berrisb082c362018-09-10 02:35:25 +0000123 auto &Destinations = Mapping.ToStates;
Dean Michael Berrisf3a36792018-09-10 02:57:05 +0000124 assert(Mapping.From == CurrentRecord &&
125 "BUG: Wrong index for record mapping.");
Dean Michael Berrisb082c362018-09-10 02:35:25 +0000126 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());
131
132 CurrentRecord = To;
133 return Error::success();
134} // namespace xray
135
136Error BlockVerifier::visit(BufferExtents &) {
137 return transition(State::BufferExtents);
138}
139
140Error BlockVerifier::visit(WallclockRecord &) {
141 return transition(State::WallClockTime);
142}
143
144Error BlockVerifier::visit(NewCPUIDRecord &) {
145 return transition(State::NewCPUId);
146}
147
148Error BlockVerifier::visit(TSCWrapRecord &) {
149 return transition(State::TSCWrap);
150}
151
152Error BlockVerifier::visit(CustomEventRecord &) {
153 return transition(State::CustomEvent);
154}
155
Dean Michael Berris59439dd2018-11-07 04:37:42 +0000156Error BlockVerifier::visit(CustomEventRecordV5 &) {
157 return transition(State::CustomEvent);
158}
159
160Error BlockVerifier::visit(TypedEventRecord &) {
161 return transition(State::TypedEvent);
162}
163
Dean Michael Berrisb082c362018-09-10 02:35:25 +0000164Error BlockVerifier::visit(CallArgRecord &) {
165 return transition(State::CallArg);
166}
167
168Error BlockVerifier::visit(PIDRecord &) { return transition(State::PIDEntry); }
169
170Error BlockVerifier::visit(NewBufferRecord &) {
171 return transition(State::NewBuffer);
172}
173
174Error BlockVerifier::visit(EndBufferRecord &) {
175 return transition(State::EndOfBuffer);
176}
177
178Error BlockVerifier::visit(FunctionRecord &) {
179 return transition(State::Function);
180}
181
182Error 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:
Dean Michael Berris59439dd2018-11-07 04:37:42 +0000188 case State::TypedEvent:
Dean Michael Berrisb082c362018-09-10 02:35:25 +0000189 case State::Function:
190 case State::CallArg:
191 case State::TSCWrap:
192 return Error::success();
193 default:
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());
198 }
199}
200
201void BlockVerifier::reset() { CurrentRecord = State::Unknown; }
202
203} // namespace xray
204} // namespace llvm