10b57cec5SDimitry Andric //===- BlockVerifier.cpp - FDR Block Verifier -----------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric #include "llvm/XRay/BlockVerifier.h"
90b57cec5SDimitry Andric #include "llvm/Support/Error.h"
100b57cec5SDimitry Andric
11*5f757f3fSDimitry Andric #include <bitset>
12*5f757f3fSDimitry Andric
130b57cec5SDimitry Andric namespace llvm {
140b57cec5SDimitry Andric namespace xray {
150b57cec5SDimitry Andric namespace {
160b57cec5SDimitry Andric
mask(BlockVerifier::State S)170b57cec5SDimitry Andric constexpr unsigned long long mask(BlockVerifier::State S) {
180b57cec5SDimitry Andric return 1uLL << static_cast<std::size_t>(S);
190b57cec5SDimitry Andric }
200b57cec5SDimitry Andric
number(BlockVerifier::State S)210b57cec5SDimitry Andric constexpr std::size_t number(BlockVerifier::State S) {
220b57cec5SDimitry Andric return static_cast<std::size_t>(S);
230b57cec5SDimitry Andric }
240b57cec5SDimitry Andric
recordToString(BlockVerifier::State R)250b57cec5SDimitry Andric StringRef recordToString(BlockVerifier::State R) {
260b57cec5SDimitry Andric switch (R) {
270b57cec5SDimitry Andric case BlockVerifier::State::BufferExtents:
280b57cec5SDimitry Andric return "BufferExtents";
290b57cec5SDimitry Andric case BlockVerifier::State::NewBuffer:
300b57cec5SDimitry Andric return "NewBuffer";
310b57cec5SDimitry Andric case BlockVerifier::State::WallClockTime:
320b57cec5SDimitry Andric return "WallClockTime";
330b57cec5SDimitry Andric case BlockVerifier::State::PIDEntry:
340b57cec5SDimitry Andric return "PIDEntry";
350b57cec5SDimitry Andric case BlockVerifier::State::NewCPUId:
360b57cec5SDimitry Andric return "NewCPUId";
370b57cec5SDimitry Andric case BlockVerifier::State::TSCWrap:
380b57cec5SDimitry Andric return "TSCWrap";
390b57cec5SDimitry Andric case BlockVerifier::State::CustomEvent:
400b57cec5SDimitry Andric return "CustomEvent";
410b57cec5SDimitry Andric case BlockVerifier::State::Function:
420b57cec5SDimitry Andric return "Function";
430b57cec5SDimitry Andric case BlockVerifier::State::CallArg:
440b57cec5SDimitry Andric return "CallArg";
450b57cec5SDimitry Andric case BlockVerifier::State::EndOfBuffer:
460b57cec5SDimitry Andric return "EndOfBuffer";
470b57cec5SDimitry Andric case BlockVerifier::State::TypedEvent:
480b57cec5SDimitry Andric return "TypedEvent";
490b57cec5SDimitry Andric case BlockVerifier::State::StateMax:
500b57cec5SDimitry Andric case BlockVerifier::State::Unknown:
510b57cec5SDimitry Andric return "Unknown";
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric llvm_unreachable("Unkown state!");
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric struct Transition {
570b57cec5SDimitry Andric BlockVerifier::State From;
580b57cec5SDimitry Andric std::bitset<number(BlockVerifier::State::StateMax)> ToStates;
590b57cec5SDimitry Andric };
600b57cec5SDimitry Andric
610b57cec5SDimitry Andric } // namespace
620b57cec5SDimitry Andric
transition(State To)630b57cec5SDimitry Andric Error BlockVerifier::transition(State To) {
640b57cec5SDimitry Andric using ToSet = std::bitset<number(State::StateMax)>;
650b57cec5SDimitry Andric static constexpr std::array<const Transition, number(State::StateMax)>
660b57cec5SDimitry Andric TransitionTable{{{State::Unknown,
670b57cec5SDimitry Andric {mask(State::BufferExtents) | mask(State::NewBuffer)}},
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric {State::BufferExtents, {mask(State::NewBuffer)}},
700b57cec5SDimitry Andric
710b57cec5SDimitry Andric {State::NewBuffer, {mask(State::WallClockTime)}},
720b57cec5SDimitry Andric
730b57cec5SDimitry Andric {State::WallClockTime,
740b57cec5SDimitry Andric {mask(State::PIDEntry) | mask(State::NewCPUId)}},
750b57cec5SDimitry Andric
760b57cec5SDimitry Andric {State::PIDEntry, {mask(State::NewCPUId)}},
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric {State::NewCPUId,
790b57cec5SDimitry Andric {mask(State::NewCPUId) | mask(State::TSCWrap) |
800b57cec5SDimitry Andric mask(State::CustomEvent) | mask(State::Function) |
810b57cec5SDimitry Andric mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
820b57cec5SDimitry Andric
830b57cec5SDimitry Andric {State::TSCWrap,
840b57cec5SDimitry Andric {mask(State::TSCWrap) | mask(State::NewCPUId) |
850b57cec5SDimitry Andric mask(State::CustomEvent) | mask(State::Function) |
860b57cec5SDimitry Andric mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric {State::CustomEvent,
890b57cec5SDimitry Andric {mask(State::CustomEvent) | mask(State::TSCWrap) |
900b57cec5SDimitry Andric mask(State::NewCPUId) | mask(State::Function) |
910b57cec5SDimitry Andric mask(State::EndOfBuffer) | mask(State::TypedEvent)}},
920b57cec5SDimitry Andric
930b57cec5SDimitry Andric {State::TypedEvent,
940b57cec5SDimitry Andric {mask(State::TypedEvent) | mask(State::TSCWrap) |
950b57cec5SDimitry Andric mask(State::NewCPUId) | mask(State::Function) |
960b57cec5SDimitry Andric mask(State::EndOfBuffer) | mask(State::CustomEvent)}},
970b57cec5SDimitry Andric
980b57cec5SDimitry Andric {State::Function,
990b57cec5SDimitry Andric {mask(State::Function) | mask(State::TSCWrap) |
1000b57cec5SDimitry Andric mask(State::NewCPUId) | mask(State::CustomEvent) |
1010b57cec5SDimitry Andric mask(State::CallArg) | mask(State::EndOfBuffer) |
1020b57cec5SDimitry Andric mask(State::TypedEvent)}},
1030b57cec5SDimitry Andric
1040b57cec5SDimitry Andric {State::CallArg,
1050b57cec5SDimitry Andric {mask(State::CallArg) | mask(State::Function) |
1060b57cec5SDimitry Andric mask(State::TSCWrap) | mask(State::NewCPUId) |
1070b57cec5SDimitry Andric mask(State::CustomEvent) | mask(State::EndOfBuffer) |
1080b57cec5SDimitry Andric mask(State::TypedEvent)}},
1090b57cec5SDimitry Andric
1100b57cec5SDimitry Andric {State::EndOfBuffer, {}}}};
1110b57cec5SDimitry Andric
1120b57cec5SDimitry Andric if (CurrentRecord >= State::StateMax)
1130b57cec5SDimitry Andric return createStringError(
1140b57cec5SDimitry Andric std::make_error_code(std::errc::executable_format_error),
1150b57cec5SDimitry Andric "BUG (BlockVerifier): Cannot find transition table entry for %s, "
1160b57cec5SDimitry Andric "transitioning to %s.",
1170b57cec5SDimitry Andric recordToString(CurrentRecord).data(), recordToString(To).data());
1180b57cec5SDimitry Andric
1190b57cec5SDimitry Andric // If we're at an EndOfBuffer record, we ignore anything that follows that
1200b57cec5SDimitry Andric // isn't a NewBuffer record.
1210b57cec5SDimitry Andric if (CurrentRecord == State::EndOfBuffer && To != State::NewBuffer)
1220b57cec5SDimitry Andric return Error::success();
1230b57cec5SDimitry Andric
1240b57cec5SDimitry Andric auto &Mapping = TransitionTable[number(CurrentRecord)];
1250b57cec5SDimitry Andric auto &Destinations = Mapping.ToStates;
1260b57cec5SDimitry Andric assert(Mapping.From == CurrentRecord &&
1270b57cec5SDimitry Andric "BUG: Wrong index for record mapping.");
1280b57cec5SDimitry Andric if ((Destinations & ToSet(mask(To))) == 0)
1290b57cec5SDimitry Andric return createStringError(
1300b57cec5SDimitry Andric std::make_error_code(std::errc::executable_format_error),
1310b57cec5SDimitry Andric "BlockVerifier: Invalid transition from %s to %s.",
1320b57cec5SDimitry Andric recordToString(CurrentRecord).data(), recordToString(To).data());
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric CurrentRecord = To;
1350b57cec5SDimitry Andric return Error::success();
1360b57cec5SDimitry Andric } // namespace xray
1370b57cec5SDimitry Andric
visit(BufferExtents &)1380b57cec5SDimitry Andric Error BlockVerifier::visit(BufferExtents &) {
1390b57cec5SDimitry Andric return transition(State::BufferExtents);
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric
visit(WallclockRecord &)1420b57cec5SDimitry Andric Error BlockVerifier::visit(WallclockRecord &) {
1430b57cec5SDimitry Andric return transition(State::WallClockTime);
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric
visit(NewCPUIDRecord &)1460b57cec5SDimitry Andric Error BlockVerifier::visit(NewCPUIDRecord &) {
1470b57cec5SDimitry Andric return transition(State::NewCPUId);
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric
visit(TSCWrapRecord &)1500b57cec5SDimitry Andric Error BlockVerifier::visit(TSCWrapRecord &) {
1510b57cec5SDimitry Andric return transition(State::TSCWrap);
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric
visit(CustomEventRecord &)1540b57cec5SDimitry Andric Error BlockVerifier::visit(CustomEventRecord &) {
1550b57cec5SDimitry Andric return transition(State::CustomEvent);
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric
visit(CustomEventRecordV5 &)1580b57cec5SDimitry Andric Error BlockVerifier::visit(CustomEventRecordV5 &) {
1590b57cec5SDimitry Andric return transition(State::CustomEvent);
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric
visit(TypedEventRecord &)1620b57cec5SDimitry Andric Error BlockVerifier::visit(TypedEventRecord &) {
1630b57cec5SDimitry Andric return transition(State::TypedEvent);
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric
visit(CallArgRecord &)1660b57cec5SDimitry Andric Error BlockVerifier::visit(CallArgRecord &) {
1670b57cec5SDimitry Andric return transition(State::CallArg);
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric
visit(PIDRecord &)1700b57cec5SDimitry Andric Error BlockVerifier::visit(PIDRecord &) { return transition(State::PIDEntry); }
1710b57cec5SDimitry Andric
visit(NewBufferRecord &)1720b57cec5SDimitry Andric Error BlockVerifier::visit(NewBufferRecord &) {
1730b57cec5SDimitry Andric return transition(State::NewBuffer);
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric
visit(EndBufferRecord &)1760b57cec5SDimitry Andric Error BlockVerifier::visit(EndBufferRecord &) {
1770b57cec5SDimitry Andric return transition(State::EndOfBuffer);
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric
visit(FunctionRecord &)1800b57cec5SDimitry Andric Error BlockVerifier::visit(FunctionRecord &) {
1810b57cec5SDimitry Andric return transition(State::Function);
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric
verify()1840b57cec5SDimitry Andric Error BlockVerifier::verify() {
1850b57cec5SDimitry Andric // The known terminal conditions are the following:
1860b57cec5SDimitry Andric switch (CurrentRecord) {
1870b57cec5SDimitry Andric case State::EndOfBuffer:
1880b57cec5SDimitry Andric case State::NewCPUId:
1890b57cec5SDimitry Andric case State::CustomEvent:
1900b57cec5SDimitry Andric case State::TypedEvent:
1910b57cec5SDimitry Andric case State::Function:
1920b57cec5SDimitry Andric case State::CallArg:
1930b57cec5SDimitry Andric case State::TSCWrap:
1940b57cec5SDimitry Andric return Error::success();
1950b57cec5SDimitry Andric default:
1960b57cec5SDimitry Andric return createStringError(
1970b57cec5SDimitry Andric std::make_error_code(std::errc::executable_format_error),
1980b57cec5SDimitry Andric "BlockVerifier: Invalid terminal condition %s, malformed block.",
1990b57cec5SDimitry Andric recordToString(CurrentRecord).data());
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric
reset()2030b57cec5SDimitry Andric void BlockVerifier::reset() { CurrentRecord = State::Unknown; }
2040b57cec5SDimitry Andric
2050b57cec5SDimitry Andric } // namespace xray
2060b57cec5SDimitry Andric } // namespace llvm
207