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