mirror of
https://github.com/RPCS3/llvm.git
synced 2025-05-28 16:26:18 +00:00

Summary: This patch implements a `BlockVerifier` type which enforces the invariants of the log structure of FDR mode logs on a per-block basis. This ensures that the data we encounter from an FDR mode log semantically correct (i.e. that records follow the documented "grammar" for FDR mode log records). This is another part of the refactoring of D50441. This is a slightly modified version of rL341628, avoiding the `std::tuple<...>` constructor that is not constexpr in C++11. Reviewers: mboerger, eizan Subscribers: mgorny, hiraditya, llvm-commits Differential Revision: https://reviews.llvm.org/D51723 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@341769 91177308-0d34-0410-b5e6-96231b3b80d8
188 lines
6.0 KiB
C++
188 lines
6.0 KiB
C++
//===- BlockVerifier.cpp - FDR Block Verifier -----------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "llvm/XRay/BlockVerifier.h"
|
|
#include "llvm/Support/Error.h"
|
|
|
|
namespace llvm {
|
|
namespace xray {
|
|
namespace {
|
|
|
|
constexpr unsigned long long mask(BlockVerifier::State S) {
|
|
return 1uLL << static_cast<std::size_t>(S);
|
|
}
|
|
|
|
constexpr std::size_t number(BlockVerifier::State S) {
|
|
return static_cast<std::size_t>(S);
|
|
}
|
|
|
|
StringRef recordToString(BlockVerifier::State R) {
|
|
switch (R) {
|
|
case BlockVerifier::State::BufferExtents:
|
|
return "BufferExtents";
|
|
case BlockVerifier::State::NewBuffer:
|
|
return "NewBuffer";
|
|
case BlockVerifier::State::WallClockTime:
|
|
return "WallClockTime";
|
|
case BlockVerifier::State::PIDEntry:
|
|
return "PIDEntry";
|
|
case BlockVerifier::State::NewCPUId:
|
|
return "NewCPUId";
|
|
case BlockVerifier::State::TSCWrap:
|
|
return "TSCWrap";
|
|
case BlockVerifier::State::CustomEvent:
|
|
return "CustomEvent";
|
|
case BlockVerifier::State::Function:
|
|
return "Function";
|
|
case BlockVerifier::State::CallArg:
|
|
return "CallArg";
|
|
case BlockVerifier::State::EndOfBuffer:
|
|
return "EndOfBuffer";
|
|
case BlockVerifier::State::StateMax:
|
|
case BlockVerifier::State::Unknown:
|
|
return "Unknown";
|
|
}
|
|
llvm_unreachable("Unkown state!");
|
|
}
|
|
|
|
struct Transition {
|
|
BlockVerifier::State From;
|
|
std::bitset<number(BlockVerifier::State::StateMax)> ToStates;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
Error BlockVerifier::transition(State To) {
|
|
using ToSet = std::bitset<number(State::StateMax)>;
|
|
static constexpr std::array<const Transition, number(State::StateMax)>
|
|
TransitionTable{{{State::Unknown,
|
|
{mask(State::BufferExtents) | mask(State::NewBuffer)}},
|
|
|
|
{State::BufferExtents, {mask(State::NewBuffer)}},
|
|
|
|
{State::NewBuffer, {mask(State::WallClockTime)}},
|
|
|
|
{State::WallClockTime,
|
|
{mask(State::PIDEntry) | mask(State::NewCPUId)}},
|
|
|
|
{State::PIDEntry, {mask(State::NewCPUId)}},
|
|
|
|
{State::NewCPUId,
|
|
{mask(State::NewCPUId) | mask(State::TSCWrap) |
|
|
mask(State::CustomEvent) | mask(State::Function) |
|
|
mask(State::EndOfBuffer)}},
|
|
|
|
{State::TSCWrap,
|
|
{mask(State::TSCWrap) | mask(State::NewCPUId) |
|
|
mask(State::CustomEvent) | mask(State::Function) |
|
|
mask(State::EndOfBuffer)}},
|
|
|
|
{State::CustomEvent,
|
|
{mask(State::CustomEvent) | mask(State::TSCWrap) |
|
|
mask(State::NewCPUId) | mask(State::Function) |
|
|
mask(State::EndOfBuffer)}},
|
|
|
|
{State::Function,
|
|
{mask(State::Function) | mask(State::TSCWrap) |
|
|
mask(State::NewCPUId) | mask(State::CustomEvent) |
|
|
mask(State::CallArg) | mask(State::EndOfBuffer)}},
|
|
|
|
{State::CallArg,
|
|
{mask(State::CallArg) | mask(State::Function) |
|
|
mask(State::TSCWrap) | mask(State::NewCPUId) |
|
|
mask(State::CustomEvent) | mask(State::EndOfBuffer)}},
|
|
|
|
{State::EndOfBuffer, {}}}};
|
|
|
|
if (CurrentRecord >= State::StateMax)
|
|
return createStringError(
|
|
std::make_error_code(std::errc::executable_format_error),
|
|
"BUG (BlockVerifier): Cannot find transition table entry for %s, "
|
|
"transitioning to %s.",
|
|
recordToString(CurrentRecord).data(), recordToString(To).data());
|
|
|
|
// If we're at an EndOfBuffer record, we ignore anything that follows that
|
|
// isn't a NewBuffer record.
|
|
if (CurrentRecord == State::EndOfBuffer && To != State::NewBuffer)
|
|
return Error::success();
|
|
|
|
auto &Mapping = TransitionTable[number(CurrentRecord)];
|
|
auto &From = Mapping.From;
|
|
auto &Destinations = Mapping.ToStates;
|
|
assert(From == CurrentRecord && "BUG: Wrong index for record mapping.");
|
|
if ((Destinations & ToSet(mask(To))) == 0)
|
|
return createStringError(
|
|
std::make_error_code(std::errc::executable_format_error),
|
|
"BlockVerifier: Invalid transition from %s to %s.",
|
|
recordToString(CurrentRecord).data(), recordToString(To).data());
|
|
|
|
CurrentRecord = To;
|
|
return Error::success();
|
|
} // namespace xray
|
|
|
|
Error BlockVerifier::visit(BufferExtents &) {
|
|
return transition(State::BufferExtents);
|
|
}
|
|
|
|
Error BlockVerifier::visit(WallclockRecord &) {
|
|
return transition(State::WallClockTime);
|
|
}
|
|
|
|
Error BlockVerifier::visit(NewCPUIDRecord &) {
|
|
return transition(State::NewCPUId);
|
|
}
|
|
|
|
Error BlockVerifier::visit(TSCWrapRecord &) {
|
|
return transition(State::TSCWrap);
|
|
}
|
|
|
|
Error BlockVerifier::visit(CustomEventRecord &) {
|
|
return transition(State::CustomEvent);
|
|
}
|
|
|
|
Error BlockVerifier::visit(CallArgRecord &) {
|
|
return transition(State::CallArg);
|
|
}
|
|
|
|
Error BlockVerifier::visit(PIDRecord &) { return transition(State::PIDEntry); }
|
|
|
|
Error BlockVerifier::visit(NewBufferRecord &) {
|
|
return transition(State::NewBuffer);
|
|
}
|
|
|
|
Error BlockVerifier::visit(EndBufferRecord &) {
|
|
return transition(State::EndOfBuffer);
|
|
}
|
|
|
|
Error BlockVerifier::visit(FunctionRecord &) {
|
|
return transition(State::Function);
|
|
}
|
|
|
|
Error BlockVerifier::verify() {
|
|
// The known terminal conditions are the following:
|
|
switch (CurrentRecord) {
|
|
case State::EndOfBuffer:
|
|
case State::NewCPUId:
|
|
case State::CustomEvent:
|
|
case State::Function:
|
|
case State::CallArg:
|
|
case State::TSCWrap:
|
|
return Error::success();
|
|
default:
|
|
return createStringError(
|
|
std::make_error_code(std::errc::executable_format_error),
|
|
"BlockVerifier: Invalid terminal condition %s, malformed block.",
|
|
recordToString(CurrentRecord).data());
|
|
}
|
|
}
|
|
|
|
void BlockVerifier::reset() { CurrentRecord = State::Unknown; }
|
|
|
|
} // namespace xray
|
|
} // namespace llvm
|