BlockVerifier.cpp revision 344779
1//===- 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::TypedEvent: 47 return "TypedEvent"; 48 case BlockVerifier::State::StateMax: 49 case BlockVerifier::State::Unknown: 50 return "Unknown"; 51 } 52 llvm_unreachable("Unkown state!"); 53} 54 55struct Transition { 56 BlockVerifier::State From; 57 std::bitset<number(BlockVerifier::State::StateMax)> ToStates; 58}; 59 60} // namespace 61 62Error BlockVerifier::transition(State To) { 63 using ToSet = std::bitset<number(State::StateMax)>; 64 static constexpr std::array<const Transition, number(State::StateMax)> 65 TransitionTable{{{State::Unknown, 66 {mask(State::BufferExtents) | mask(State::NewBuffer)}}, 67 68 {State::BufferExtents, {mask(State::NewBuffer)}}, 69 70 {State::NewBuffer, {mask(State::WallClockTime)}}, 71 72 {State::WallClockTime, 73 {mask(State::PIDEntry) | mask(State::NewCPUId)}}, 74 75 {State::PIDEntry, {mask(State::NewCPUId)}}, 76 77 {State::NewCPUId, 78 {mask(State::NewCPUId) | mask(State::TSCWrap) | 79 mask(State::CustomEvent) | mask(State::Function) | 80 mask(State::EndOfBuffer) | mask(State::TypedEvent)}}, 81 82 {State::TSCWrap, 83 {mask(State::TSCWrap) | mask(State::NewCPUId) | 84 mask(State::CustomEvent) | mask(State::Function) | 85 mask(State::EndOfBuffer) | mask(State::TypedEvent)}}, 86 87 {State::CustomEvent, 88 {mask(State::CustomEvent) | mask(State::TSCWrap) | 89 mask(State::NewCPUId) | mask(State::Function) | 90 mask(State::EndOfBuffer) | mask(State::TypedEvent)}}, 91 92 {State::TypedEvent, 93 {mask(State::TypedEvent) | mask(State::TSCWrap) | 94 mask(State::NewCPUId) | mask(State::Function) | 95 mask(State::EndOfBuffer) | mask(State::CustomEvent)}}, 96 97 {State::Function, 98 {mask(State::Function) | mask(State::TSCWrap) | 99 mask(State::NewCPUId) | mask(State::CustomEvent) | 100 mask(State::CallArg) | mask(State::EndOfBuffer) | 101 mask(State::TypedEvent)}}, 102 103 {State::CallArg, 104 {mask(State::CallArg) | mask(State::Function) | 105 mask(State::TSCWrap) | mask(State::NewCPUId) | 106 mask(State::CustomEvent) | mask(State::EndOfBuffer) | 107 mask(State::TypedEvent)}}, 108 109 {State::EndOfBuffer, {}}}}; 110 111 if (CurrentRecord >= State::StateMax) 112 return createStringError( 113 std::make_error_code(std::errc::executable_format_error), 114 "BUG (BlockVerifier): Cannot find transition table entry for %s, " 115 "transitioning to %s.", 116 recordToString(CurrentRecord).data(), recordToString(To).data()); 117 118 // If we're at an EndOfBuffer record, we ignore anything that follows that 119 // isn't a NewBuffer record. 120 if (CurrentRecord == State::EndOfBuffer && To != State::NewBuffer) 121 return Error::success(); 122 123 auto &Mapping = TransitionTable[number(CurrentRecord)]; 124 auto &Destinations = Mapping.ToStates; 125 assert(Mapping.From == CurrentRecord && 126 "BUG: Wrong index for record mapping."); 127 if ((Destinations & ToSet(mask(To))) == 0) 128 return createStringError( 129 std::make_error_code(std::errc::executable_format_error), 130 "BlockVerifier: Invalid transition from %s to %s.", 131 recordToString(CurrentRecord).data(), recordToString(To).data()); 132 133 CurrentRecord = To; 134 return Error::success(); 135} // namespace xray 136 137Error BlockVerifier::visit(BufferExtents &) { 138 return transition(State::BufferExtents); 139} 140 141Error BlockVerifier::visit(WallclockRecord &) { 142 return transition(State::WallClockTime); 143} 144 145Error BlockVerifier::visit(NewCPUIDRecord &) { 146 return transition(State::NewCPUId); 147} 148 149Error BlockVerifier::visit(TSCWrapRecord &) { 150 return transition(State::TSCWrap); 151} 152 153Error BlockVerifier::visit(CustomEventRecord &) { 154 return transition(State::CustomEvent); 155} 156 157Error BlockVerifier::visit(CustomEventRecordV5 &) { 158 return transition(State::CustomEvent); 159} 160 161Error BlockVerifier::visit(TypedEventRecord &) { 162 return transition(State::TypedEvent); 163} 164 165Error BlockVerifier::visit(CallArgRecord &) { 166 return transition(State::CallArg); 167} 168 169Error BlockVerifier::visit(PIDRecord &) { return transition(State::PIDEntry); } 170 171Error BlockVerifier::visit(NewBufferRecord &) { 172 return transition(State::NewBuffer); 173} 174 175Error BlockVerifier::visit(EndBufferRecord &) { 176 return transition(State::EndOfBuffer); 177} 178 179Error BlockVerifier::visit(FunctionRecord &) { 180 return transition(State::Function); 181} 182 183Error BlockVerifier::verify() { 184 // The known terminal conditions are the following: 185 switch (CurrentRecord) { 186 case State::EndOfBuffer: 187 case State::NewCPUId: 188 case State::CustomEvent: 189 case State::TypedEvent: 190 case State::Function: 191 case State::CallArg: 192 case State::TSCWrap: 193 return Error::success(); 194 default: 195 return createStringError( 196 std::make_error_code(std::errc::executable_format_error), 197 "BlockVerifier: Invalid terminal condition %s, malformed block.", 198 recordToString(CurrentRecord).data()); 199 } 200} 201 202void BlockVerifier::reset() { CurrentRecord = State::Unknown; } 203 204} // namespace xray 205} // namespace llvm 206