1 //===- BlockVerifier.cpp - FDR Block Verifier -----------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 #include "llvm/XRay/BlockVerifier.h" 10 #include "llvm/Support/Error.h" 11 12 namespace llvm { 13 namespace xray { 14 namespace { 15 16 constexpr unsigned long long mask(BlockVerifier::State S) { 17 return 1uLL << static_cast<std::size_t>(S); 18 } 19 20 constexpr std::size_t number(BlockVerifier::State S) { 21 return static_cast<std::size_t>(S); 22 } 23 24 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::StateMax: 47 case BlockVerifier::State::Unknown: 48 return "Unknown"; 49 } 50 } 51 52 } // namespace 53 54 Error BlockVerifier::transition(State To) { 55 using ToSet = std::bitset<number(State::StateMax)>; 56 static constexpr std::array<const std::tuple<State, ToSet>, 57 number(State::StateMax)> 58 TransitionTable{{{State::Unknown, 59 {mask(State::BufferExtents) | mask(State::NewBuffer)}}, 60 61 {State::BufferExtents, {mask(State::NewBuffer)}}, 62 63 {State::NewBuffer, {mask(State::WallClockTime)}}, 64 65 {State::WallClockTime, 66 {mask(State::PIDEntry) | mask(State::NewCPUId)}}, 67 68 {State::PIDEntry, {mask(State::NewCPUId)}}, 69 70 {State::NewCPUId, 71 {mask(State::NewCPUId) | mask(State::TSCWrap) | 72 mask(State::CustomEvent) | mask(State::Function) | 73 mask(State::EndOfBuffer)}}, 74 75 {State::TSCWrap, 76 {mask(State::TSCWrap) | mask(State::NewCPUId) | 77 mask(State::CustomEvent) | mask(State::Function) | 78 mask(State::EndOfBuffer)}}, 79 80 {State::CustomEvent, 81 {mask(State::CustomEvent) | mask(State::TSCWrap) | 82 mask(State::NewCPUId) | mask(State::Function) | 83 mask(State::EndOfBuffer)}}, 84 85 {State::Function, 86 {mask(State::Function) | mask(State::TSCWrap) | 87 mask(State::NewCPUId) | mask(State::CustomEvent) | 88 mask(State::CallArg) | mask(State::EndOfBuffer)}}, 89 90 {State::CallArg, 91 {mask(State::CallArg) | mask(State::Function) | 92 mask(State::TSCWrap) | mask(State::NewCPUId) | 93 mask(State::CustomEvent) | mask(State::EndOfBuffer)}}, 94 95 {State::EndOfBuffer, {}}}}; 96 97 if (CurrentRecord >= State::StateMax) 98 return createStringError( 99 std::make_error_code(std::errc::executable_format_error), 100 "BUG (BlockVerifier): Cannot find transition table entry for %s, " 101 "transitioning to %s.", 102 recordToString(CurrentRecord).data(), recordToString(To).data()); 103 104 // If we're at an EndOfBuffer record, we ignore anything that follows that 105 // isn't a NewBuffer record. 106 if (CurrentRecord == State::EndOfBuffer && To != State::NewBuffer) 107 return Error::success(); 108 109 auto &Mapping = TransitionTable[number(CurrentRecord)]; 110 auto &From = std::get<0>(Mapping); 111 auto &Destinations = std::get<1>(Mapping); 112 assert(From == CurrentRecord && "BUG: Wrong index for record mapping."); 113 if ((Destinations & ToSet(mask(To))) == 0) 114 return createStringError( 115 std::make_error_code(std::errc::executable_format_error), 116 "BlockVerifier: Invalid transition from %s to %s.", 117 recordToString(CurrentRecord).data(), recordToString(To).data()); 118 119 CurrentRecord = To; 120 return Error::success(); 121 } // namespace xray 122 123 Error BlockVerifier::visit(BufferExtents &) { 124 return transition(State::BufferExtents); 125 } 126 127 Error BlockVerifier::visit(WallclockRecord &) { 128 return transition(State::WallClockTime); 129 } 130 131 Error BlockVerifier::visit(NewCPUIDRecord &) { 132 return transition(State::NewCPUId); 133 } 134 135 Error BlockVerifier::visit(TSCWrapRecord &) { 136 return transition(State::TSCWrap); 137 } 138 139 Error BlockVerifier::visit(CustomEventRecord &) { 140 return transition(State::CustomEvent); 141 } 142 143 Error BlockVerifier::visit(CallArgRecord &) { 144 return transition(State::CallArg); 145 } 146 147 Error BlockVerifier::visit(PIDRecord &) { return transition(State::PIDEntry); } 148 149 Error BlockVerifier::visit(NewBufferRecord &) { 150 return transition(State::NewBuffer); 151 } 152 153 Error BlockVerifier::visit(EndBufferRecord &) { 154 return transition(State::EndOfBuffer); 155 } 156 157 Error BlockVerifier::visit(FunctionRecord &) { 158 return transition(State::Function); 159 } 160 161 Error BlockVerifier::verify() { 162 // The known terminal conditions are the following: 163 switch (CurrentRecord) { 164 case State::EndOfBuffer: 165 case State::NewCPUId: 166 case State::CustomEvent: 167 case State::Function: 168 case State::CallArg: 169 case State::TSCWrap: 170 return Error::success(); 171 default: 172 return createStringError( 173 std::make_error_code(std::errc::executable_format_error), 174 "BlockVerifier: Invalid terminal condition %s, malformed block.", 175 recordToString(CurrentRecord).data()); 176 } 177 } 178 179 void BlockVerifier::reset() { CurrentRecord = State::Unknown; } 180 181 } // namespace xray 182 } // namespace llvm 183