BlockVerifier.cpp revision 353358
1//===- BlockVerifier.cpp - FDR Block Verifier -----------------------------===// 2// 3// 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 6// 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"; 45 case BlockVerifier::State::TypedEvent: 46 return "TypedEvent"; 47 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) | 79 mask(State::EndOfBuffer) | mask(State::TypedEvent)}}, 80 81 {State::TSCWrap, 82 {mask(State::TSCWrap) | mask(State::NewCPUId) | 83 mask(State::CustomEvent) | mask(State::Function) | 84 mask(State::EndOfBuffer) | mask(State::TypedEvent)}}, 85 86 {State::CustomEvent, 87 {mask(State::CustomEvent) | mask(State::TSCWrap) | 88 mask(State::NewCPUId) | mask(State::Function) | 89 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)}}, 95 96 {State::Function, 97 {mask(State::Function) | mask(State::TSCWrap) | 98 mask(State::NewCPUId) | mask(State::CustomEvent) | 99 mask(State::CallArg) | mask(State::EndOfBuffer) | 100 mask(State::TypedEvent)}}, 101 102 {State::CallArg, 103 {mask(State::CallArg) | mask(State::Function) | 104 mask(State::TSCWrap) | mask(State::NewCPUId) | 105 mask(State::CustomEvent) | mask(State::EndOfBuffer) | 106 mask(State::TypedEvent)}}, 107 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)]; 123 auto &Destinations = Mapping.ToStates; 124 assert(Mapping.From == CurrentRecord && 125 "BUG: Wrong index for record mapping."); 126 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 156Error BlockVerifier::visit(CustomEventRecordV5 &) { 157 return transition(State::CustomEvent); 158} 159 160Error BlockVerifier::visit(TypedEventRecord &) { 161 return transition(State::TypedEvent); 162} 163 164Error 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: 188 case State::TypedEvent: 189 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 205