1 //===- FaultMaps.h - The "FaultMaps" section --------------------*- C++ -*-===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_CODEGEN_FAULTMAPS_H 10 #define LLVM_CODEGEN_FAULTMAPS_H 11 12 #include "llvm/MC/MCSymbol.h" 13 #include "llvm/Support/Endian.h" 14 #include <cassert> 15 #include <cstddef> 16 #include <cstdint> 17 #include <map> 18 #include <vector> 19 20 namespace llvm { 21 22 class AsmPrinter; 23 class MCExpr; 24 class raw_ostream; 25 26 class FaultMaps { 27 public: 28 enum FaultKind { 29 FaultingLoad = 1, 30 FaultingLoadStore, 31 FaultingStore, 32 FaultKindMax 33 }; 34 35 explicit FaultMaps(AsmPrinter &AP); 36 37 static const char *faultTypeToString(FaultKind); 38 39 void recordFaultingOp(FaultKind FaultTy, const MCSymbol *FaultingLabel, 40 const MCSymbol *HandlerLabel); 41 void serializeToFaultMapSection(); reset()42 void reset() { 43 FunctionInfos.clear(); 44 } 45 46 private: 47 static const char *WFMP; 48 49 struct FaultInfo { 50 FaultKind Kind = FaultKindMax; 51 const MCExpr *FaultingOffsetExpr = nullptr; 52 const MCExpr *HandlerOffsetExpr = nullptr; 53 54 FaultInfo() = default; 55 FaultInfoFaultInfo56 explicit FaultInfo(FaultMaps::FaultKind Kind, const MCExpr *FaultingOffset, 57 const MCExpr *HandlerOffset) 58 : Kind(Kind), FaultingOffsetExpr(FaultingOffset), 59 HandlerOffsetExpr(HandlerOffset) {} 60 }; 61 62 using FunctionFaultInfos = std::vector<FaultInfo>; 63 64 // We'd like to keep a stable iteration order for FunctionInfos to help 65 // FileCheck based testing. 66 struct MCSymbolComparator { operatorMCSymbolComparator67 bool operator()(const MCSymbol *LHS, const MCSymbol *RHS) const { 68 return LHS->getName() < RHS->getName(); 69 } 70 }; 71 72 std::map<const MCSymbol *, FunctionFaultInfos, MCSymbolComparator> 73 FunctionInfos; 74 AsmPrinter &AP; 75 76 void emitFunctionInfo(const MCSymbol *FnLabel, const FunctionFaultInfos &FFI); 77 }; 78 79 /// A parser for the __llvm_faultmaps section generated by the FaultMaps class 80 /// above. This parser is version locked with with the __llvm_faultmaps section 81 /// generated by the version of LLVM that includes it. No guarantees are made 82 /// with respect to forward or backward compatibility. 83 class FaultMapParser { 84 using FaultMapVersionType = uint8_t; 85 using Reserved0Type = uint8_t; 86 using Reserved1Type = uint16_t; 87 using NumFunctionsType = uint32_t; 88 89 static const size_t FaultMapVersionOffset = 0; 90 static const size_t Reserved0Offset = 91 FaultMapVersionOffset + sizeof(FaultMapVersionType); 92 static const size_t Reserved1Offset = Reserved0Offset + sizeof(Reserved0Type); 93 static const size_t NumFunctionsOffset = 94 Reserved1Offset + sizeof(Reserved1Type); 95 static const size_t FunctionInfosOffset = 96 NumFunctionsOffset + sizeof(NumFunctionsType); 97 98 const uint8_t *P; 99 const uint8_t *E; 100 read(const uint8_t * P,const uint8_t * E)101 template <typename T> static T read(const uint8_t *P, const uint8_t *E) { 102 assert(P + sizeof(T) <= E && "out of bounds read!"); 103 return support::endian::read<T, support::little, 1>(P); 104 } 105 106 public: 107 class FunctionFaultInfoAccessor { 108 using FaultKindType = uint32_t; 109 using FaultingPCOffsetType = uint32_t; 110 using HandlerPCOffsetType = uint32_t; 111 112 static const size_t FaultKindOffset = 0; 113 static const size_t FaultingPCOffsetOffset = 114 FaultKindOffset + sizeof(FaultKindType); 115 static const size_t HandlerPCOffsetOffset = 116 FaultingPCOffsetOffset + sizeof(FaultingPCOffsetType); 117 118 const uint8_t *P; 119 const uint8_t *E; 120 121 public: 122 static const size_t Size = 123 HandlerPCOffsetOffset + sizeof(HandlerPCOffsetType); 124 FunctionFaultInfoAccessor(const uint8_t * P,const uint8_t * E)125 explicit FunctionFaultInfoAccessor(const uint8_t *P, const uint8_t *E) 126 : P(P), E(E) {} 127 getFaultKind()128 FaultKindType getFaultKind() const { 129 return read<FaultKindType>(P + FaultKindOffset, E); 130 } 131 getFaultingPCOffset()132 FaultingPCOffsetType getFaultingPCOffset() const { 133 return read<FaultingPCOffsetType>(P + FaultingPCOffsetOffset, E); 134 } 135 getHandlerPCOffset()136 HandlerPCOffsetType getHandlerPCOffset() const { 137 return read<HandlerPCOffsetType>(P + HandlerPCOffsetOffset, E); 138 } 139 }; 140 141 class FunctionInfoAccessor { 142 using FunctionAddrType = uint64_t; 143 using NumFaultingPCsType = uint32_t; 144 using ReservedType = uint32_t; 145 146 static const size_t FunctionAddrOffset = 0; 147 static const size_t NumFaultingPCsOffset = 148 FunctionAddrOffset + sizeof(FunctionAddrType); 149 static const size_t ReservedOffset = 150 NumFaultingPCsOffset + sizeof(NumFaultingPCsType); 151 static const size_t FunctionFaultInfosOffset = 152 ReservedOffset + sizeof(ReservedType); 153 static const size_t FunctionInfoHeaderSize = FunctionFaultInfosOffset; 154 155 const uint8_t *P = nullptr; 156 const uint8_t *E = nullptr; 157 158 public: 159 FunctionInfoAccessor() = default; 160 FunctionInfoAccessor(const uint8_t * P,const uint8_t * E)161 explicit FunctionInfoAccessor(const uint8_t *P, const uint8_t *E) 162 : P(P), E(E) {} 163 getFunctionAddr()164 FunctionAddrType getFunctionAddr() const { 165 return read<FunctionAddrType>(P + FunctionAddrOffset, E); 166 } 167 getNumFaultingPCs()168 NumFaultingPCsType getNumFaultingPCs() const { 169 return read<NumFaultingPCsType>(P + NumFaultingPCsOffset, E); 170 } 171 getFunctionFaultInfoAt(uint32_t Index)172 FunctionFaultInfoAccessor getFunctionFaultInfoAt(uint32_t Index) const { 173 assert(Index < getNumFaultingPCs() && "index out of bounds!"); 174 const uint8_t *Begin = P + FunctionFaultInfosOffset + 175 FunctionFaultInfoAccessor::Size * Index; 176 return FunctionFaultInfoAccessor(Begin, E); 177 } 178 getNextFunctionInfo()179 FunctionInfoAccessor getNextFunctionInfo() const { 180 size_t MySize = FunctionInfoHeaderSize + 181 getNumFaultingPCs() * FunctionFaultInfoAccessor::Size; 182 183 const uint8_t *Begin = P + MySize; 184 assert(Begin < E && "out of bounds!"); 185 return FunctionInfoAccessor(Begin, E); 186 } 187 }; 188 FaultMapParser(const uint8_t * Begin,const uint8_t * End)189 explicit FaultMapParser(const uint8_t *Begin, const uint8_t *End) 190 : P(Begin), E(End) {} 191 getFaultMapVersion()192 FaultMapVersionType getFaultMapVersion() const { 193 auto Version = read<FaultMapVersionType>(P + FaultMapVersionOffset, E); 194 assert(Version == 1 && "only version 1 supported!"); 195 return Version; 196 } 197 getNumFunctions()198 NumFunctionsType getNumFunctions() const { 199 return read<NumFunctionsType>(P + NumFunctionsOffset, E); 200 } 201 getFirstFunctionInfo()202 FunctionInfoAccessor getFirstFunctionInfo() const { 203 const uint8_t *Begin = P + FunctionInfosOffset; 204 return FunctionInfoAccessor(Begin, E); 205 } 206 }; 207 208 raw_ostream & 209 operator<<(raw_ostream &OS, const FaultMapParser::FunctionFaultInfoAccessor &); 210 211 raw_ostream &operator<<(raw_ostream &OS, 212 const FaultMapParser::FunctionInfoAccessor &); 213 214 raw_ostream &operator<<(raw_ostream &OS, const FaultMapParser &); 215 216 } // end namespace llvm 217 218 #endif // LLVM_CODEGEN_FAULTMAPS_H 219