From db5e2f303baee08e8a4559e3e1820fd9bb427f47 Mon Sep 17 00:00:00 2001 From: Haowei Wu Date: Wed, 31 Mar 2021 16:48:56 -0700 Subject: [PATCH] [elfabi] Prepare elfabi/ifs merging. This change implements unified text stub format and command line interface proposed in the elfabi/ifs merge plan. Differential Revision: https://reviews.llvm.org/D99399 --- include/llvm/BinaryFormat/ELF.h | 8 + include/llvm/InterfaceStub/ELFObjHandler.h | 3 +- include/llvm/InterfaceStub/ELFStub.h | 49 +- include/llvm/InterfaceStub/TBEHandler.h | 19 +- lib/BinaryFormat/CMakeLists.txt | 1 + lib/BinaryFormat/ELF.cpp | 568 ++++++++++++++++++ lib/InterfaceStub/CMakeLists.txt | 1 + lib/InterfaceStub/ELFObjHandler.cpp | 38 +- lib/InterfaceStub/ELFStub.cpp | 29 +- lib/InterfaceStub/TBEHandler.cpp | 271 +++++++-- .../llvm-elfabi/binary-read-add-soname.test | 8 +- test/tools/llvm-elfabi/binary-read-arch.test | 106 +++- .../llvm-elfabi/binary-read-bad-soname.test | 2 +- .../llvm-elfabi/binary-read-bad-vaddr.test | 2 +- .../binary-read-neededlibs-bad-offset.test | 2 +- .../llvm-elfabi/binary-read-neededlibs.test | 4 +- .../llvm-elfabi/binary-read-no-dt-strsz.test | 2 +- .../llvm-elfabi/binary-read-no-dt-strtab.test | 2 +- .../llvm-elfabi/binary-read-no-dynamic.test | 2 +- .../binary-read-replace-soname.test | 4 +- .../binary-read-soname-no-null.test | 2 +- .../tools/llvm-elfabi/binary-read-soname.test | 8 +- .../binary-read-syms-gnu-hash.test | 26 +- .../binary-read-syms-sysv-hash.test | 26 +- test/tools/llvm-elfabi/fail-file-open.test | 2 +- .../llvm-elfabi/fail-file-write-windows.test | 8 +- test/tools/llvm-elfabi/fail-file-write.test | 8 +- .../llvm-elfabi/output-target-error.test | 14 +- .../llvm-elfabi/preserve-dates-stub.test | 14 +- .../tools/llvm-elfabi/preserve-dates-tbe.test | 4 +- test/tools/llvm-elfabi/read-elf-dynsym.test | 16 +- test/tools/llvm-elfabi/read-tbe-as-elf.test | 16 +- test/tools/llvm-elfabi/read-tbe-as-tbe.test | 14 +- .../read-tbe-with-bad-bitwidth.test | 17 + .../read-tbe-with-bad-endianness.test | 17 + .../llvm-elfabi/read-unsupported-file.test | 2 +- test/tools/llvm-elfabi/strip-target.test | 27 + .../tbe-emits-current-version.test | 10 +- test/tools/llvm-elfabi/tbe-read-basic.test | 30 +- .../write-stub-no-nonlocal-symbol.test | 8 +- test/tools/llvm-elfabi/write-stub.test | 40 +- tools/llvm-elfabi/CMakeLists.txt | 1 + tools/llvm-elfabi/llvm-elfabi.cpp | 131 ++-- tools/llvm-ifs/CMakeLists.txt | 2 +- tools/llvm-ifs/llvm-ifs.cpp | 31 +- unittests/InterfaceStub/ELFYAMLTest.cpp | 105 ++-- 46 files changed, 1399 insertions(+), 301 deletions(-) create mode 100644 lib/BinaryFormat/ELF.cpp create mode 100644 test/tools/llvm-elfabi/read-tbe-with-bad-bitwidth.test create mode 100644 test/tools/llvm-elfabi/read-tbe-with-bad-endianness.test create mode 100644 test/tools/llvm-elfabi/strip-target.test diff --git a/include/llvm/BinaryFormat/ELF.h b/include/llvm/BinaryFormat/ELF.h index 8660d40ca03..d8961aa43c4 100644 --- a/include/llvm/BinaryFormat/ELF.h +++ b/include/llvm/BinaryFormat/ELF.h @@ -19,8 +19,10 @@ #ifndef LLVM_BINARYFORMAT_ELF_H #define LLVM_BINARYFORMAT_ELF_H +#include "llvm/ADT/StringRef.h" #include #include +#include namespace llvm { namespace ELF { @@ -1673,6 +1675,12 @@ enum { ELFCOMPRESS_HIPROC = 0x7fffffff // End of processor-specific. }; +/// Convert an architecture name into ELF's e_machine value. +uint16_t convertArchNameToEMachine(StringRef Arch); + +/// Convert an ELF's e_machine value into an architecture name. +StringRef convertEMachineToArchName(uint16_t EMachine); + } // end namespace ELF } // end namespace llvm diff --git a/include/llvm/InterfaceStub/ELFObjHandler.h b/include/llvm/InterfaceStub/ELFObjHandler.h index 43cac176d10..a96f02bc388 100644 --- a/include/llvm/InterfaceStub/ELFObjHandler.h +++ b/include/llvm/InterfaceStub/ELFObjHandler.h @@ -35,11 +35,10 @@ Expected> readELFFile(MemoryBufferRef Buf); /// /// @param FilePath File path for writing the ELF binary. /// @param Stub Source ELFStub to generate a binary ELF stub from. -/// @param OutputFormat Target ELFType to write binary as. /// @param WriteIfChanged Whether or not to preserve timestamp if /// the output stays the same. Error writeBinaryStub(StringRef FilePath, const ELFStub &Stub, - ELFTarget OutputFormat, bool WriteIfChanged = false); + bool WriteIfChanged = false); } // end namespace elfabi } // end namespace llvm diff --git a/include/llvm/InterfaceStub/ELFStub.h b/include/llvm/InterfaceStub/ELFStub.h index 20c1ab449bd..a8c3f22a22a 100644 --- a/include/llvm/InterfaceStub/ELFStub.h +++ b/include/llvm/InterfaceStub/ELFStub.h @@ -15,6 +15,7 @@ #define LLVM_INTERFACESTUB_ELFSTUB_H #include "llvm/BinaryFormat/ELF.h" +#include "llvm/Support/Error.h" #include "llvm/Support/VersionTuple.h" #include #include @@ -34,8 +35,25 @@ enum class ELFSymbolType { Unknown = 16, }; +enum class ELFEndiannessType { + Little = ELF::ELFDATA2LSB, + Big = ELF::ELFDATA2MSB, + + // Endianness info is 1 bytes, 256 is safely out of rance. + Unknown = 256, +}; + +enum class ELFBitWidthType { + ELF32 = ELF::ELFCLASS32, + ELF64 = ELF::ELFCLASS64, + + // Bit width info is 1 bytes, 256 is safely out of rance. + Unknown = 256, +}; + struct ELFSymbol { - ELFSymbol(std::string SymbolName) : Name(SymbolName) {} + ELFSymbol() = default; + explicit ELFSymbol(std::string SymbolName) : Name(std::move(SymbolName)) {} std::string Name; uint64_t Size; ELFSymbolType Type; @@ -45,21 +63,42 @@ struct ELFSymbol { bool operator<(const ELFSymbol &RHS) const { return Name < RHS.Name; } }; +struct IFSTarget { + Optional Triple; + Optional ObjectFormat; + Optional Arch; + Optional ArchString; + Optional Endianness; + Optional BitWidth; +}; + // A cumulative representation of ELF stubs. // Both textual and binary stubs will read into and write from this object. -class ELFStub { +struct ELFStub { // TODO: Add support for symbol versioning. -public: VersionTuple TbeVersion; Optional SoName; - ELFArch Arch; + IFSTarget Target; std::vector NeededLibs; - std::set Symbols; + std::vector Symbols; ELFStub() {} ELFStub(const ELFStub &Stub); ELFStub(ELFStub &&Stub); }; + +// Create a alias class for ELFStub. +// LLVM's YAML library does not allow mapping a class with 2 traits, +// which prevents us using 'Target:' field with different definitions. +// This class makes it possible to map a second traits so the same data +// structure can be used for 2 different yaml schema. +struct ELFStubTriple : ELFStub { + ELFStubTriple() {} + ELFStubTriple(const ELFStub &Stub); + ELFStubTriple(const ELFStubTriple &Stub); + ELFStubTriple(ELFStubTriple &&Stub); +}; + } // end namespace elfabi } // end namespace llvm diff --git a/include/llvm/InterfaceStub/TBEHandler.h b/include/llvm/InterfaceStub/TBEHandler.h index aee7ed0d0fc..0caa07af330 100644 --- a/include/llvm/InterfaceStub/TBEHandler.h +++ b/include/llvm/InterfaceStub/TBEHandler.h @@ -15,6 +15,7 @@ #ifndef LLVM_INTERFACESTUB_TBEHANDLER_H #define LLVM_INTERFACESTUB_TBEHANDLER_H +#include "ELFStub.h" #include "llvm/Support/Error.h" #include "llvm/Support/VersionTuple.h" #include @@ -27,7 +28,7 @@ class StringRef; namespace elfabi { -class ELFStub; +struct ELFStub; const VersionTuple TBEVersionCurrent(1, 0); @@ -37,6 +38,22 @@ Expected> readTBEFromBuffer(StringRef Buf); /// Attempts to write an ELF interface file to a raw_ostream. Error writeTBEToOutputStream(raw_ostream &OS, const ELFStub &Stub); +/// Override the target platform inforation in the text stub. +Error overrideTBETarget(ELFStub &Stub, Optional OverrideArch, + Optional OverrideEndianness, + Optional OverrideBitWidth, + Optional OverrideTriple); + +/// Validate the target platform inforation in the text stub. +Error validateTBETarget(ELFStub &Stub, bool ParseTriple); + +/// Strips target platform information from the text stub. +void stripTBETarget(ELFStub &Stub, bool StripTriple, bool StripArch, + bool StripEndianness, bool StripBitWidth); + +/// Parse llvm triple string into a IFSTarget struct. +IFSTarget parseTriple(StringRef TripleStr); + } // end namespace elfabi } // end namespace llvm diff --git a/lib/BinaryFormat/CMakeLists.txt b/lib/BinaryFormat/CMakeLists.txt index 66c89052454..37f6865a487 100644 --- a/lib/BinaryFormat/CMakeLists.txt +++ b/lib/BinaryFormat/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_component_library(LLVMBinaryFormat AMDGPUMetadataVerifier.cpp Dwarf.cpp + ELF.cpp MachO.cpp Magic.cpp Minidump.cpp diff --git a/lib/BinaryFormat/ELF.cpp b/lib/BinaryFormat/ELF.cpp new file mode 100644 index 00000000000..2ede63f464d --- /dev/null +++ b/lib/BinaryFormat/ELF.cpp @@ -0,0 +1,568 @@ +//===- llvm/BinaryFormat/ELF.cpp - The ELF format ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Error.h" + +using namespace llvm; +using namespace ELF; + +/// Convert an architecture name into ELF's e_machine value. +uint16_t ELF::convertArchNameToEMachine(StringRef Arch) { + std::string LowerArch = Arch.lower(); + return StringSwitch(LowerArch) + .Case("none", EM_NONE) + .Case("m32", EM_M32) + .Case("sparc", EM_SPARC) + .Case("386", EM_386) + .Case("68k", EM_68K) + .Case("88k", EM_88K) + .Case("iamcu", EM_IAMCU) + .Case("860", EM_860) + .Case("mips", EM_MIPS) + .Case("s370", EM_S370) + .Case("mips_rs3_le", EM_MIPS_RS3_LE) + .Case("parisc", EM_PARISC) + .Case("vpp500", EM_VPP500) + .Case("sparc32plus", EM_SPARC32PLUS) + .Case("960", EM_960) + .Case("ppc", EM_PPC) + .Case("ppc64", EM_PPC64) + .Case("s390", EM_S390) + .Case("spu", EM_SPU) + .Case("v800", EM_V800) + .Case("fr20", EM_FR20) + .Case("rh32", EM_RH32) + .Case("rce", EM_RCE) + .Case("arm", EM_ARM) + .Case("alpha", EM_ALPHA) + .Case("sh", EM_SH) + .Case("sparcv9", EM_SPARCV9) + .Case("tricore", EM_TRICORE) + .Case("arc", EM_ARC) + .Case("h8_300", EM_H8_300) + .Case("h8_300h", EM_H8_300H) + .Case("h8s", EM_H8S) + .Case("h8_500", EM_H8_500) + .Case("ia_64", EM_IA_64) + .Case("mips_x", EM_MIPS_X) + .Case("coldfire", EM_COLDFIRE) + .Case("68hc12", EM_68HC12) + .Case("mma", EM_MMA) + .Case("pcp", EM_PCP) + .Case("ncpu", EM_NCPU) + .Case("ndr1", EM_NDR1) + .Case("starcore", EM_STARCORE) + .Case("me16", EM_ME16) + .Case("st100", EM_ST100) + .Case("tinyj", EM_TINYJ) + .Case("x86_64", EM_X86_64) + .Case("pdsp", EM_PDSP) + .Case("pdp10", EM_PDP10) + .Case("pdp11", EM_PDP11) + .Case("fx66", EM_FX66) + .Case("st9plus", EM_ST9PLUS) + .Case("st7", EM_ST7) + .Case("68hc16", EM_68HC16) + .Case("68hc11", EM_68HC11) + .Case("68hc08", EM_68HC08) + .Case("68hc05", EM_68HC05) + .Case("svx", EM_SVX) + .Case("st19", EM_ST19) + .Case("vax", EM_VAX) + .Case("cris", EM_CRIS) + .Case("javelin", EM_JAVELIN) + .Case("firepath", EM_FIREPATH) + .Case("zsp", EM_ZSP) + .Case("mmix", EM_MMIX) + .Case("huany", EM_HUANY) + .Case("prism", EM_PRISM) + .Case("avr", EM_AVR) + .Case("fr30", EM_FR30) + .Case("d10v", EM_D10V) + .Case("d30v", EM_D30V) + .Case("v850", EM_V850) + .Case("m32r", EM_M32R) + .Case("mn10300", EM_MN10300) + .Case("mn10200", EM_MN10200) + .Case("pj", EM_PJ) + .Case("openrisc", EM_OPENRISC) + .Case("arc_compact", EM_ARC_COMPACT) + .Case("xtensa", EM_XTENSA) + .Case("videocore", EM_VIDEOCORE) + .Case("tmm_gpp", EM_TMM_GPP) + .Case("ns32k", EM_NS32K) + .Case("tpc", EM_TPC) + .Case("snp1k", EM_SNP1K) + .Case("st200", EM_ST200) + .Case("ip2k", EM_IP2K) + .Case("max", EM_MAX) + .Case("cr", EM_CR) + .Case("f2mc16", EM_F2MC16) + .Case("msp430", EM_MSP430) + .Case("blackfin", EM_BLACKFIN) + .Case("se_c33", EM_SE_C33) + .Case("sep", EM_SEP) + .Case("arca", EM_ARCA) + .Case("unicore", EM_UNICORE) + .Case("excess", EM_EXCESS) + .Case("dxp", EM_DXP) + .Case("altera_nios2", EM_ALTERA_NIOS2) + .Case("crx", EM_CRX) + .Case("xgate", EM_XGATE) + .Case("c166", EM_C166) + .Case("m16c", EM_M16C) + .Case("dspic30f", EM_DSPIC30F) + .Case("ce", EM_CE) + .Case("m32c", EM_M32C) + .Case("tsk3000", EM_TSK3000) + .Case("rs08", EM_RS08) + .Case("sharc", EM_SHARC) + .Case("ecog2", EM_ECOG2) + .Case("score7", EM_SCORE7) + .Case("dsp24", EM_DSP24) + .Case("videocore3", EM_VIDEOCORE3) + .Case("latticemico32", EM_LATTICEMICO32) + .Case("se_c17", EM_SE_C17) + .Case("ti_c6000", EM_TI_C6000) + .Case("ti_c2000", EM_TI_C2000) + .Case("ti_c5500", EM_TI_C5500) + .Case("mmdsp_plus", EM_MMDSP_PLUS) + .Case("cypress_m8c", EM_CYPRESS_M8C) + .Case("r32c", EM_R32C) + .Case("trimedia", EM_TRIMEDIA) + .Case("hexagon", EM_HEXAGON) + .Case("8051", EM_8051) + .Case("stxp7x", EM_STXP7X) + .Case("nds32", EM_NDS32) + .Case("ecog1", EM_ECOG1) + .Case("ecog1x", EM_ECOG1X) + .Case("maxq30", EM_MAXQ30) + .Case("ximo16", EM_XIMO16) + .Case("manik", EM_MANIK) + .Case("craynv2", EM_CRAYNV2) + .Case("rx", EM_RX) + .Case("metag", EM_METAG) + .Case("mcst_elbrus", EM_MCST_ELBRUS) + .Case("ecog16", EM_ECOG16) + .Case("cr16", EM_CR16) + .Case("etpu", EM_ETPU) + .Case("sle9x", EM_SLE9X) + .Case("l10m", EM_L10M) + .Case("k10m", EM_K10M) + .Case("aarch64", EM_AARCH64) + .Case("avr32", EM_AVR32) + .Case("stm8", EM_STM8) + .Case("tile64", EM_TILE64) + .Case("tilepro", EM_TILEPRO) + .Case("cuda", EM_CUDA) + .Case("tilegx", EM_TILEGX) + .Case("cloudshield", EM_CLOUDSHIELD) + .Case("corea_1st", EM_COREA_1ST) + .Case("corea_2nd", EM_COREA_2ND) + .Case("arc_compact2", EM_ARC_COMPACT2) + .Case("open8", EM_OPEN8) + .Case("rl78", EM_RL78) + .Case("videocore5", EM_VIDEOCORE5) + .Case("78kor", EM_78KOR) + .Case("56800ex", EM_56800EX) + .Case("ba1", EM_BA1) + .Case("ba2", EM_BA2) + .Case("xcore", EM_XCORE) + .Case("mchp_pic", EM_MCHP_PIC) + .Case("intel205", EM_INTEL205) + .Case("intel206", EM_INTEL206) + .Case("intel207", EM_INTEL207) + .Case("intel208", EM_INTEL208) + .Case("intel209", EM_INTEL209) + .Case("km32", EM_KM32) + .Case("kmx32", EM_KMX32) + .Case("kmx16", EM_KMX16) + .Case("kmx8", EM_KMX8) + .Case("kvarc", EM_KVARC) + .Case("cdp", EM_CDP) + .Case("coge", EM_COGE) + .Case("cool", EM_COOL) + .Case("norc", EM_NORC) + .Case("csr_kalimba", EM_CSR_KALIMBA) + .Case("amdgpu", EM_AMDGPU) + .Case("riscv", EM_RISCV) + .Case("lanai", EM_LANAI) + .Case("bpf", EM_BPF) + .Case("ve", EM_VE) + .Case("csky", EM_CSKY) + .Default(EM_NONE); +} + +/// Convert an ELF's e_machine value into an architecture name. +StringRef ELF::convertEMachineToArchName(uint16_t EMachine) { + switch (EMachine) { + case EM_NONE: + return "None"; + case EM_M32: + return "m32"; + case EM_SPARC: + return "sparc"; + case EM_386: + return "386"; + case EM_68K: + return "68k"; + case EM_88K: + return "88k"; + case EM_IAMCU: + return "iamcu"; + case EM_860: + return "860"; + case EM_MIPS: + return "mips"; + case EM_S370: + return "s370"; + case EM_MIPS_RS3_LE: + return "mips_rs3_le"; + case EM_PARISC: + return "parisc"; + case EM_VPP500: + return "vpp500"; + case EM_SPARC32PLUS: + return "sparc32plus"; + case EM_960: + return "960"; + case EM_PPC: + return "ppc"; + case EM_PPC64: + return "ppc64"; + case EM_S390: + return "s390"; + case EM_SPU: + return "spu"; + case EM_V800: + return "v800"; + case EM_FR20: + return "fr20"; + case EM_RH32: + return "rh32"; + case EM_RCE: + return "rce"; + case EM_ARM: + return "arm"; + case EM_ALPHA: + return "alpha"; + case EM_SH: + return "sh"; + case EM_SPARCV9: + return "sparcv9"; + case EM_TRICORE: + return "tricore"; + case EM_ARC: + return "arc"; + case EM_H8_300: + return "h8_300"; + case EM_H8_300H: + return "h8_300h"; + case EM_H8S: + return "h8s"; + case EM_H8_500: + return "h8_500"; + case EM_IA_64: + return "ia_64"; + case EM_MIPS_X: + return "mips_x"; + case EM_COLDFIRE: + return "coldfire"; + case EM_68HC12: + return "68hc12"; + case EM_MMA: + return "mma"; + case EM_PCP: + return "pcp"; + case EM_NCPU: + return "ncpu"; + case EM_NDR1: + return "ndr1"; + case EM_STARCORE: + return "starcore"; + case EM_ME16: + return "me16"; + case EM_ST100: + return "st100"; + case EM_TINYJ: + return "tinyj"; + case EM_X86_64: + return "x86_64"; + case EM_PDSP: + return "pdsp"; + case EM_PDP10: + return "pdp10"; + case EM_PDP11: + return "pdp11"; + case EM_FX66: + return "fx66"; + case EM_ST9PLUS: + return "st9plus"; + case EM_ST7: + return "st7"; + case EM_68HC16: + return "68hc16"; + case EM_68HC11: + return "68hc11"; + case EM_68HC08: + return "68hc08"; + case EM_68HC05: + return "68hc05"; + case EM_SVX: + return "svx"; + case EM_ST19: + return "st19"; + case EM_VAX: + return "vax"; + case EM_CRIS: + return "cris"; + case EM_JAVELIN: + return "javelin"; + case EM_FIREPATH: + return "firepath"; + case EM_ZSP: + return "zsp"; + case EM_MMIX: + return "mmix"; + case EM_HUANY: + return "huany"; + case EM_PRISM: + return "prism"; + case EM_AVR: + return "avr"; + case EM_FR30: + return "fr30"; + case EM_D10V: + return "d10v"; + case EM_D30V: + return "d30v"; + case EM_V850: + return "v850"; + case EM_M32R: + return "m32r"; + case EM_MN10300: + return "mn10300"; + case EM_MN10200: + return "mn10200"; + case EM_PJ: + return "pj"; + case EM_OPENRISC: + return "openrisc"; + case EM_ARC_COMPACT: + return "arc_compact"; + case EM_XTENSA: + return "xtensa"; + case EM_VIDEOCORE: + return "videocore"; + case EM_TMM_GPP: + return "tmm_gpp"; + case EM_NS32K: + return "ns32k"; + case EM_TPC: + return "tpc"; + case EM_SNP1K: + return "snp1k"; + case EM_ST200: + return "st200"; + case EM_IP2K: + return "ip2k"; + case EM_MAX: + return "max"; + case EM_CR: + return "cr"; + case EM_F2MC16: + return "f2mc16"; + case EM_MSP430: + return "msp430"; + case EM_BLACKFIN: + return "blackfin"; + case EM_SE_C33: + return "se_c33"; + case EM_SEP: + return "sep"; + case EM_ARCA: + return "arca"; + case EM_UNICORE: + return "unicore"; + case EM_EXCESS: + return "excess"; + case EM_DXP: + return "dxp"; + case EM_ALTERA_NIOS2: + return "altera_nios2"; + case EM_CRX: + return "crx"; + case EM_XGATE: + return "xgate"; + case EM_C166: + return "c166"; + case EM_M16C: + return "m16c"; + case EM_DSPIC30F: + return "dspic30f"; + case EM_CE: + return "ce"; + case EM_M32C: + return "m32c"; + case EM_TSK3000: + return "tsk3000"; + case EM_RS08: + return "rs08"; + case EM_SHARC: + return "sharc"; + case EM_ECOG2: + return "ecog2"; + case EM_SCORE7: + return "score7"; + case EM_DSP24: + return "dsp24"; + case EM_VIDEOCORE3: + return "videocore3"; + case EM_LATTICEMICO32: + return "latticemico32"; + case EM_SE_C17: + return "se_c17"; + case EM_TI_C6000: + return "ti_c6000"; + case EM_TI_C2000: + return "ti_c2000"; + case EM_TI_C5500: + return "ti_c5500"; + case EM_MMDSP_PLUS: + return "mmdsp_plus"; + case EM_CYPRESS_M8C: + return "cypress_m8c"; + case EM_R32C: + return "r32c"; + case EM_TRIMEDIA: + return "trimedia"; + case EM_HEXAGON: + return "hexagon"; + case EM_8051: + return "8051"; + case EM_STXP7X: + return "stxp7x"; + case EM_NDS32: + return "nds32"; + case EM_ECOG1: + return "ecog1"; + case EM_MAXQ30: + return "maxq30"; + case EM_XIMO16: + return "ximo16"; + case EM_MANIK: + return "manik"; + case EM_CRAYNV2: + return "craynv2"; + case EM_RX: + return "rx"; + case EM_METAG: + return "metag"; + case EM_MCST_ELBRUS: + return "mcst_elbrus"; + case EM_ECOG16: + return "ecog16"; + case EM_CR16: + return "cr16"; + case EM_ETPU: + return "etpu"; + case EM_SLE9X: + return "sle9x"; + case EM_L10M: + return "l10m"; + case EM_K10M: + return "k10m"; + case EM_AARCH64: + return "AArch64"; + case EM_AVR32: + return "avr32"; + case EM_STM8: + return "stm8"; + case EM_TILE64: + return "tile64"; + case EM_TILEPRO: + return "tilepro"; + case EM_CUDA: + return "cuda"; + case EM_TILEGX: + return "tilegx"; + case EM_CLOUDSHIELD: + return "cloudshield"; + case EM_COREA_1ST: + return "corea_1st"; + case EM_COREA_2ND: + return "corea_2nd"; + case EM_ARC_COMPACT2: + return "arc_compact2"; + case EM_OPEN8: + return "open8"; + case EM_RL78: + return "rl78"; + case EM_VIDEOCORE5: + return "videocore5"; + case EM_78KOR: + return "78kor"; + case EM_56800EX: + return "56800ex"; + case EM_BA1: + return "ba1"; + case EM_BA2: + return "ba2"; + case EM_XCORE: + return "xcore"; + case EM_MCHP_PIC: + return "mchp_pic"; + case EM_INTEL205: + return "intel205"; + case EM_INTEL206: + return "intel206"; + case EM_INTEL207: + return "intel207"; + case EM_INTEL208: + return "intel208"; + case EM_INTEL209: + return "intel209"; + case EM_KM32: + return "km32"; + case EM_KMX32: + return "kmx32"; + case EM_KMX16: + return "kmx16"; + case EM_KMX8: + return "kmx8"; + case EM_KVARC: + return "kvarc"; + case EM_CDP: + return "cdp"; + case EM_COGE: + return "coge"; + case EM_COOL: + return "cool"; + case EM_NORC: + return "norc"; + case EM_CSR_KALIMBA: + return "csr_kalimba"; + case EM_AMDGPU: + return "amdgpu"; + case EM_RISCV: + return "riscv"; + case EM_LANAI: + return "lanai"; + case EM_BPF: + return "bpf"; + case EM_VE: + return "ve"; + case EM_CSKY: + return "csky"; + default: + return "None"; + } +} diff --git a/lib/InterfaceStub/CMakeLists.txt b/lib/InterfaceStub/CMakeLists.txt index 17801999c48..497cd6d7810 100644 --- a/lib/InterfaceStub/CMakeLists.txt +++ b/lib/InterfaceStub/CMakeLists.txt @@ -4,6 +4,7 @@ add_llvm_component_library(LLVMInterfaceStub TBEHandler.cpp LINK_COMPONENTS + BinaryFormat MC Object Support diff --git a/lib/InterfaceStub/ELFObjHandler.cpp b/lib/InterfaceStub/ELFObjHandler.cpp index 9deb5ba0ae4..6ed52befa04 100644 --- a/lib/InterfaceStub/ELFObjHandler.cpp +++ b/lib/InterfaceStub/ELFObjHandler.cpp @@ -250,7 +250,8 @@ public: fillStrTabShdr(ShStrTab); // Finish initializing the ELF header. - initELFHeader(ElfHeader, Stub.Arch); + initELFHeader(ElfHeader, + static_cast(Stub.Target.Arch.getValue())); ElfHeader.e_shstrndx = ShStrTab.Index; ElfHeader.e_shnum = LastSection->Index + 1; ElfHeader.e_shoff = @@ -517,7 +518,7 @@ static Error populateSymbols(ELFStub &TargetStub, if (!SymName) return SymName.takeError(); ELFSymbol Sym = createELFSym(*SymName, RawSym); - TargetStub.Symbols.insert(std::move(Sym)); + TargetStub.Symbols.push_back(std::move(Sym)); // TODO: Populate symbol warning. } return Error::success(); @@ -561,7 +562,12 @@ buildStub(const ELFObjectFile &ElfObj) { DynEnt.StrSize); // Populate Arch from ELF header. - DestStub->Arch = ElfFile.getHeader().e_machine; + DestStub->Target.Arch = static_cast(ElfFile.getHeader().e_machine); + DestStub->Target.BitWidth = + (ELFBitWidthType)ElfFile.getHeader().e_ident[EI_CLASS]; + DestStub->Target.Endianness = + (ELFEndiannessType)ElfFile.getHeader().e_ident[EI_DATA]; + DestStub->Target.ObjectFormat = "ELF"; // Populate SoName from .dynamic entries and dynamic string table. if (DynEnt.SONameOffset.hasValue()) { @@ -667,15 +673,23 @@ Expected> readELFFile(MemoryBufferRef Buf) { // This function wraps the ELFT writeELFBinaryToFile() so writeBinaryStub() // can be called without having to use ELFType templates directly. Error writeBinaryStub(StringRef FilePath, const ELFStub &Stub, - ELFTarget OutputFormat, bool WriteIfChanged) { - if (OutputFormat == ELFTarget::ELF32LE) - return writeELFBinaryToFile(FilePath, Stub, WriteIfChanged); - if (OutputFormat == ELFTarget::ELF32BE) - return writeELFBinaryToFile(FilePath, Stub, WriteIfChanged); - if (OutputFormat == ELFTarget::ELF64LE) - return writeELFBinaryToFile(FilePath, Stub, WriteIfChanged); - if (OutputFormat == ELFTarget::ELF64BE) - return writeELFBinaryToFile(FilePath, Stub, WriteIfChanged); + bool WriteIfChanged) { + assert(Stub.Target.Arch); + assert(Stub.Target.BitWidth); + assert(Stub.Target.Endianness); + if (Stub.Target.BitWidth == ELFBitWidthType::ELF32) { + if (Stub.Target.Endianness == ELFEndiannessType::Little) { + return writeELFBinaryToFile(FilePath, Stub, WriteIfChanged); + } else { + return writeELFBinaryToFile(FilePath, Stub, WriteIfChanged); + } + } else { + if (Stub.Target.Endianness == ELFEndiannessType::Little) { + return writeELFBinaryToFile(FilePath, Stub, WriteIfChanged); + } else { + return writeELFBinaryToFile(FilePath, Stub, WriteIfChanged); + } + } llvm_unreachable("invalid binary output target"); } diff --git a/lib/InterfaceStub/ELFStub.cpp b/lib/InterfaceStub/ELFStub.cpp index 3c637695d8e..81c521b5413 100644 --- a/lib/InterfaceStub/ELFStub.cpp +++ b/lib/InterfaceStub/ELFStub.cpp @@ -7,13 +7,14 @@ //===-----------------------------------------------------------------------===/ #include "llvm/InterfaceStub/ELFStub.h" +#include "llvm/Support/Error.h" using namespace llvm; using namespace llvm::elfabi; ELFStub::ELFStub(ELFStub const &Stub) { TbeVersion = Stub.TbeVersion; - Arch = Stub.Arch; + Target = Stub.Target; SoName = Stub.SoName; NeededLibs = Stub.NeededLibs; Symbols = Stub.Symbols; @@ -21,7 +22,31 @@ ELFStub::ELFStub(ELFStub const &Stub) { ELFStub::ELFStub(ELFStub &&Stub) { TbeVersion = std::move(Stub.TbeVersion); - Arch = std::move(Stub.Arch); + Target = std::move(Stub.Target); + SoName = std::move(Stub.SoName); + NeededLibs = std::move(Stub.NeededLibs); + Symbols = std::move(Stub.Symbols); +} + +ELFStubTriple::ELFStubTriple(ELFStubTriple const &Stub) { + TbeVersion = Stub.TbeVersion; + Target = Stub.Target; + SoName = Stub.SoName; + NeededLibs = Stub.NeededLibs; + Symbols = Stub.Symbols; +} + +ELFStubTriple::ELFStubTriple(ELFStub const &Stub) { + TbeVersion = Stub.TbeVersion; + Target = Stub.Target; + SoName = Stub.SoName; + NeededLibs = Stub.NeededLibs; + Symbols = Stub.Symbols; +} + +ELFStubTriple::ELFStubTriple(ELFStubTriple &&Stub) { + TbeVersion = std::move(Stub.TbeVersion); + Target = std::move(Stub.Target); SoName = std::move(Stub.SoName); NeededLibs = std::move(Stub.NeededLibs); Symbols = std::move(Stub.Symbols); diff --git a/lib/InterfaceStub/TBEHandler.cpp b/lib/InterfaceStub/TBEHandler.cpp index ee95d21ee66..ea2dd7a26b4 100644 --- a/lib/InterfaceStub/TBEHandler.cpp +++ b/lib/InterfaceStub/TBEHandler.cpp @@ -9,14 +9,16 @@ #include "llvm/InterfaceStub/TBEHandler.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" #include "llvm/InterfaceStub/ELFStub.h" #include "llvm/Support/Error.h" +#include "llvm/Support/LineIterator.h" #include "llvm/Support/YAMLTraits.h" using namespace llvm; using namespace llvm::elfabi; -LLVM_YAML_STRONG_TYPEDEF(ELFArch, ELFArchMapper) +LLVM_YAML_IS_SEQUENCE_VECTOR(ELFSymbol) namespace llvm { namespace yaml { @@ -35,43 +37,80 @@ template <> struct ScalarEnumerationTraits { } }; -/// YAML traits for ELFArch. -template <> struct ScalarTraits { - static void output(const ELFArchMapper &Value, void *, +template <> struct ScalarTraits { + static void output(const ELFEndiannessType &Value, void *, llvm::raw_ostream &Out) { - // Map from integer to architecture string. switch (Value) { - case (ELFArch)ELF::EM_X86_64: - Out << "x86_64"; + case ELFEndiannessType::Big: + Out << "big"; break; - case (ELFArch)ELF::EM_AARCH64: - Out << "AArch64"; + case ELFEndiannessType::Little: + Out << "little"; break; - case (ELFArch)ELF::EM_NONE: default: - Out << "Unknown"; + llvm_unreachable("Unsupported endianness"); } } - static StringRef input(StringRef Scalar, void *, ELFArchMapper &Value) { - // Map from architecture string to integer. - Value = StringSwitch(Scalar) - .Case("x86_64", ELF::EM_X86_64) - .Case("AArch64", ELF::EM_AARCH64) - .Case("Unknown", ELF::EM_NONE) - .Default(ELF::EM_NONE); - - // Returning empty StringRef indicates successful parse. + static StringRef input(StringRef Scalar, void *, ELFEndiannessType &Value) { + Value = StringSwitch(Scalar) + .Case("big", ELFEndiannessType::Big) + .Case("little", ELFEndiannessType::Little) + .Default(ELFEndiannessType::Unknown); + if (Value == ELFEndiannessType::Unknown) { + return "Unsupported endianness"; + } return StringRef(); } - // Don't place quotation marks around architecture value. static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; +template <> struct ScalarTraits { + static void output(const ELFBitWidthType &Value, void *, + llvm::raw_ostream &Out) { + switch (Value) { + case ELFBitWidthType::ELF32: + Out << "32"; + break; + case ELFBitWidthType::ELF64: + Out << "64"; + break; + default: + llvm_unreachable("Unsupported bit width"); + } + } + + static StringRef input(StringRef Scalar, void *, ELFBitWidthType &Value) { + Value = StringSwitch(Scalar) + .Case("32", ELFBitWidthType::ELF32) + .Case("64", ELFBitWidthType::ELF64) + .Default(ELFBitWidthType::Unknown); + if (Value == ELFBitWidthType::Unknown) { + return "Unsupported bit width"; + } + return StringRef(); + } + + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, IFSTarget &Target) { + IO.mapOptional("ObjectFormat", Target.ObjectFormat); + IO.mapOptional("Arch", Target.ArchString); + IO.mapOptional("Endianness", Target.Endianness); + IO.mapOptional("BitWidth", Target.BitWidth); + } + + // Compacts symbol information into a single line. + static const bool flow = true; // NOLINT(readability-identifier-naming) +}; + /// YAML traits for ELFSymbol. template <> struct MappingTraits { static void mapping(IO &IO, ELFSymbol &Symbol) { + IO.mapRequired("Name", Symbol.Name); IO.mapRequired("Type", Symbol.Type); // The need for symbol size depends on the symbol type. if (Symbol.Type == ELFSymbolType::NoType) { @@ -87,57 +126,203 @@ template <> struct MappingTraits { } // Compacts symbol information into a single line. - static const bool flow = true; -}; - -/// YAML traits for set of ELFSymbols. -template <> struct CustomMappingTraits> { - static void inputOne(IO &IO, StringRef Key, std::set &Set) { - ELFSymbol Sym(Key.str()); - IO.mapRequired(Key.str().c_str(), Sym); - Set.insert(Sym); - } - - static void output(IO &IO, std::set &Set) { - for (auto &Sym : Set) - IO.mapRequired(Sym.Name.c_str(), const_cast(Sym)); - } + static const bool flow = true; // NOLINT(readability-identifier-naming) }; /// YAML traits for ELFStub objects. template <> struct MappingTraits { static void mapping(IO &IO, ELFStub &Stub) { - if (!IO.mapTag("!tapi-tbe", true)) + if (!IO.mapTag("!ifs-v1", true)) IO.setError("Not a .tbe YAML file."); IO.mapRequired("TbeVersion", Stub.TbeVersion); IO.mapOptional("SoName", Stub.SoName); - IO.mapRequired("Arch", (ELFArchMapper &)Stub.Arch); + IO.mapOptional("Target", Stub.Target); IO.mapOptional("NeededLibs", Stub.NeededLibs); IO.mapRequired("Symbols", Stub.Symbols); } }; +/// YAML traits for ELFStubTriple objects. +template <> struct MappingTraits { + static void mapping(IO &IO, ELFStubTriple &Stub) { + if (!IO.mapTag("!ifs-v1", true)) + IO.setError("Not a .tbe YAML file."); + IO.mapRequired("TbeVersion", Stub.TbeVersion); + IO.mapOptional("SoName", Stub.SoName); + IO.mapOptional("Target", Stub.Target.Triple); + IO.mapOptional("NeededLibs", Stub.NeededLibs); + IO.mapRequired("Symbols", Stub.Symbols); + } +}; } // end namespace yaml } // end namespace llvm +/// Attempt to determine if a Text stub uses target triple. +bool usesTriple(StringRef Buf) { + for (line_iterator I(MemoryBufferRef(Buf, "ELFStub")); !I.is_at_eof(); ++I) { + StringRef Line = (*I).trim(); + if (Line.startswith("Target:")) { + if (Line == "Target:" || (Line.find("{") != Line.npos)) { + return false; + } + } + } + return true; +} + Expected> elfabi::readTBEFromBuffer(StringRef Buf) { yaml::Input YamlIn(Buf); - std::unique_ptr Stub(new ELFStub()); - YamlIn >> *Stub; - if (std::error_code Err = YamlIn.error()) + std::unique_ptr Stub(new ELFStubTriple()); + if (usesTriple(Buf)) { + YamlIn >> *Stub; + } else { + YamlIn >> *static_cast(Stub.get()); + } + if (std::error_code Err = YamlIn.error()) { return createStringError(Err, "YAML failed reading as TBE"); + } if (Stub->TbeVersion > elfabi::TBEVersionCurrent) return make_error( "TBE version " + Stub->TbeVersion.getAsString() + " is unsupported.", std::make_error_code(std::errc::invalid_argument)); - + if (Stub->Target.ArchString) { + Stub->Target.Arch = + ELF::convertArchNameToEMachine(Stub->Target.ArchString.getValue()); + } return std::move(Stub); } Error elfabi::writeTBEToOutputStream(raw_ostream &OS, const ELFStub &Stub) { yaml::Output YamlOut(OS, NULL, /*WrapColumn =*/0); + std::unique_ptr CopyStub(new ELFStubTriple(Stub)); + if (Stub.Target.Arch) { + CopyStub->Target.ArchString = std::string( + ELF::convertEMachineToArchName(Stub.Target.Arch.getValue())); + } + IFSTarget Target = Stub.Target; - YamlOut << const_cast(Stub); + if (CopyStub->Target.Triple || + (!CopyStub->Target.ArchString && !CopyStub->Target.Endianness && + !CopyStub->Target.BitWidth)) + YamlOut << *CopyStub; + else + YamlOut << *static_cast(CopyStub.get()); return Error::success(); } + +Error elfabi::overrideTBETarget(ELFStub &Stub, Optional OverrideArch, + Optional OverrideEndianness, + Optional OverrideBitWidth, + Optional OverrideTriple) { + std::error_code OverrideEC(1, std::generic_category()); + if (OverrideArch) { + if (Stub.Target.Arch && + Stub.Target.Arch.getValue() != OverrideArch.getValue()) { + return make_error( + "Supplied Arch conflicts with the text stub", OverrideEC); + } + Stub.Target.Arch = OverrideArch.getValue(); + } + if (OverrideEndianness) { + if (Stub.Target.Endianness && + Stub.Target.Endianness.getValue() != OverrideEndianness.getValue()) { + return make_error( + "Supplied Endianness conflicts with the text stub", OverrideEC); + } + Stub.Target.Endianness = OverrideEndianness.getValue(); + } + if (OverrideBitWidth) { + if (Stub.Target.BitWidth && + Stub.Target.BitWidth.getValue() != OverrideBitWidth.getValue()) { + return make_error( + "Supplied BitWidth conflicts with the text stub", OverrideEC); + } + Stub.Target.BitWidth = OverrideBitWidth.getValue(); + } + if (OverrideTriple) { + if (Stub.Target.Triple && + Stub.Target.Triple.getValue() != OverrideTriple.getValue()) { + return make_error( + "Supplied Triple conflicts with the text stub", OverrideEC); + } + Stub.Target.Triple = OverrideTriple.getValue(); + } + return Error::success(); +} + +Error elfabi::validateTBETarget(ELFStub &Stub, bool ParseTriple) { + std::error_code ValidationEC(1, std::generic_category()); + if (Stub.Target.Triple) { + if (Stub.Target.Arch || Stub.Target.BitWidth || Stub.Target.Endianness || + Stub.Target.ObjectFormat) { + return make_error( + "Target triple cannot be used simultaneously with ELF target format", + ValidationEC); + } + if (ParseTriple) { + IFSTarget TargetFromTriple = parseTriple(Stub.Target.Triple.getValue()); + Stub.Target.Arch = TargetFromTriple.Arch; + Stub.Target.BitWidth = TargetFromTriple.BitWidth; + Stub.Target.Endianness = TargetFromTriple.Endianness; + } + return Error::success(); + } + if (!Stub.Target.Arch || !Stub.Target.BitWidth || !Stub.Target.Endianness) { + // TODO: unify the error message. + if (!Stub.Target.Arch) { + return make_error("Arch is not defined in the text stub", + ValidationEC); + } + if (!Stub.Target.BitWidth) { + return make_error("BitWidth is not defined in the text stub", + ValidationEC); + } + if (!Stub.Target.Endianness) { + return make_error( + "Endianness is not defined in the text stub", ValidationEC); + } + } + return Error::success(); +} + +IFSTarget elfabi::parseTriple(StringRef TripleStr) { + Triple IFSTriple(TripleStr); + IFSTarget RetTarget; + // TODO: Implement a Triple Arch enum to e_machine map. + switch (IFSTriple.getArch()) { + case Triple::ArchType::aarch64: + RetTarget.Arch = (ELFArch)ELF::EM_AARCH64; + break; + case Triple::ArchType::x86_64: + RetTarget.Arch = (ELFArch)ELF::EM_X86_64; + break; + default: + RetTarget.Arch = (ELFArch)ELF::EM_NONE; + } + RetTarget.Endianness = IFSTriple.isLittleEndian() ? ELFEndiannessType::Little + : ELFEndiannessType::Big; + RetTarget.BitWidth = + IFSTriple.isArch64Bit() ? ELFBitWidthType::ELF64 : ELFBitWidthType::ELF32; + return RetTarget; +} + +void elfabi::stripTBETarget(ELFStub &Stub, bool StripTriple, bool StripArch, + bool StripEndianness, bool StripBitWidth) { + if (StripTriple || StripArch) { + Stub.Target.Arch.reset(); + Stub.Target.ArchString.reset(); + } + if (StripTriple || StripEndianness) { + Stub.Target.Endianness.reset(); + } + if (StripTriple || StripBitWidth) { + Stub.Target.BitWidth.reset(); + } + if (StripTriple) { + Stub.Target.Triple.reset(); + } + if (!Stub.Target.Arch && !Stub.Target.BitWidth && !Stub.Target.Endianness) { + Stub.Target.ObjectFormat.reset(); + } +} diff --git a/test/tools/llvm-elfabi/binary-read-add-soname.test b/test/tools/llvm-elfabi/binary-read-add-soname.test index 0f75a4c3b34..90f0849748c 100644 --- a/test/tools/llvm-elfabi/binary-read-add-soname.test +++ b/test/tools/llvm-elfabi/binary-read-add-soname.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: llvm-elfabi --elf %t --emit-tbe=- --soname=best.so | FileCheck %s +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --output=- --soname=best.so %t | FileCheck %s !ELF FileHeader: @@ -42,9 +42,9 @@ ProgramHeaders: FirstSec: .dynamic LastSec: .dynamic -# CHECK: --- !tapi-tbe +# CHECK: --- !ifs-v1 # CHECK-NEXT: TbeVersion: {{[1-9]\d*\.(0|([1-9]\d*))}} # CHECK-NEXT: SoName: best.so{{$}} -# CHECK-NEXT: Arch: AArch64 -# CHECK-NEXT: Symbols: {} +# CHECK-NEXT: Target: { ObjectFormat: ELF, Arch: AArch64, Endianness: little, BitWidth: 64 } +# CHECK-NEXT: Symbols: [] # CHECK-NEXT: ... diff --git a/test/tools/llvm-elfabi/binary-read-arch.test b/test/tools/llvm-elfabi/binary-read-arch.test index e0e6ddd7f9c..1bf5c91a9e6 100644 --- a/test/tools/llvm-elfabi/binary-read-arch.test +++ b/test/tools/llvm-elfabi/binary-read-arch.test @@ -1,7 +1,8 @@ -# RUN: yaml2obj %s -o %t -# RUN: llvm-elfabi --elf %t --emit-tbe=- | FileCheck %s +# RUN: yaml2obj --docnum=1 %s -o %t +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --output=- %t | FileCheck %s -DTARGET="{ ObjectFormat: ELF, Arch: x86_64, Endianness: little, BitWidth: 64 }" +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --output=- --hint-ifs-target="x86_64-linux-gnu" %t | FileCheck %s -DTARGET="x86_64-linux-gnu" -!ELF +--- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB @@ -42,8 +43,101 @@ ProgramHeaders: FirstSec: .dynamic LastSec: .dynamic -# CHECK: --- !tapi-tbe +# CHECK: --- !ifs-v1 # CHECK-NEXT: TbeVersion: {{[1-9]\d*\.(0|([1-9]\d*))}} -# CHECK-NEXT: Arch: x86_64 -# CHECK-NEXT: Symbols: {} +# CHECK-NEXT: Target: [[TARGET]] +# CHECK-NEXT: Symbols: [] # CHECK-NEXT: ... + +# HINTERR: error: Triple hint does not match the actual [[MSG]] + +# RUN: yaml2obj --docnum=1 %s -o %t +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=%t.tbe --hint-ifs-target="aarch64-linux-gnu" %t 2>&1 | FileCheck %s -DMSG=architecture --check-prefix=HINTERR + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + Address: 0x0000 + Content: "00" + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Address: 0x0000000000000008 + Link: .dynstr + AddressAlign: 0x0000000000000008 + EntSize: 0x0000000000000010 + Entries: + - Tag: DT_STRSZ + Value: 0x0000000000000001 + - Tag: DT_STRTAB + Value: 0x0000000000000000 + - Tag: DT_SYMTAB + Value: 0x0000000000000000 + - Tag: DT_NULL + Value: 0x0000000000000000 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_R ] + VAddr: 0x0000 + Align: 8 + FirstSec: .dynstr + LastSec: .dynamic + - Type: PT_DYNAMIC + Flags: [ PF_X, PF_R ] + VAddr: 0x0008 + FirstSec: .dynamic + LastSec: .dynamic + +# RUN: yaml2obj --docnum=2 %s -o %t +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=%t.tbe --hint-ifs-target="x86_64-unknown-linux-gnu" %t 2>&1 | FileCheck %s -DMSG="endianness" --check-prefix=HINTERR + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + Address: 0x0000 + Content: "00" + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Address: 0x0000000000000008 + Link: .dynstr + AddressAlign: 0x0000000000000008 + EntSize: 0x0000000000000010 + Entries: + - Tag: DT_STRSZ + Value: 0x0000000000000001 + - Tag: DT_STRTAB + Value: 0x0000000000000000 + - Tag: DT_SYMTAB + Value: 0x0000000000000000 + - Tag: DT_NULL + Value: 0x0000000000000000 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_R ] + VAddr: 0x0000 + Align: 8 + FirstSec: .dynstr + LastSec: .dynamic + - Type: PT_DYNAMIC + Flags: [ PF_X, PF_R ] + VAddr: 0x0008 + FirstSec: .dynamic + LastSec: .dynamic + +# RUN: yaml2obj --docnum=3 %s -o %t +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=%t.tbe --hint-ifs-target="x86_64-unknown-linux-gnu" %t 2>&1 | FileCheck %s -DMSG="bit width" --check-prefix=HINTERR diff --git a/test/tools/llvm-elfabi/binary-read-bad-soname.test b/test/tools/llvm-elfabi/binary-read-bad-soname.test index 032d3e1c82a..e1c2bdf3a00 100644 --- a/test/tools/llvm-elfabi/binary-read-bad-soname.test +++ b/test/tools/llvm-elfabi/binary-read-bad-soname.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: not llvm-elfabi --elf %t --emit-tbe=%t.tbe 2>&1 | FileCheck %s +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=%t.tbe %t 2>&1 | FileCheck %s !ELF FileHeader: diff --git a/test/tools/llvm-elfabi/binary-read-bad-vaddr.test b/test/tools/llvm-elfabi/binary-read-bad-vaddr.test index 666a01acca6..41ccbd5d7dc 100644 --- a/test/tools/llvm-elfabi/binary-read-bad-vaddr.test +++ b/test/tools/llvm-elfabi/binary-read-bad-vaddr.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: not llvm-elfabi --elf %t --emit-tbe=%t.tbe 2>&1 | FileCheck %s +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=%t.tbe %t 2>&1 | FileCheck %s !ELF FileHeader: diff --git a/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test b/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test index 3c2edcbb9ea..e057c817bec 100644 --- a/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test +++ b/test/tools/llvm-elfabi/binary-read-neededlibs-bad-offset.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: not llvm-elfabi --elf %t --emit-tbe=%t.tbe 2>&1 | FileCheck %s +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=%t.tbe %t 2>&1 | FileCheck %s !ELF FileHeader: diff --git a/test/tools/llvm-elfabi/binary-read-neededlibs.test b/test/tools/llvm-elfabi/binary-read-neededlibs.test index 51adf60866c..b6ad1103d4b 100644 --- a/test/tools/llvm-elfabi/binary-read-neededlibs.test +++ b/test/tools/llvm-elfabi/binary-read-neededlibs.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: llvm-elfabi --elf %t --emit-tbe=- | FileCheck %s +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --output=- %t | FileCheck %s !ELF FileHeader: @@ -48,4 +48,4 @@ ProgramHeaders: # CHECK: NeededLibs: # CHECK-NEXT: - libfoo.so{{$}} # CHECK-NEXT: - libbar.so{{$}} -# CHECK-NEXT: Symbols: {} +# CHECK-NEXT: Symbols: [] diff --git a/test/tools/llvm-elfabi/binary-read-no-dt-strsz.test b/test/tools/llvm-elfabi/binary-read-no-dt-strsz.test index 0a21fd84ead..1685a4ae153 100644 --- a/test/tools/llvm-elfabi/binary-read-no-dt-strsz.test +++ b/test/tools/llvm-elfabi/binary-read-no-dt-strsz.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: not llvm-elfabi --elf %t --emit-tbe=%t.tbe 2>&1 | FileCheck %s +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=%t.tbe %t 2>&1 | FileCheck %s !ELF FileHeader: diff --git a/test/tools/llvm-elfabi/binary-read-no-dt-strtab.test b/test/tools/llvm-elfabi/binary-read-no-dt-strtab.test index 4d3c0c7601a..3b208f0e39f 100644 --- a/test/tools/llvm-elfabi/binary-read-no-dt-strtab.test +++ b/test/tools/llvm-elfabi/binary-read-no-dt-strtab.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: not llvm-elfabi --elf %t --emit-tbe=%t.tbe 2>&1 | FileCheck %s +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=%t.tbe %t 2>&1 | FileCheck %s !ELF FileHeader: diff --git a/test/tools/llvm-elfabi/binary-read-no-dynamic.test b/test/tools/llvm-elfabi/binary-read-no-dynamic.test index fc88d83340e..a1e99e5b35b 100644 --- a/test/tools/llvm-elfabi/binary-read-no-dynamic.test +++ b/test/tools/llvm-elfabi/binary-read-no-dynamic.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: not llvm-elfabi --elf %t --emit-tbe=%t.tbe 2>&1 | FileCheck %s +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=%t.tbe %t 2>&1 | FileCheck %s !ELF FileHeader: diff --git a/test/tools/llvm-elfabi/binary-read-replace-soname.test b/test/tools/llvm-elfabi/binary-read-replace-soname.test index e58e8e9a7dc..e0c26d0c487 100644 --- a/test/tools/llvm-elfabi/binary-read-replace-soname.test +++ b/test/tools/llvm-elfabi/binary-read-replace-soname.test @@ -1,6 +1,6 @@ # RUN: yaml2obj %s -o %t -# RUN: llvm-elfabi --elf %t --emit-tbe=- | FileCheck %s --check-prefix=ORIGINAL -# RUN: llvm-elfabi --elf %t --emit-tbe=- --soname=libbest.so | FileCheck %s --check-prefix=REPLACED +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --output=- %t | FileCheck %s --check-prefix=ORIGINAL +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --soname=libbest.so --output=- %t | FileCheck %s --check-prefix=REPLACED !ELF FileHeader: diff --git a/test/tools/llvm-elfabi/binary-read-soname-no-null.test b/test/tools/llvm-elfabi/binary-read-soname-no-null.test index 4ffa44ce98b..3eb8ccdc41c 100644 --- a/test/tools/llvm-elfabi/binary-read-soname-no-null.test +++ b/test/tools/llvm-elfabi/binary-read-soname-no-null.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: not llvm-elfabi --elf %t --emit-tbe=%t.tbe 2>&1 | FileCheck %s +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=%t.tbe %t 2>&1 | FileCheck %s !ELF FileHeader: diff --git a/test/tools/llvm-elfabi/binary-read-soname.test b/test/tools/llvm-elfabi/binary-read-soname.test index 7436a381470..979bb21605b 100644 --- a/test/tools/llvm-elfabi/binary-read-soname.test +++ b/test/tools/llvm-elfabi/binary-read-soname.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: llvm-elfabi --elf %t --emit-tbe=- | FileCheck %s +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --output=- %t | FileCheck %s !ELF FileHeader: @@ -45,9 +45,9 @@ ProgramHeaders: FirstSec: .dynamic LastSec: .dynamic -# CHECK: --- !tapi-tbe +# CHECK: --- !ifs-v1 # CHECK-NEXT: TbeVersion: {{[1-9]\d*\.(0|([1-9]\d*))}} # CHECK-NEXT: SoName: somelib.so{{$}} -# CHECK-NEXT: Arch: x86_64 -# CHECK-NEXT: Symbols: {} +# CHECK-NEXT: Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, BitWidth: 64 } +# CHECK-NEXT: Symbols: [] # CHECK-NEXT: ... diff --git a/test/tools/llvm-elfabi/binary-read-syms-gnu-hash.test b/test/tools/llvm-elfabi/binary-read-syms-gnu-hash.test index 777f2714b28..73c39cfecbc 100644 --- a/test/tools/llvm-elfabi/binary-read-syms-gnu-hash.test +++ b/test/tools/llvm-elfabi/binary-read-syms-gnu-hash.test @@ -1,22 +1,22 @@ -# RUN: llvm-elfabi --elf %p/Inputs/gnu_hash.so --emit-tbe=- | FileCheck %s +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --output=- %p/Inputs/gnu_hash.so | FileCheck %s -# CHECK: --- !tapi-tbe +# CHECK: --- !ifs-v1 # CHECK-NEXT: TbeVersion: 1.0 # CHECK-NEXT: SoName: libsomething.so -# CHECK-NEXT: Arch: x86_64 +# CHECK-NEXT: Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, BitWidth: 64 } # CHECK-NEXT: NeededLibs: # CHECK-NEXT: - libm.so.6 # CHECK-NEXT: - libc.so.6 # CHECK-NEXT: - ld-linux-x86-64.so.2 # CHECK-NEXT: Symbols: -# CHECK-NEXT: AGlobalInteger: { Type: Object, Size: 4 } -# CHECK-NEXT: AThreadLocalLongInteger: { Type: TLS, Size: 8 } -# CHECK-NEXT: _ITM_deregisterTMCloneTable: { Type: NoType, Undefined: true, Weak: true } -# CHECK-NEXT: _ITM_registerTMCloneTable: { Type: NoType, Undefined: true, Weak: true } -# CHECK-NEXT: _Z11rotateArrayPii: { Type: Func } -# CHECK-NEXT: __cxa_finalize: { Type: Func, Undefined: true, Weak: true } -# CHECK-NEXT: __gmon_start__: { Type: NoType, Undefined: true, Weak: true } -# CHECK-NEXT: __tls_get_addr: { Type: Func, Undefined: true } -# CHECK-NEXT: _fini: { Type: Func } -# CHECK-NEXT: _init: { Type: Func } +# CHECK-NEXT: - { Name: __gmon_start__, Type: NoType, Undefined: true, Weak: true } +# CHECK-NEXT: - { Name: _ITM_deregisterTMCloneTable, Type: NoType, Undefined: true, Weak: true } +# CHECK-NEXT: - { Name: _ITM_registerTMCloneTable, Type: NoType, Undefined: true, Weak: true } +# CHECK-NEXT: - { Name: __cxa_finalize, Type: Func, Undefined: true, Weak: true } +# CHECK-NEXT: - { Name: __tls_get_addr, Type: Func, Undefined: true } +# CHECK-NEXT: - { Name: _init, Type: Func } +# CHECK-NEXT: - { Name: _fini, Type: Func } +# CHECK-NEXT: - { Name: AGlobalInteger, Type: Object, Size: 4 } +# CHECK-NEXT: - { Name: AThreadLocalLongInteger, Type: TLS, Size: 8 } +# CHECK-NEXT: - { Name: _Z11rotateArrayPii, Type: Func } # CHECK-NEXT: ... diff --git a/test/tools/llvm-elfabi/binary-read-syms-sysv-hash.test b/test/tools/llvm-elfabi/binary-read-syms-sysv-hash.test index 0f290852998..f9453552488 100644 --- a/test/tools/llvm-elfabi/binary-read-syms-sysv-hash.test +++ b/test/tools/llvm-elfabi/binary-read-syms-sysv-hash.test @@ -1,22 +1,22 @@ -# RUN: llvm-elfabi --elf %p/Inputs/sysv_hash.so --emit-tbe=- | FileCheck %s +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --output=- %p/Inputs/sysv_hash.so | FileCheck %s -# CHECK: --- !tapi-tbe +# CHECK: --- !ifs-v1 # CHECK-NEXT: TbeVersion: 1.0 # CHECK-NEXT: SoName: libsomething.so -# CHECK-NEXT: Arch: x86_64 +# CHECK-NEXT: Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, BitWidth: 64 } # CHECK-NEXT: NeededLibs: # CHECK-NEXT: - libm.so.6 # CHECK-NEXT: - libc.so.6 # CHECK-NEXT: - ld-linux-x86-64.so.2 # CHECK-NEXT: Symbols: -# CHECK-NEXT: AGlobalInteger: { Type: Object, Size: 4 } -# CHECK-NEXT: AThreadLocalLongInteger: { Type: TLS, Size: 8 } -# CHECK-NEXT: _ITM_deregisterTMCloneTable: { Type: NoType, Undefined: true, Weak: true } -# CHECK-NEXT: _ITM_registerTMCloneTable: { Type: NoType, Undefined: true, Weak: true } -# CHECK-NEXT: _Z11rotateArrayPii: { Type: Func } -# CHECK-NEXT: __cxa_finalize: { Type: Func, Undefined: true, Weak: true } -# CHECK-NEXT: __gmon_start__: { Type: NoType, Undefined: true, Weak: true } -# CHECK-NEXT: __tls_get_addr: { Type: Func, Undefined: true } -# CHECK-NEXT: _fini: { Type: Func } -# CHECK-NEXT: _init: { Type: Func } +# CHECK-NEXT: - { Name: __gmon_start__, Type: NoType, Undefined: true, Weak: true } +# CHECK-NEXT: - { Name: _init, Type: Func } +# CHECK-NEXT: - { Name: _fini, Type: Func } +# CHECK-NEXT: - { Name: _ITM_deregisterTMCloneTable, Type: NoType, Undefined: true, Weak: true } +# CHECK-NEXT: - { Name: _ITM_registerTMCloneTable, Type: NoType, Undefined: true, Weak: true } +# CHECK-NEXT: - { Name: __cxa_finalize, Type: Func, Undefined: true, Weak: true } +# CHECK-NEXT: - { Name: AGlobalInteger, Type: Object, Size: 4 } +# CHECK-NEXT: - { Name: AThreadLocalLongInteger, Type: TLS, Size: 8 } +# CHECK-NEXT: - { Name: _Z11rotateArrayPii, Type: Func } +# CHECK-NEXT: - { Name: __tls_get_addr, Type: Func, Undefined: true } # CHECK-NEXT: ... diff --git a/test/tools/llvm-elfabi/fail-file-open.test b/test/tools/llvm-elfabi/fail-file-open.test index b4019af9feb..0e4e75d9010 100644 --- a/test/tools/llvm-elfabi/fail-file-open.test +++ b/test/tools/llvm-elfabi/fail-file-open.test @@ -1,4 +1,4 @@ -# RUN: not llvm-elfabi %s.NotAFileInTestingDir --emit-tbe=%t 2>&1 | FileCheck %s +# RUN: not llvm-elfabi --output-format=TBE --output=%t.tbe %s.NotAFileInTestingDir 2>&1 | FileCheck %s This file will not be read. An invalid file path is fed to llvm-elfabi. diff --git a/test/tools/llvm-elfabi/fail-file-write-windows.test b/test/tools/llvm-elfabi/fail-file-write-windows.test index fb3a1a63884..c7efb5679f3 100644 --- a/test/tools/llvm-elfabi/fail-file-write-windows.test +++ b/test/tools/llvm-elfabi/fail-file-write-windows.test @@ -3,14 +3,14 @@ # REQUIRES: system-windows # RUN: touch %t.TestFile # RUN: chmod 400 %t.TestFile -# RUN: not llvm-elfabi %s --output-target=elf64-little %t.TestFile 2>&1 | FileCheck -DMSG=%errc_EACCES %s --check-prefix=ERR +# RUN: not llvm-elfabi --output-format=ELF --output=%t.TestFile %s 2>&1 | FileCheck -DMSG=%errc_EACCES %s --check-prefix=ERR # RUN: chmod 777 %t.TestFile # RUN: rm -rf %t.TestFile ---- !tapi-tbe +--- !ifs-v1 TbeVersion: 1.0 -Arch: AArch64 -Symbols: {} +Target: { ObjectFormat: ELF, Arch: AArch64, Endianness: little, BitWidth: 64 } +Symbols: [] ... # ERR: error: [[MSG]] diff --git a/test/tools/llvm-elfabi/fail-file-write.test b/test/tools/llvm-elfabi/fail-file-write.test index 928528d16c6..1ac9ef79297 100644 --- a/test/tools/llvm-elfabi/fail-file-write.test +++ b/test/tools/llvm-elfabi/fail-file-write.test @@ -5,14 +5,14 @@ # RUN: mkdir %t.TestDir # RUN: touch %t.TestDir/Output.TestFile # RUN: chmod 400 %t.TestDir -# RUN: not llvm-elfabi %s --output-target=elf64-little %t.TestDir/Output.TestFile 2>&1 | FileCheck -DMSG=%errc_EACCES %s --check-prefix=ERR +# RUN: not llvm-elfabi --output-format=ELF --output=%t.TestDir/Output.TestFile %s 2>&1 | FileCheck -DMSG=%errc_EACCES %s --check-prefix=ERR # RUN: chmod 777 %t.TestDir # RUN: rm -rf %t.TestDir ---- !tapi-tbe +--- !ifs-v1 TbeVersion: 1.0 -Arch: AArch64 -Symbols: {} +Target: { ObjectFormat: ELF, Arch: AArch64, Endianness: little, BitWidth: 64 } +Symbols: [] ... # ERR: [[MSG]] when trying to open `{{.*}}.TestDir/Output.TestFile` for writing diff --git a/test/tools/llvm-elfabi/output-target-error.test b/test/tools/llvm-elfabi/output-target-error.test index a0c4bec5451..b2726e61a8b 100644 --- a/test/tools/llvm-elfabi/output-target-error.test +++ b/test/tools/llvm-elfabi/output-target-error.test @@ -1,15 +1,15 @@ ## Test running llvm-elfabi without specifying a valid target. -# RUN: not llvm-elfabi %s %t 2>&1 | FileCheck %s --check-prefix=MISSING -# RUN: not llvm-elfabi %s --output-target=nope %t 2>&1 | FileCheck %s --check-prefix=INVALID +# RUN: not llvm-elfabi --output=%t %s 2>&1 | FileCheck %s --check-prefix=MISSING +# RUN: not llvm-elfabi --output-format=nope --output=%t %s 2>&1 | FileCheck %s --check-prefix=INVALID ---- !tapi-tbe +--- !ifs-v1 SoName: somelib.so TbeVersion: 1.0 -Arch: x86_64 -Symbols: {} +Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, BitWidth: 64 } +Symbols: [] ... -# MISSING: error: no binary output target specified. +# MISSING: llvm-elfabi: for the --output-format option: must be specified at least once! -# INVALID: llvm-elfabi: for the --output-target option: Cannot find option named 'nope'! +# INVALID: llvm-elfabi: for the --output-format option: Cannot find option named 'nope'! diff --git a/test/tools/llvm-elfabi/preserve-dates-stub.test b/test/tools/llvm-elfabi/preserve-dates-stub.test index 9742a61aa28..5c41a05ee2e 100644 --- a/test/tools/llvm-elfabi/preserve-dates-stub.test +++ b/test/tools/llvm-elfabi/preserve-dates-stub.test @@ -1,19 +1,19 @@ ## Test writing unchanged content to ELF Stub file with --write-if-changed flag. -# RUN: llvm-elfabi %s --output-target=elf64-little %t +# RUN: llvm-elfabi --output-format=ELF --output=%t %s # RUN: env TZ=GMT touch -m -t 197001010000 %t -# RUN: llvm-elfabi %s --output-target=elf64-little %t --write-if-changed +# RUN: llvm-elfabi --output-format=ELF --output=%t --write-if-changed %s # RUN: env TZ=GMT ls -l %t | FileCheck %s ---- !tapi-tbe +--- !ifs-v1 TbeVersion: 1.0 -Arch: x86_64 +Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, BitWidth: 64 } NeededLibs: - libc.so.6 Symbols: - bar: { Type: Object, Size: 42 } - baz: { Type: TLS, Size: 3 } - plus: { Type: Func } + - { Name: bar, Type: Object, Size: 42 } + - { Name: baz, Type: TLS, Size: 3 } + - { Name: plus, Type: Func } ... # CHECK: {{[[:space:]]1970}} diff --git a/test/tools/llvm-elfabi/preserve-dates-tbe.test b/test/tools/llvm-elfabi/preserve-dates-tbe.test index 3ec190067c7..e1edb6c9fc3 100644 --- a/test/tools/llvm-elfabi/preserve-dates-tbe.test +++ b/test/tools/llvm-elfabi/preserve-dates-tbe.test @@ -1,8 +1,8 @@ ## Test writing unchanged content to TBE file with --write-if-changed flag. -# RUN: llvm-elfabi --elf %p/Inputs/gnu_hash.so --emit-tbe=%t +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --output=%t %p/Inputs/gnu_hash.so # RUN: env TZ=GMT touch -m -t 197001010000 %t -# RUN: llvm-elfabi --elf %p/Inputs/gnu_hash.so --emit-tbe=%t --write-if-changed +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --output=%t --write-if-changed %p/Inputs/gnu_hash.so # RUN: env TZ=GMT ls -l %t | FileCheck %s # CHECK: {{[[:space:]]1970}} diff --git a/test/tools/llvm-elfabi/read-elf-dynsym.test b/test/tools/llvm-elfabi/read-elf-dynsym.test index 8c2fe2bf049..7de9b9317f3 100644 --- a/test/tools/llvm-elfabi/read-elf-dynsym.test +++ b/test/tools/llvm-elfabi/read-elf-dynsym.test @@ -5,26 +5,26 @@ ## Test if llvm-elfabi reads DT_SYMTAB size through section headers by puting the wrong terminator in DT_GNU_HASH. # RUN: yaml2obj %s -o %tfull -DGNUHASHVALUE="[0x9]" -DTAG1="DT_GNU_HASH" -DVAL1="0xC00" -# RUN: llvm-elfabi --elf %tfull --emit-tbe=- | FileCheck %s +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --output=- %tfull | FileCheck %s ## Test if llvm-elfabi fails to read DT_SYMTAB size through section headers when the value of sh_entsize is invalid. # RUN: yaml2obj %s -o %tfull -DGNUHASHVALUE="[0x9]" -DTAG1="DT_GNU_HASH" -DVAL1="0xC00" -DENTSIZE="0x19" -# RUN: not llvm-elfabi --elf %tfull --emit-tbe=- 2>&1 | FileCheck %s --check-prefix=BADENTSIZE +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=- %tfull 2>&1 | FileCheck %s --check-prefix=BADENTSIZE ## Test if llvm-elfabi reads DT_SYMTAB size through DT_GNU_HASH. # RUN: yaml2obj %s -o %tw.gnu.hash -DGNUHASHVALUE="[0x8, 0x9]" -DTAG1="DT_GNU_HASH" -DVAL1="0xC00" -DNOHEADER="true" -# RUN: llvm-elfabi --elf %tw.gnu.hash --emit-tbe=- | FileCheck %s +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --output=- %tw.gnu.hash | FileCheck %s ## Test if llvm-elfabi fails to read DT_SYMTAB size through DT_GNU_HASH when there is no terminator. # RUN: yaml2obj %s -o %tw.gnu.hash -DGNUHASHVALUE="[0x8, 0xA]" -DTAG1="DT_GNU_HASH" -DVAL1="0xC00" -DNOHEADER="true" -# RUN: not llvm-elfabi --elf %tw.gnu.hash --emit-tbe=- 2>&1 | FileCheck %s --check-prefix=NOTERMINATOR +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=- %tw.gnu.hash 2>&1 | FileCheck %s --check-prefix=NOTERMINATOR -# CHECK: --- !tapi-tbe +# CHECK: --- !ifs-v1 # CHECK-NEXT: TbeVersion: 1.0 -# CHECK-NEXT: Arch: AArch64 +# CHECK-NEXT: Target: { ObjectFormat: ELF, Arch: AArch64, Endianness: little, BitWidth: 64 } # CHECK-NEXT: Symbols: -# CHECK-NEXT: bar: { Type: Object, Size: 0, Undefined: true } -# CHECK-NEXT: foo: { Type: Func, Undefined: true } +# CHECK-NEXT: - { Name: foo, Type: Func, Undefined: true } +# CHECK-NEXT: - { Name: bar, Type: Object, Size: 0, Undefined: true } # CHECK-NEXT: ... # BADENTSIZE: SHT_DYNSYM section has sh_size (72) % sh_entsize (25) that is not 0 diff --git a/test/tools/llvm-elfabi/read-tbe-as-elf.test b/test/tools/llvm-elfabi/read-tbe-as-elf.test index eaddd38867a..ceae17699d9 100644 --- a/test/tools/llvm-elfabi/read-tbe-as-elf.test +++ b/test/tools/llvm-elfabi/read-tbe-as-elf.test @@ -1,15 +1,15 @@ -# RUN: not llvm-elfabi --elf %s --emit-tbe=%t 2>&1 | FileCheck %s +# RUN: not llvm-elfabi --input-format=ELF --output-format=TBE --output=%t %s 2>&1 | FileCheck %s ---- !tapi-tbe +--- !ifs-v1 SoName: somelib.so TbeVersion: 1.0 -Arch: x86_64 +Target: { ObjectFormat: ELF, Arch: AArch64, Endianness: little, BitWidth: 64 } Symbols: - foo: { Type: Func } - bar: { Type: Object, Size: 42 } - baz: { Type: Object, Size: 8 } - not: { Type: Object, Undefined: true, Size: 128 } - nor: { Type: Func, Undefined: true } + - { Name: foo, Type: Func } + - { Name: bar, Type: Object, Size: 42 } + - { Name: baz, Type: Object, Size: 8 } + - { Name: not, Type: Object, Undefined: true, Size: 128 } + - { Name: nor, Type: Func, Undefined: true } ... # CHECK: The file was not recognized as a valid object file diff --git a/test/tools/llvm-elfabi/read-tbe-as-tbe.test b/test/tools/llvm-elfabi/read-tbe-as-tbe.test index a5e2d44134e..154b6eebb6c 100644 --- a/test/tools/llvm-elfabi/read-tbe-as-tbe.test +++ b/test/tools/llvm-elfabi/read-tbe-as-tbe.test @@ -1,13 +1,13 @@ -# RUN: llvm-elfabi --tbe %s --emit-tbe=- | FileCheck %s +# RUN: llvm-elfabi --input-format=TBE --output-format=TBE --output=- %s | FileCheck %s ---- !tapi-tbe +--- !ifs-v1 TbeVersion: 1.0 -Arch: AArch64 -Symbols: {} +Target: { ObjectFormat: ELF, Arch: AArch64, Endianness: little, BitWidth: 64 } +Symbols: [] ... -# CHECK: --- !tapi-tbe +# CHECK: --- !ifs-v1 # CHECK-NEXT: TbeVersion: {{[1-9]\d*\.(0|([1-9]\d*))}} -# CHECK-NEXT: Arch: AArch64 -# CHECK-NEXT: Symbols: {} +# CHECK-NEXT: Target: { ObjectFormat: ELF, Arch: AArch64, Endianness: little, BitWidth: 64 } +# CHECK-NEXT: Symbols: [] # CHECK-NEXT: ... diff --git a/test/tools/llvm-elfabi/read-tbe-with-bad-bitwidth.test b/test/tools/llvm-elfabi/read-tbe-with-bad-bitwidth.test new file mode 100644 index 00000000000..1ca314436ba --- /dev/null +++ b/test/tools/llvm-elfabi/read-tbe-with-bad-bitwidth.test @@ -0,0 +1,17 @@ +## Test reading TBE file with bad bit width. + +# RUN: not llvm-elfabi --output-format=TBE --output=- %s 2>&1 | FileCheck %s + +--- !ifs-v1 +SoName: somelib.so +TbeVersion: 1.0 +Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, BitWidth: 65 } +Symbols: + - { Name: foo, Type: Func } + - { Name: bar, Type: Object, Size: 42 } + - { Name: baz, Type: Object, Size: 8 } + - { Name: not, Type: Object, Size: 128, Undefined: true } + - { Name: nor, Type: Func, Undefined: true } +... + +# CHECK: YAML:8:74: error: Unsupported bit width diff --git a/test/tools/llvm-elfabi/read-tbe-with-bad-endianness.test b/test/tools/llvm-elfabi/read-tbe-with-bad-endianness.test new file mode 100644 index 00000000000..5413855c5b4 --- /dev/null +++ b/test/tools/llvm-elfabi/read-tbe-with-bad-endianness.test @@ -0,0 +1,17 @@ +## Test reading TBE file with bad endianness. + +# RUN: not llvm-elfabi --output-format=TBE --output=- %s 2>&1 | FileCheck %s + +--- !ifs-v1 +SoName: somelib.so +TbeVersion: 1.0 +Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: lit, BitWidth: 64 } +Symbols: + - { Name: foo, Type: Func } + - { Name: bar, Type: Object, Size: 42 } + - { Name: baz, Type: Object, Size: 8 } + - { Name: not, Type: Object, Size: 128, Undefined: true } + - { Name: nor, Type: Func, Undefined: true } +... + +# CHECK: YAML:8:56: error: Unsupported endianness diff --git a/test/tools/llvm-elfabi/read-unsupported-file.test b/test/tools/llvm-elfabi/read-unsupported-file.test index 4ebe1bcc6d4..d84a47ae558 100644 --- a/test/tools/llvm-elfabi/read-unsupported-file.test +++ b/test/tools/llvm-elfabi/read-unsupported-file.test @@ -1,4 +1,4 @@ -# RUN: not llvm-elfabi %s --emit-tbe=%t 2>&1 | FileCheck %s +# RUN: not llvm-elfabi --output-format=TBE --output=- %s 2>&1| FileCheck %s This is just some text that cannot be read by llvm-elfabi. diff --git a/test/tools/llvm-elfabi/strip-target.test b/test/tools/llvm-elfabi/strip-target.test new file mode 100644 index 00000000000..f9da26a99e1 --- /dev/null +++ b/test/tools/llvm-elfabi/strip-target.test @@ -0,0 +1,27 @@ +## Test writing tbe with stripped target information. + +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --strip-ifs-target --output=- %p/Inputs/sysv_hash.so | FileCheck %s --check-prefix=NOTARGET +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --strip-ifs-arch --strip-ifs-endianness --strip-ifs-bitwidth --output=- %p/Inputs/sysv_hash.so | FileCheck %s --check-prefix=NOTARGET +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --strip-ifs-arch --output=- %p/Inputs/sysv_hash.so | FileCheck %s -DELFTARGET="ObjectFormat: ELF, Endianness: little, BitWidth: 64" --check-prefix=CHECK +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --strip-ifs-endianness --output=- %p/Inputs/sysv_hash.so | FileCheck %s -DELFTARGET="ObjectFormat: ELF, Arch: x86_64, BitWidth: 64" --check-prefix=CHECK +# RUN: llvm-elfabi --input-format=ELF --output-format=TBE --strip-ifs-bitwidth --output=- %p/Inputs/sysv_hash.so | FileCheck %s -DELFTARGET="ObjectFormat: ELF, Arch: x86_64, Endianness: little" --check-prefix=CHECK + + +# CHECK: --- !ifs-v1 +# CHECK-NEXT: TbeVersion: 1.0 +# CHECK-NEXT: SoName: libsomething.so +# CHECK-NEXT: Target: { [[ELFTARGET]] } +# CHECK-NEXT: NeededLibs: +# CHECK-NEXT: - libm.so.6 +# CHECK-NEXT: - libc.so.6 +# CHECK-NEXT: - ld-linux-x86-64.so.2 +# CHECK-NEXT: Symbols: + +# NOTARGET: --- !ifs-v1 +# NOTARGET-NEXT: TbeVersion: 1.0 +# NOTARGET-NEXT: SoName: libsomething.so +# NOTARGET-NEXT: NeededLibs: +# NOTARGET-NEXT: - libm.so.6 +# NOTARGET-NEXT: - libc.so.6 +# NOTARGET-NEXT: - ld-linux-x86-64.so.2 +# NOTARGET-NEXT: Symbols: diff --git a/test/tools/llvm-elfabi/tbe-emits-current-version.test b/test/tools/llvm-elfabi/tbe-emits-current-version.test index 12a5476175a..0799a14f4ef 100644 --- a/test/tools/llvm-elfabi/tbe-emits-current-version.test +++ b/test/tools/llvm-elfabi/tbe-emits-current-version.test @@ -1,13 +1,13 @@ -# RUN: llvm-elfabi %s --emit-tbe=- | FileCheck %s +# RUN: llvm-elfabi --output-format=TBE --output=- %s | FileCheck %s ---- !tapi-tbe +--- !ifs-v1 TbeVersion: 1.0 -Arch: AArch64 -Symbols: {} +Target: { ObjectFormat: ELF, Arch: AArch64, Endianness: little, BitWidth: 64 } +Symbols: [] ... # As the tbe reader/writer is updated, update this check to ensure --emit-tbe # uses the latest tbe writer by default. -# CHECK: --- !tapi-tbe +# CHECK: --- !ifs-v1 # CHECK-NEXT: TbeVersion: 1.0 diff --git a/test/tools/llvm-elfabi/tbe-read-basic.test b/test/tools/llvm-elfabi/tbe-read-basic.test index 1599f5a891e..a8e285c7eb6 100644 --- a/test/tools/llvm-elfabi/tbe-read-basic.test +++ b/test/tools/llvm-elfabi/tbe-read-basic.test @@ -1,25 +1,25 @@ -# RUN: llvm-elfabi %s --emit-tbe=- | FileCheck %s +# RUN: llvm-elfabi --output-format=TBE --output=- %s | FileCheck %s ---- !tapi-tbe +--- !ifs-v1 SoName: somelib.so TbeVersion: 1.0 -Arch: x86_64 +Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, BitWidth: 64 } Symbols: - foo: { Type: Func } - bar: { Type: Object, Size: 42 } - baz: { Type: Object, Size: 8 } - not: { Type: Object, Undefined: true, Size: 128 } - nor: { Type: Func, Undefined: true } + - { Name: foo, Type: Func } + - { Name: bar, Type: Object, Size: 42 } + - { Name: baz, Type: Object, Size: 8 } + - { Name: not, Type: Object, Size: 128, Undefined: true } + - { Name: nor, Type: Func, Undefined: true } ... -# CHECK: --- !tapi-tbe +# CHECK: --- !ifs-v1 # CHECK-NEXT: TbeVersion: {{[1-9]\d*\.(0|([1-9]\d*))}} # CHECK-NEXT: SoName: somelib.so -# CHECK-NEXT: Arch: x86_64 +# CHECK-NEXT: Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, BitWidth: 64 } # CHECK-NEXT: Symbols: -# CHECK-NEXT: bar: { Type: Object, Size: 42 } -# CHECK-NEXT: baz: { Type: Object, Size: 8 } -# CHECK-NEXT: foo: { Type: Func } -# CHECK-NEXT: nor: { Type: Func, Undefined: true } -# CHECK-NEXT: not: { Type: Object, Size: 128, Undefined: true } +# CHECK-NEXT: - { Name: foo, Type: Func } +# CHECK-NEXT: - { Name: bar, Type: Object, Size: 42 } +# CHECK-NEXT: - { Name: baz, Type: Object, Size: 8 } +# CHECK-NEXT: - { Name: not, Type: Object, Size: 128, Undefined: true } +# CHECK-NEXT: - { Name: nor, Type: Func, Undefined: true } # CHECK-NEXT: ... diff --git a/test/tools/llvm-elfabi/write-stub-no-nonlocal-symbol.test b/test/tools/llvm-elfabi/write-stub-no-nonlocal-symbol.test index 98dece0e37d..3f7531f2a0b 100644 --- a/test/tools/llvm-elfabi/write-stub-no-nonlocal-symbol.test +++ b/test/tools/llvm-elfabi/write-stub-no-nonlocal-symbol.test @@ -1,14 +1,14 @@ ## Test writing stub elf when symbol table contains no non-local symbol. -# RUN: llvm-elfabi %s --output-target=elf64-little %t +# RUN: llvm-elfabi --output-format=ELF --output=%t %s # RUN: llvm-readobj -S %t | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="LittleEndian (0x1)" -DHS=64 -DPHES=56 -DSHES=64 -DDYNSYMAL=8 -DDYNSYMES=24 -DDYNAMICAL=8 -DDYNAMICES=16 -DDYNTABZ=000000000 ---- !tapi-tbe +--- !ifs-v1 TbeVersion: 1.0 -Arch: x86_64 +Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, BitWidth: 64 } NeededLibs: - libc.so.6 -Symbols: {} +Symbols: [] ... # CHECK: Section { diff --git a/test/tools/llvm-elfabi/write-stub.test b/test/tools/llvm-elfabi/write-stub.test index 837c508b485..78e40f05be4 100644 --- a/test/tools/llvm-elfabi/write-stub.test +++ b/test/tools/llvm-elfabi/write-stub.test @@ -1,26 +1,44 @@ ## Test writing stub elf with minimal sections. -# RUN: llvm-elfabi %s --output-target=elf32-little %t.elf32l +# RUN: llvm-elfabi --output-format=ELF --output=%t.elf32l --arch=x86_64 --bitwidth=32 --endianness=little %s # RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf32l | FileCheck %s -DCLASS="32-bit (0x1)" -DDE="LittleEndian (0x1)" -DHS=52 -DPHES=32 -DSHES=40 -DDYNSYMAL=4 -DDYNSYMES=16 -DDYNAMICAL=4 -DDYNAMICES=8 -DDYNTABZ=0 -# RUN: llvm-elfabi %s --output-target=elf32-big %t.elf32b +# RUN: llvm-elfabi --output-format=ELF --output=%t.elf32b --arch=x86_64 --bitwidth=32 --endianness=big %s # RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf32b | FileCheck %s -DCLASS="32-bit (0x1)" -DDE="BigEndian (0x2)" -DHS=52 -DPHES=32 -DSHES=40 -DDYNSYMAL=4 -DDYNSYMES=16 -DDYNAMICAL=4 -DDYNAMICES=8 -DDYNTABZ=0 -# RUN: llvm-elfabi %s --output-target=elf64-little %t.elf64l +# RUN: llvm-elfabi --output-format=ELF --output=%t.elf64l --arch=x86_64 --bitwidth=64 --endianness=little %s # RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf64l | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="LittleEndian (0x1)" -DHS=64 -DPHES=56 -DSHES=64 -DDYNSYMAL=8 -DDYNSYMES=24 -DDYNAMICAL=8 -DDYNAMICES=16 -DDYNTABZ=000000000 -# RUN: llvm-elfabi %s --output-target=elf64-big %t.elf64b +# RUN: llvm-elfabi --output-format=ELF --output=%t.elf64l --target=x86_64-linux-gnu %s +# RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf64l | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="LittleEndian (0x1)" -DHS=64 -DPHES=56 -DSHES=64 -DDYNSYMAL=8 -DDYNSYMES=24 -DDYNAMICAL=8 -DDYNAMICES=16 -DDYNTABZ=000000000 + +# RUN: llvm-elfabi --output-format=ELF --output=%t.elf64b --arch=x86_64 --bitwidth=64 --endianness=big %s # RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf64b | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="BigEndian (0x2)" -DHS=64 -DPHES=56 -DSHES=64 -DDYNSYMAL=8 -DDYNSYMES=24 -DDYNAMICAL=8 -DDYNAMICES=16 -DDYNTABZ=000000000 ---- !tapi-tbe +# RUN: not llvm-elfabi --output-format=ELF --output=%t --arch=x86_64 --bitwidth=64 --endianness=big --target=x86_64-linux-gnu %s 2>&1 | FileCheck %s --check-prefix=TRIPLEERR + +# RUN: not llvm-elfabi --output-format=ELF --output=%t --bitwidth=64 --endianness=big %s 2>&1 | FileCheck %s -DMSG="Arch" --check-prefix=TARGETERR + +# RUN: not llvm-elfabi --output-format=ELF --output=%t --arch=x86_64 --endianness=big %s 2>&1 | FileCheck %s -DMSG="BitWidth" --check-prefix=TARGETERR + +# RUN: not llvm-elfabi --output-format=ELF --output=%t --arch=x86_64 --bitwidth=64 %s 2>&1 | FileCheck %s -DMSG="Endianness" --check-prefix=TARGETERR + +# RUN: llvm-elfabi --output-format=TBE --output=%t.target --target=x86_64-linux-gnu %s +# RUN: not llvm-elfabi --output-format=ELF --output=%t --target=aarch64-linux-gnu %t.target 2>&1 | FileCheck %s -DMSG="Triple" --check-prefix=CONFLICTERR + +# RUN: llvm-elfabi --output-format=TBE --output=%t.target --arch=x86_64 --endianness=little --bitwidth=64 %s +# RUN: not llvm-elfabi --output-format=ELF --output=%t --arch=AArch64 %t.target 2>&1 | FileCheck %s -DMSG=Arch --check-prefix=CONFLICTERR +# RUN: not llvm-elfabi --output-format=ELF --output=%t --endianness=big %t.target 2>&1 | FileCheck %s -DMSG=Endianness --check-prefix=CONFLICTERR +# RUN: not llvm-elfabi --output-format=ELF --output=%t --bitwidth=32 %t.target 2>&1 | FileCheck %s -DMSG=BitWidth --check-prefix=CONFLICTERR + +--- !ifs-v1 TbeVersion: 1.0 -Arch: x86_64 NeededLibs: - libc.so.6 Symbols: - bar: { Type: Object, Size: 42 } - baz: { Type: TLS, Size: 3 } - plus: { Type: Func } + - { Name: bar, Type: Object, Size: 42 } + - { Name: baz, Type: TLS, Size: 3 } + - { Name: plus, Type: Func } ... # CHECK: ElfHeader { @@ -175,3 +193,7 @@ Symbols: # CHECK-NEXT: [ 9] .dynsym # CHECK-NEXT: [ 11] .dynamic # CHECK-NEXT: [ 1a] .shstrtab + +# TRIPLEERR: error: Target triple cannot be used simultaneously with ELF target format +# TARGETERR: error: [[MSG]] is not defined in the text stub +# CONFLICTERR: error: Supplied [[MSG]] conflicts with the text stub \ No newline at end of file diff --git a/tools/llvm-elfabi/CMakeLists.txt b/tools/llvm-elfabi/CMakeLists.txt index 43b4b5b5faa..85eb3a4ed77 100644 --- a/tools/llvm-elfabi/CMakeLists.txt +++ b/tools/llvm-elfabi/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + BinaryFormat InterfaceStub Object Support diff --git a/tools/llvm-elfabi/llvm-elfabi.cpp b/tools/llvm-elfabi/llvm-elfabi.cpp index 761c6a80b34..b94d075177c 100644 --- a/tools/llvm-elfabi/llvm-elfabi.cpp +++ b/tools/llvm-elfabi/llvm-elfabi.cpp @@ -30,33 +30,50 @@ using namespace llvm; using namespace llvm::elfabi; // Command line flags: -cl::opt InputFileFormat( - cl::desc("Force input file format:"), - cl::values(clEnumValN(FileFormat::TBE, "tbe", - "Read `input` as text-based ELF stub"), - clEnumValN(FileFormat::ELF, "elf", - "Read `input` as ELF binary"))); cl::opt InputFilePath(cl::Positional, cl::desc("input"), cl::Required); -cl::opt - EmitTBE("emit-tbe", - cl::desc("Emit a text-based ELF stub (.tbe) from the input file"), - cl::value_desc("path")); +cl::opt InputFormat( + "input-format", cl::desc("Specify the input file format"), + cl::values(clEnumValN(FileFormat::TBE, "TBE", "Text based ELF stub file"), + clEnumValN(FileFormat::ELF, "ELF", "ELF object file"))); +cl::opt OutputFormat( + "output-format", cl::desc("Specify the output file format"), + cl::values(clEnumValN(FileFormat::TBE, "TBE", "Text based ELF stub file"), + clEnumValN(FileFormat::ELF, "ELF", "ELF stub file")), + cl::Required); +cl::opt OptArch("arch", + cl::desc("Specify the architecture, e.g. x86_64")); +cl::opt OptBitWidth( + "bitwidth", cl::desc("Specify the bit width"), + cl::values(clEnumValN(ELFBitWidthType::ELF32, "32", "32 bits"), + clEnumValN(ELFBitWidthType::ELF64, "64", "64 bits"))); +cl::opt OptEndianness( + "endianness", cl::desc("Specify the endianness"), + cl::values(clEnumValN(ELFEndiannessType::Little, "little", "Little Endian"), + clEnumValN(ELFEndiannessType::Big, "big", "Big Endian"))); +cl::opt OptTargetTriple( + "target", cl::desc("Specify the target triple, e.g. x86_64-linux-gnu")); +cl::opt OptTargetTripleHint( + "hint-ifs-target", + cl::desc("When --output-format is 'TBE', this flag will hint the expected " + "target triple for IFS output")); +cl::opt StripIFSArch( + "strip-ifs-arch", + cl::desc("Strip target architecture information away from IFS output")); +cl::opt StripIFSBitWidth( + "strip-ifs-bitwidth", + cl::desc("Strip target bit width information away from IFS output")); +cl::opt StripIFSEndiannessWidth( + "strip-ifs-endianness", + cl::desc("Strip target endianness information away from IFS output")); +cl::opt StripIFSTarget( + "strip-ifs-target", + cl::desc("Strip all target information away from IFS output")); cl::opt SOName("soname", cl::desc("Manually set the DT_SONAME entry of any emitted files"), cl::value_desc("name")); -cl::opt BinaryOutputTarget( - "output-target", cl::desc("Create a binary stub for the specified target"), - cl::values(clEnumValN(ELFTarget::ELF32LE, "elf32-little", - "32-bit little-endian ELF stub"), - clEnumValN(ELFTarget::ELF32BE, "elf32-big", - "32-bit big-endian ELF stub"), - clEnumValN(ELFTarget::ELF64LE, "elf64-little", - "64-bit little-endian ELF stub"), - clEnumValN(ELFTarget::ELF64BE, "elf64-big", - "64-bit big-endian ELF stub"))); -cl::opt BinaryOutputFilePath(cl::Positional, cl::desc("output")); +cl::opt OutputFilePath("output", cl::desc("Output file")); cl::opt WriteIfChanged( "write-if-changed", cl::desc("Write the output file only if it is new or has changed.")); @@ -106,8 +123,7 @@ static Expected> readInputFile(StringRef FilePath) { ErrorCollector EC(/*UseFatalErrors=*/false); // First try to read as a binary (fails fast if not binary). - if (InputFileFormat.getNumOccurrences() == 0 || - InputFileFormat == FileFormat::ELF) { + if (InputFormat.getNumOccurrences() == 0 || InputFormat == FileFormat::ELF) { Expected> StubFromELF = readELFFile(FileReadBuffer->getMemBufferRef()); if (StubFromELF) { @@ -117,8 +133,7 @@ static Expected> readInputFile(StringRef FilePath) { } // Fall back to reading as a tbe. - if (InputFileFormat.getNumOccurrences() == 0 || - InputFileFormat == FileFormat::TBE) { + if (InputFormat.getNumOccurrences() == 0 || InputFormat == FileFormat::TBE) { Expected> StubFromTBE = readTBEFromBuffer(FileReadBuffer->getBuffer()); if (StubFromTBE) { @@ -145,7 +160,6 @@ static void fatalError(Error Err) { int main(int argc, char *argv[]) { // Parse arguments. cl::ParseCommandLineOptions(argc, argv); - Expected> StubOrErr = readInputFile(InputFilePath); if (!StubOrErr) fatalError(StubOrErr.takeError()); @@ -155,22 +169,65 @@ int main(int argc, char *argv[]) { // Change SoName before emitting stubs. if (SOName.getNumOccurrences() == 1) TargetStub->SoName = SOName; - - if (EmitTBE.getNumOccurrences() == 1) { + Optional OverrideArch; + Optional OverrideEndianness; + Optional OverrideBitWidth; + Optional OverrideTriple; + if (OptArch.getNumOccurrences() == 1) { + OverrideArch = ELF::convertArchNameToEMachine(OptArch.getValue()); + } + if (OptEndianness.getNumOccurrences() == 1) + OverrideEndianness = OptEndianness.getValue(); + if (OptBitWidth.getNumOccurrences() == 1) + OverrideBitWidth = OptBitWidth.getValue(); + if (OptTargetTriple.getNumOccurrences() == 1) + OverrideTriple = OptTargetTriple.getValue(); + Error OverrideError = + overrideTBETarget(*TargetStub, OverrideArch, OverrideEndianness, + OverrideBitWidth, OverrideTriple); + if (OverrideError) + fatalError(std::move(OverrideError)); + switch (OutputFormat.getValue()) { + case FileFormat::TBE: { TargetStub->TbeVersion = TBEVersionCurrent; - Error TBEWriteError = writeTBE(EmitTBE, *TargetStub); + if (InputFormat.getValue() == FileFormat::ELF && + OptTargetTripleHint.getNumOccurrences() == 1) { + std::error_code HintEC(1, std::generic_category()); + IFSTarget HintTarget = parseTriple(OptTargetTripleHint); + if (TargetStub->Target.Arch.getValue() != HintTarget.Arch.getValue()) { + fatalError(make_error( + "Triple hint does not match the actual architecture", HintEC)); + } + if (TargetStub->Target.Endianness.getValue() != + HintTarget.Endianness.getValue()) { + fatalError(make_error( + "Triple hint does not match the actual endianness", HintEC)); + } + if (TargetStub->Target.BitWidth.getValue() != + HintTarget.BitWidth.getValue()) { + fatalError(make_error( + "Triple hint does not match the actual bit width", HintEC)); + } + stripTBETarget(*TargetStub, true, false, false, false); + TargetStub->Target.Triple = OptTargetTripleHint.getValue(); + } else { + stripTBETarget(*TargetStub, StripIFSTarget, StripIFSArch, + StripIFSEndiannessWidth, StripIFSBitWidth); + } + Error TBEWriteError = writeTBE(OutputFilePath.getValue(), *TargetStub); if (TBEWriteError) fatalError(std::move(TBEWriteError)); + break; } - - // Write out binary ELF stub. - if (BinaryOutputFilePath.getNumOccurrences() == 1) { - if (BinaryOutputTarget.getNumOccurrences() == 0) - fatalError(createStringError(errc::not_supported, - "no binary output target specified.")); - Error BinaryWriteError = writeBinaryStub( - BinaryOutputFilePath, *TargetStub, BinaryOutputTarget, WriteIfChanged); + case FileFormat::ELF: { + Error TargetError = validateTBETarget(*TargetStub, true); + if (TargetError) + fatalError(std::move(TargetError)); + Error BinaryWriteError = + writeBinaryStub(OutputFilePath, *TargetStub, WriteIfChanged); if (BinaryWriteError) fatalError(std::move(BinaryWriteError)); + break; + } } } diff --git a/tools/llvm-ifs/CMakeLists.txt b/tools/llvm-ifs/CMakeLists.txt index 456f88d2b76..373ef2ba2c2 100644 --- a/tools/llvm-ifs/CMakeLists.txt +++ b/tools/llvm-ifs/CMakeLists.txt @@ -1,5 +1,5 @@ set(LLVM_LINK_COMPONENTS - InterfaceStub + InterfaceStub Object Support TextAPI diff --git a/tools/llvm-ifs/llvm-ifs.cpp b/tools/llvm-ifs/llvm-ifs.cpp index b6a1b4a9512..8ab5ef9101f 100644 --- a/tools/llvm-ifs/llvm-ifs.cpp +++ b/tools/llvm-ifs/llvm-ifs.cpp @@ -10,6 +10,8 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/InterfaceStub/ELFObjHandler.h" +#include "llvm/InterfaceStub/ELFStub.h" +#include "llvm/InterfaceStub/TBEHandler.h" #include "llvm/ObjectYAML/yaml2obj.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -348,23 +350,10 @@ static int writeElfStub(const Triple &T, const std::vector &Symbols, return convertYAML(YIn, Out, ErrHandler) ? 0 : 1; } -static elfabi::ELFTarget convertIFSStub(const IFSStub &IfsStub, - elfabi::ELFStub &ElfStub) { +static Error convertIFSStub(const IFSStub &IfsStub, elfabi::ELFStub &ElfStub) { ElfStub.TbeVersion = IfsStub.IfsVersion; ElfStub.SoName = IfsStub.SOName; - // TODO: Support more archs and targets. - Triple IFSTriple(IfsStub.Triple); - elfabi::ELFTarget Target = elfabi::ELFTarget::ELF64LE; - switch (IFSTriple.getArch()) { - case Triple::ArchType::aarch64: - ElfStub.Arch = (elfabi::ELFArch)ELF::EM_AARCH64; - break; - case Triple::ArchType::x86_64: - ElfStub.Arch = (elfabi::ELFArch)ELF::EM_X86_64; - break; - default: - ElfStub.Arch = (elfabi::ELFArch)ELF::EM_NONE; - } + ElfStub.Target.Triple = IfsStub.Triple; ElfStub.NeededLibs = IfsStub.NeededLibs; for (const IFSSymbol &IfsSymbol : IfsStub.Symbols) { elfabi::ELFSymbol ElfSymbol(IfsSymbol.Name); @@ -387,9 +376,9 @@ static elfabi::ELFTarget convertIFSStub(const IFSStub &IfsStub, ElfSymbol.Undefined = false; ElfSymbol.Weak = IfsSymbol.Weak; ElfSymbol.Warning = IfsSymbol.Warning; - ElfStub.Symbols.insert(ElfSymbol); + ElfStub.Symbols.push_back(ElfSymbol); } - return Target; + return llvm::elfabi::validateTBETarget(ElfStub, true); } static int writeIfso(const IFSStub &Stub, bool IsWriteIfs) { @@ -400,9 +389,11 @@ static int writeIfso(const IFSStub &Stub, bool IsWriteIfs) { // format is ELF. if (UseInterfaceStub && (!IsWriteIfs) && ObjectFileFormat != "TBD") { elfabi::ELFStub ElfStub; - elfabi::ELFTarget Target = convertIFSStub(Stub, ElfStub); - Error BinaryWriteError = - elfabi::writeBinaryStub(OutputFilename, ElfStub, Target); + Error ConvertError = convertIFSStub(Stub, ElfStub); + if (ConvertError) { + return -1; + } + Error BinaryWriteError = elfabi::writeBinaryStub(OutputFilename, ElfStub); if (BinaryWriteError) { return -1; } diff --git a/unittests/InterfaceStub/ELFYAMLTest.cpp b/unittests/InterfaceStub/ELFYAMLTest.cpp index aa048839d3b..e438f841eb9 100644 --- a/unittests/InterfaceStub/ELFYAMLTest.cpp +++ b/unittests/InterfaceStub/ELFYAMLTest.cpp @@ -34,19 +34,21 @@ void compareByLine(StringRef LHS, StringRef RHS) { } TEST(ElfYamlTextAPI, YAMLReadableTBE) { - const char Data[] = "--- !tapi-tbe\n" + const char Data[] = "--- !ifs-v1\n" "TbeVersion: 1.0\n" - "Arch: x86_64\n" + "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: " + "little, BitWidth: 64 }\n" "NeededLibs: [libc.so, libfoo.so, libbar.so]\n" "Symbols:\n" - " foo: { Type: Func, Undefined: true }\n" + " - { Name: foo, Type: Func, Undefined: true }\n" "...\n"; Expected> StubOrErr = readTBEFromBuffer(Data); ASSERT_THAT_ERROR(StubOrErr.takeError(), Succeeded()); std::unique_ptr Stub = std::move(StubOrErr.get()); EXPECT_NE(Stub.get(), nullptr); EXPECT_FALSE(Stub->SoName.hasValue()); - EXPECT_EQ(Stub->Arch, (uint16_t)llvm::ELF::EM_X86_64); + EXPECT_TRUE(Stub->Target.Arch.hasValue()); + EXPECT_EQ(Stub->Target.Arch.getValue(), (uint16_t)llvm::ELF::EM_X86_64); EXPECT_EQ(Stub->NeededLibs.size(), 3u); EXPECT_STREQ(Stub->NeededLibs[0].c_str(), "libc.so"); EXPECT_STREQ(Stub->NeededLibs[1].c_str(), "libfoo.so"); @@ -54,18 +56,20 @@ TEST(ElfYamlTextAPI, YAMLReadableTBE) { } TEST(ElfYamlTextAPI, YAMLReadsTBESymbols) { - const char Data[] = "--- !tapi-tbe\n" - "TbeVersion: 1.0\n" - "SoName: test.so\n" - "Arch: x86_64\n" - "Symbols:\n" - " bar: { Type: Object, Size: 42 }\n" - " baz: { Type: TLS, Size: 3 }\n" - " foo: { Type: Func, Warning: \"Deprecated!\" }\n" - " nor: { Type: NoType, Undefined: true }\n" - " not: { Type: File, Undefined: true, Size: 111, " - "Weak: true, Warning: \'All fields populated!\' }\n" - "...\n"; + const char Data[] = + "--- !ifs-v1\n" + "TbeVersion: 1.0\n" + "SoName: test.so\n" + "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, " + "BitWidth: 64 }\n" + "Symbols:\n" + " - { Name: bar, Type: Object, Size: 42 }\n" + " - { Name: baz, Type: TLS, Size: 3 }\n" + " - { Name: foo, Type: Func, Warning: \"Deprecated!\" }\n" + " - { Name: nor, Type: NoType, Undefined: true }\n" + " - { Name: not, Type: File, Undefined: true, Size: 111, " + "Weak: true, Warning: \'All fields populated!\' }\n" + "...\n"; Expected> StubOrErr = readTBEFromBuffer(Data); ASSERT_THAT_ERROR(StubOrErr.takeError(), Succeeded()); std::unique_ptr Stub = std::move(StubOrErr.get()); @@ -119,11 +123,12 @@ TEST(ElfYamlTextAPI, YAMLReadsTBESymbols) { } TEST(ElfYamlTextAPI, YAMLReadsNoTBESyms) { - const char Data[] = "--- !tapi-tbe\n" + const char Data[] = "--- !ifs-v1\n" "TbeVersion: 1.0\n" "SoName: test.so\n" - "Arch: x86_64\n" - "Symbols: {}\n" + "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: " + "little, BitWidth: 64 }\n" + "Symbols: []\n" "...\n"; Expected> StubOrErr = readTBEFromBuffer(Data); ASSERT_THAT_ERROR(StubOrErr.takeError(), Succeeded()); @@ -137,7 +142,8 @@ TEST(ElfYamlTextAPI, YAMLUnreadableTBE) { const char Data[] = "--- !tapi-tbz\n" "TbeVersion: z.3\n" "SoName: test.so\n" - "Arch: x86_64\n" + "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: " + "little, BitWidth: 64 }\n" "Symbols:\n" " foo: { Type: Func, Undefined: true }\n"; Expected> StubOrErr = readTBEFromBuffer(Data); @@ -145,11 +151,12 @@ TEST(ElfYamlTextAPI, YAMLUnreadableTBE) { } TEST(ElfYamlTextAPI, YAMLUnsupportedVersion) { - const char Data[] = "--- !tapi-tbe\n" + const char Data[] = "--- !ifs-v1\n" "TbeVersion: 9.9.9\n" "SoName: test.so\n" - "Arch: x86_64\n" - "Symbols: {}\n" + "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: " + "little, BitWidth: 64 }\n" + "Symbols: []\n" "...\n"; Expected> StubOrErr = readTBEFromBuffer(Data); std::string ErrorMessage = toString(StubOrErr.takeError()); @@ -158,18 +165,28 @@ TEST(ElfYamlTextAPI, YAMLUnsupportedVersion) { TEST(ElfYamlTextAPI, YAMLWritesTBESymbols) { const char Expected[] = - "--- !tapi-tbe\n" + "--- !ifs-v1\n" "TbeVersion: 1.0\n" - "Arch: AArch64\n" + "Target: { ObjectFormat: ELF, Arch: AArch64, Endianness: " + "little, BitWidth: 64 }\n" "Symbols:\n" - " bar: { Type: Func, Weak: true }\n" - " foo: { Type: NoType, Size: 99, Warning: Does nothing }\n" - " nor: { Type: Func, Undefined: true }\n" - " not: { Type: Unknown, Size: 12345678901234 }\n" + " - { Name: bar, Type: Func, Weak: true }\n" + " - { Name: foo, Type: NoType, Size: 99, Warning: Does nothing }\n" + " - { Name: nor, Type: Func, Undefined: true }\n" + " - { Name: not, Type: Unknown, Size: 12345678901234 }\n" "...\n"; ELFStub Stub; Stub.TbeVersion = VersionTuple(1, 0); - Stub.Arch = ELF::EM_AARCH64; + Stub.Target.Arch = ELF::EM_AARCH64; + Stub.Target.BitWidth = ELFBitWidthType::ELF64; + Stub.Target.Endianness = ELFEndiannessType::Little; + Stub.Target.ObjectFormat = "ELF"; + + ELFSymbol SymBar("bar"); + SymBar.Size = 128u; + SymBar.Type = ELFSymbolType::Func; + SymBar.Undefined = false; + SymBar.Weak = true; ELFSymbol SymFoo("foo"); SymFoo.Size = 99u; @@ -178,12 +195,6 @@ TEST(ElfYamlTextAPI, YAMLWritesTBESymbols) { SymFoo.Weak = false; SymFoo.Warning = "Does nothing"; - ELFSymbol SymBar("bar"); - SymBar.Size = 128u; - SymBar.Type = ELFSymbolType::Func; - SymBar.Undefined = false; - SymBar.Weak = true; - ELFSymbol SymNor("nor"); SymNor.Size = 1234u; SymNor.Type = ELFSymbolType::Func; @@ -196,11 +207,11 @@ TEST(ElfYamlTextAPI, YAMLWritesTBESymbols) { SymNot.Undefined = false; SymNot.Weak = false; - // Deliberately not in order to check that result is sorted. - Stub.Symbols.insert(SymNot); - Stub.Symbols.insert(SymBar); - Stub.Symbols.insert(SymFoo); - Stub.Symbols.insert(SymNor); + // Symbol order is preserved instead of being sorted. + Stub.Symbols.push_back(SymBar); + Stub.Symbols.push_back(SymFoo); + Stub.Symbols.push_back(SymNor); + Stub.Symbols.push_back(SymNot); // Ensure move constructor works as expected. ELFStub Moved = std::move(Stub); @@ -213,20 +224,24 @@ TEST(ElfYamlTextAPI, YAMLWritesTBESymbols) { } TEST(ElfYamlTextAPI, YAMLWritesNoTBESyms) { - const char Expected[] = "--- !tapi-tbe\n" + const char Expected[] = "--- !ifs-v1\n" "TbeVersion: 1.0\n" "SoName: nosyms.so\n" - "Arch: x86_64\n" + "Target: { ObjectFormat: ELF, Arch: x86_64, " + "Endianness: little, BitWidth: 64 }\n" "NeededLibs:\n" " - libc.so\n" " - libfoo.so\n" " - libbar.so\n" - "Symbols: {}\n" + "Symbols: []\n" "...\n"; ELFStub Stub; Stub.TbeVersion = VersionTuple(1, 0); Stub.SoName = "nosyms.so"; - Stub.Arch = ELF::EM_X86_64; + Stub.Target.Arch = ELF::EM_X86_64; + Stub.Target.BitWidth = ELFBitWidthType::ELF64; + Stub.Target.Endianness = ELFEndiannessType::Little; + Stub.Target.ObjectFormat = "ELF"; Stub.NeededLibs.push_back("libc.so"); Stub.NeededLibs.push_back("libfoo.so"); Stub.NeededLibs.push_back("libbar.so");