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