1 //===- IFSHandler.cpp -----------------------------------------------------===// 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 #include "llvm/InterfaceStub/IFSHandler.h" 10 #include "llvm/ADT/StringRef.h" 11 #include "llvm/ADT/StringSwitch.h" 12 #include "llvm/ADT/Triple.h" 13 #include "llvm/BinaryFormat/ELF.h" 14 #include "llvm/InterfaceStub/IFSStub.h" 15 #include "llvm/Support/Error.h" 16 #include "llvm/Support/LineIterator.h" 17 #include "llvm/Support/YAMLTraits.h" 18 19 using namespace llvm; 20 using namespace llvm::ifs; 21 22 LLVM_YAML_IS_SEQUENCE_VECTOR(IFSSymbol) 23 24 namespace llvm { 25 namespace yaml { 26 27 /// YAML traits for ELFSymbolType. 28 template <> struct ScalarEnumerationTraits<IFSSymbolType> { 29 static void enumeration(IO &IO, IFSSymbolType &SymbolType) { 30 IO.enumCase(SymbolType, "NoType", IFSSymbolType::NoType); 31 IO.enumCase(SymbolType, "Func", IFSSymbolType::Func); 32 IO.enumCase(SymbolType, "Object", IFSSymbolType::Object); 33 IO.enumCase(SymbolType, "TLS", IFSSymbolType::TLS); 34 IO.enumCase(SymbolType, "Unknown", IFSSymbolType::Unknown); 35 // Treat other symbol types as noise, and map to Unknown. 36 if (!IO.outputting() && IO.matchEnumFallback()) 37 SymbolType = IFSSymbolType::Unknown; 38 } 39 }; 40 41 template <> struct ScalarTraits<IFSEndiannessType> { 42 static void output(const IFSEndiannessType &Value, void *, 43 llvm::raw_ostream &Out) { 44 switch (Value) { 45 case IFSEndiannessType::Big: 46 Out << "big"; 47 break; 48 case IFSEndiannessType::Little: 49 Out << "little"; 50 break; 51 default: 52 llvm_unreachable("Unsupported endianness"); 53 } 54 } 55 56 static StringRef input(StringRef Scalar, void *, IFSEndiannessType &Value) { 57 Value = StringSwitch<IFSEndiannessType>(Scalar) 58 .Case("big", IFSEndiannessType::Big) 59 .Case("little", IFSEndiannessType::Little) 60 .Default(IFSEndiannessType::Unknown); 61 if (Value == IFSEndiannessType::Unknown) { 62 return "Unsupported endianness"; 63 } 64 return StringRef(); 65 } 66 67 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 68 }; 69 70 template <> struct ScalarTraits<IFSBitWidthType> { 71 static void output(const IFSBitWidthType &Value, void *, 72 llvm::raw_ostream &Out) { 73 switch (Value) { 74 case IFSBitWidthType::IFS32: 75 Out << "32"; 76 break; 77 case IFSBitWidthType::IFS64: 78 Out << "64"; 79 break; 80 default: 81 llvm_unreachable("Unsupported bit width"); 82 } 83 } 84 85 static StringRef input(StringRef Scalar, void *, IFSBitWidthType &Value) { 86 Value = StringSwitch<IFSBitWidthType>(Scalar) 87 .Case("32", IFSBitWidthType::IFS32) 88 .Case("64", IFSBitWidthType::IFS64) 89 .Default(IFSBitWidthType::Unknown); 90 if (Value == IFSBitWidthType::Unknown) { 91 return "Unsupported bit width"; 92 } 93 return StringRef(); 94 } 95 96 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 97 }; 98 99 template <> struct MappingTraits<IFSTarget> { 100 static void mapping(IO &IO, IFSTarget &Target) { 101 IO.mapOptional("ObjectFormat", Target.ObjectFormat); 102 IO.mapOptional("Arch", Target.ArchString); 103 IO.mapOptional("Endianness", Target.Endianness); 104 IO.mapOptional("BitWidth", Target.BitWidth); 105 } 106 107 // Compacts symbol information into a single line. 108 static const bool flow = true; // NOLINT(readability-identifier-naming) 109 }; 110 111 /// YAML traits for ELFSymbol. 112 template <> struct MappingTraits<IFSSymbol> { 113 static void mapping(IO &IO, IFSSymbol &Symbol) { 114 IO.mapRequired("Name", Symbol.Name); 115 IO.mapRequired("Type", Symbol.Type); 116 // The need for symbol size depends on the symbol type. 117 if (Symbol.Type == IFSSymbolType::NoType) { 118 IO.mapOptional("Size", Symbol.Size, (uint64_t)0); 119 } else if (Symbol.Type == IFSSymbolType::Func) { 120 Symbol.Size = 0; 121 } else { 122 IO.mapRequired("Size", Symbol.Size); 123 } 124 IO.mapOptional("Undefined", Symbol.Undefined, false); 125 IO.mapOptional("Weak", Symbol.Weak, false); 126 IO.mapOptional("Warning", Symbol.Warning); 127 } 128 129 // Compacts symbol information into a single line. 130 static const bool flow = true; // NOLINT(readability-identifier-naming) 131 }; 132 133 /// YAML traits for ELFStub objects. 134 template <> struct MappingTraits<IFSStub> { 135 static void mapping(IO &IO, IFSStub &Stub) { 136 if (!IO.mapTag("!ifs-v1", true)) 137 IO.setError("Not a .tbe YAML file."); 138 IO.mapRequired("IfsVersion", Stub.IfsVersion); 139 IO.mapOptional("SoName", Stub.SoName); 140 IO.mapOptional("Target", Stub.Target); 141 IO.mapOptional("NeededLibs", Stub.NeededLibs); 142 IO.mapRequired("Symbols", Stub.Symbols); 143 } 144 }; 145 146 /// YAML traits for ELFStubTriple objects. 147 template <> struct MappingTraits<IFSStubTriple> { 148 static void mapping(IO &IO, IFSStubTriple &Stub) { 149 if (!IO.mapTag("!ifs-v1", true)) 150 IO.setError("Not a .tbe YAML file."); 151 IO.mapRequired("IfsVersion", Stub.IfsVersion); 152 IO.mapOptional("SoName", Stub.SoName); 153 IO.mapOptional("Target", Stub.Target.Triple); 154 IO.mapOptional("NeededLibs", Stub.NeededLibs); 155 IO.mapRequired("Symbols", Stub.Symbols); 156 } 157 }; 158 } // end namespace yaml 159 } // end namespace llvm 160 161 /// Attempt to determine if a Text stub uses target triple. 162 bool usesTriple(StringRef Buf) { 163 for (line_iterator I(MemoryBufferRef(Buf, "ELFStub")); !I.is_at_eof(); ++I) { 164 StringRef Line = (*I).trim(); 165 if (Line.startswith("Target:")) { 166 if (Line == "Target:" || (Line.find("{") != Line.npos)) { 167 return false; 168 } 169 } 170 } 171 return true; 172 } 173 174 Expected<std::unique_ptr<IFSStub>> ifs::readIFSFromBuffer(StringRef Buf) { 175 yaml::Input YamlIn(Buf); 176 std::unique_ptr<IFSStubTriple> Stub(new IFSStubTriple()); 177 if (usesTriple(Buf)) { 178 YamlIn >> *Stub; 179 } else { 180 YamlIn >> *static_cast<IFSStub *>(Stub.get()); 181 } 182 if (std::error_code Err = YamlIn.error()) { 183 return createStringError(Err, "YAML failed reading as IFS"); 184 } 185 186 if (Stub->IfsVersion > IFSVersionCurrent) 187 return make_error<StringError>( 188 "IFS version " + Stub->IfsVersion.getAsString() + " is unsupported.", 189 std::make_error_code(std::errc::invalid_argument)); 190 if (Stub->Target.ArchString) { 191 Stub->Target.Arch = 192 ELF::convertArchNameToEMachine(Stub->Target.ArchString.getValue()); 193 } 194 return std::move(Stub); 195 } 196 197 Error ifs::writeIFSToOutputStream(raw_ostream &OS, const IFSStub &Stub) { 198 yaml::Output YamlOut(OS, NULL, /*WrapColumn =*/0); 199 std::unique_ptr<IFSStubTriple> CopyStub(new IFSStubTriple(Stub)); 200 if (Stub.Target.Arch) { 201 CopyStub->Target.ArchString = std::string( 202 ELF::convertEMachineToArchName(Stub.Target.Arch.getValue())); 203 } 204 IFSTarget Target = Stub.Target; 205 206 if (CopyStub->Target.Triple || 207 (!CopyStub->Target.ArchString && !CopyStub->Target.Endianness && 208 !CopyStub->Target.BitWidth)) 209 YamlOut << *CopyStub; 210 else 211 YamlOut << *static_cast<IFSStub *>(CopyStub.get()); 212 return Error::success(); 213 } 214 215 Error ifs::overrideIFSTarget(IFSStub &Stub, Optional<IFSArch> OverrideArch, 216 Optional<IFSEndiannessType> OverrideEndianness, 217 Optional<IFSBitWidthType> OverrideBitWidth, 218 Optional<std::string> OverrideTriple) { 219 std::error_code OverrideEC(1, std::generic_category()); 220 if (OverrideArch) { 221 if (Stub.Target.Arch && 222 Stub.Target.Arch.getValue() != OverrideArch.getValue()) { 223 return make_error<StringError>( 224 "Supplied Arch conflicts with the text stub", OverrideEC); 225 } 226 Stub.Target.Arch = OverrideArch.getValue(); 227 } 228 if (OverrideEndianness) { 229 if (Stub.Target.Endianness && 230 Stub.Target.Endianness.getValue() != OverrideEndianness.getValue()) { 231 return make_error<StringError>( 232 "Supplied Endianness conflicts with the text stub", OverrideEC); 233 } 234 Stub.Target.Endianness = OverrideEndianness.getValue(); 235 } 236 if (OverrideBitWidth) { 237 if (Stub.Target.BitWidth && 238 Stub.Target.BitWidth.getValue() != OverrideBitWidth.getValue()) { 239 return make_error<StringError>( 240 "Supplied BitWidth conflicts with the text stub", OverrideEC); 241 } 242 Stub.Target.BitWidth = OverrideBitWidth.getValue(); 243 } 244 if (OverrideTriple) { 245 if (Stub.Target.Triple && 246 Stub.Target.Triple.getValue() != OverrideTriple.getValue()) { 247 return make_error<StringError>( 248 "Supplied Triple conflicts with the text stub", OverrideEC); 249 } 250 Stub.Target.Triple = OverrideTriple.getValue(); 251 } 252 return Error::success(); 253 } 254 255 Error ifs::validateIFSTarget(IFSStub &Stub, bool ParseTriple) { 256 std::error_code ValidationEC(1, std::generic_category()); 257 if (Stub.Target.Triple) { 258 if (Stub.Target.Arch || Stub.Target.BitWidth || Stub.Target.Endianness || 259 Stub.Target.ObjectFormat) { 260 return make_error<StringError>( 261 "Target triple cannot be used simultaneously with ELF target format", 262 ValidationEC); 263 } 264 if (ParseTriple) { 265 IFSTarget TargetFromTriple = parseTriple(Stub.Target.Triple.getValue()); 266 Stub.Target.Arch = TargetFromTriple.Arch; 267 Stub.Target.BitWidth = TargetFromTriple.BitWidth; 268 Stub.Target.Endianness = TargetFromTriple.Endianness; 269 } 270 return Error::success(); 271 } 272 if (!Stub.Target.Arch || !Stub.Target.BitWidth || !Stub.Target.Endianness) { 273 // TODO: unify the error message. 274 if (!Stub.Target.Arch) { 275 return make_error<StringError>("Arch is not defined in the text stub", 276 ValidationEC); 277 } 278 if (!Stub.Target.BitWidth) { 279 return make_error<StringError>("BitWidth is not defined in the text stub", 280 ValidationEC); 281 } 282 if (!Stub.Target.Endianness) { 283 return make_error<StringError>( 284 "Endianness is not defined in the text stub", ValidationEC); 285 } 286 } 287 return Error::success(); 288 } 289 290 IFSTarget ifs::parseTriple(StringRef TripleStr) { 291 Triple IFSTriple(TripleStr); 292 IFSTarget RetTarget; 293 // TODO: Implement a Triple Arch enum to e_machine map. 294 switch (IFSTriple.getArch()) { 295 case Triple::ArchType::aarch64: 296 RetTarget.Arch = (IFSArch)ELF::EM_AARCH64; 297 break; 298 case Triple::ArchType::x86_64: 299 RetTarget.Arch = (IFSArch)ELF::EM_X86_64; 300 break; 301 default: 302 RetTarget.Arch = (IFSArch)ELF::EM_NONE; 303 } 304 RetTarget.Endianness = IFSTriple.isLittleEndian() ? IFSEndiannessType::Little 305 : IFSEndiannessType::Big; 306 RetTarget.BitWidth = 307 IFSTriple.isArch64Bit() ? IFSBitWidthType::IFS64 : IFSBitWidthType::IFS32; 308 return RetTarget; 309 } 310 311 void ifs::stripIFSTarget(IFSStub &Stub, bool StripTriple, bool StripArch, 312 bool StripEndianness, bool StripBitWidth) { 313 if (StripTriple || StripArch) { 314 Stub.Target.Arch.reset(); 315 Stub.Target.ArchString.reset(); 316 } 317 if (StripTriple || StripEndianness) { 318 Stub.Target.Endianness.reset(); 319 } 320 if (StripTriple || StripBitWidth) { 321 Stub.Target.BitWidth.reset(); 322 } 323 if (StripTriple) { 324 Stub.Target.Triple.reset(); 325 } 326 if (!Stub.Target.Arch && !Stub.Target.BitWidth && !Stub.Target.Endianness) { 327 Stub.Target.ObjectFormat.reset(); 328 } 329 } 330