brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.8 KiB · e39f6b6 Raw
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