blob: 3bd1190006dd94cd914a3064342ac9deeb7ea561 [file] [log] [blame]
Dean Michael Berrisb082c362018-09-10 02:35:25 +00001//===- BlockVerifier.cpp - FDR Block Verifier -----------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include "llvm/XRay/BlockVerifier.h"
10#include "llvm/Support/Error.h"
11
12namespace llvm {
13namespace xray {
14namespace {
15
16constexpr unsigned long long mask(BlockVerifier::State S) {
17 return 1uLL << static_cast<std::size_t>(S);
18}
19
20constexpr std::size_t number(BlockVerifier::State S) {
21 return static_cast<std::size_t>(S);
22}
23
24StringRef recordToString(BlockVerifier::State R) {
25 switch (R) {
26 case BlockVerifier::State::BufferExtents:
27 return "BufferExtents";
28 case BlockVerifier::State::NewBuffer:
29 return "NewBuffer";
30 case BlockVerifier::State::WallClockTime:
31 return "WallClockTime";
32 case BlockVerifier::State::PIDEntry:
33 return "PIDEntry";
34 case BlockVerifier::State::NewCPUId:
35 return "NewCPUId";
36 case BlockVerifier::State::TSCWrap:
37 return "TSCWrap";
38 case BlockVerifier::State::CustomEvent:
39 return "CustomEvent";
40 case BlockVerifier::State::Function:
41 return "Function";
42 case BlockVerifier::State::CallArg:
43 return "CallArg";
44 case BlockVerifier::State::EndOfBuffer:
45 return "EndOfBuffer";
46 case BlockVerifier::State::StateMax:
47 case BlockVerifier::State::Unknown:
48 return "Unknown";
49 }
50 llvm_unreachable("Unkown state!");
51}
52
53struct Transition {
54 BlockVerifier::State From;
55 std::bitset<number(BlockVerifier::State::StateMax)> ToStates;
56};
57
58} // namespace
59
60Error 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)}},
65
66 {State::BufferExtents, {mask(State::NewBuffer)}},
67
68 {State::NewBuffer, {mask(State::WallClockTime)}},
69
70 {State::WallClockTime,
71 {mask(State::PIDEntry) | mask(State::NewCPUId)}},
72
73 {State::PIDEntry, {mask(State::NewCPUId)}},
74
75 {State::NewCPUId,
76 {mask(State::NewCPUId) | mask(State::TSCWrap) |
77 mask(State::CustomEvent) | mask(State::Function) |
78 mask(State::EndOfBuffer)}},
79
80 {State::TSCWrap,
81 {mask(State::TSCWrap) | mask(State::NewCPUId) |
82 mask(State::CustomEvent) | mask(State::Function) |
83 mask(State::EndOfBuffer)}},
84
85 {State::CustomEvent,
86 {mask(State::CustomEvent) | mask(State::TSCWrap) |
87 mask(State::NewCPUId) | mask(State::Function) |
88 mask(State::EndOfBuffer)}},
89
90 {State::Function,
91 {mask(State::Function) | mask(State::TSCWrap) |
92 mask(State::NewCPUId) | mask(State::CustomEvent) |
93 mask(State::CallArg) | mask(State::EndOfBuffer)}},
94
95 {State::CallArg,
96 {mask(State::CallArg) | mask(State::Function) |
97 mask(State::TSCWrap) | mask(State::NewCPUId) |
98 mask(State::CustomEvent) | mask(State::EndOfBuffer)}},
99
100 {State::EndOfBuffer, {}}}};
101
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());
108
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();
113
114 auto &Mapping = TransitionTable[number(CurrentRecord)];
115 auto &From = Mapping.From;
116 auto &Destinations = Mapping.ToStates;
117 assert(From == CurrentRecord && "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());
123
124 CurrentRecord = To;
125 return Error::success();
126} // namespace xray
127
128Error BlockVerifier::visit(BufferExtents &) {
129 return transition(State::BufferExtents);
130}
131
132Error BlockVerifier::visit(WallclockRecord &) {
133 return transition(State::WallClockTime);
134}
135
136Error BlockVerifier::visit(NewCPUIDRecord &) {
137 return transition(State::NewCPUId);
138}
139
140Error BlockVerifier::visit(TSCWrapRecord &) {
141 return transition(State::TSCWrap);
142}
143
144Error BlockVerifier::visit(CustomEventRecord &) {
145 return transition(State::CustomEvent);
146}
147
148Error BlockVerifier::visit(CallArgRecord &) {
149 return transition(State::CallArg);
150}
151
152Error BlockVerifier::visit(PIDRecord &) { return transition(State::PIDEntry); }
153
154Error BlockVerifier::visit(NewBufferRecord &) {
155 return transition(State::NewBuffer);
156}
157
158Error BlockVerifier::visit(EndBufferRecord &) {
159 return transition(State::EndOfBuffer);
160}
161
162Error BlockVerifier::visit(FunctionRecord &) {
163 return transition(State::Function);
164}
165
166Error 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:
173 case State::CallArg:
174 case State::TSCWrap:
175 return Error::success();
176 default:
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());
181 }
182}
183
184void BlockVerifier::reset() { CurrentRecord = State::Unknown; }
185
186} // namespace xray
187} // namespace llvm