|  | //===-- llvm/BinaryFormat/XCOFF.cpp - The XCOFF file 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/XCOFF.h" | 
|  | #include "llvm/ADT/SmallString.h" | 
|  | #include "llvm/ADT/StringRef.h" | 
|  | #include "llvm/ADT/StringSwitch.h" | 
|  | #include "llvm/Support/Errc.h" | 
|  | #include "llvm/Support/Error.h" | 
|  | #include "llvm/TargetParser/PPCTargetParser.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define SMC_CASE(A)                                                            \ | 
|  | case XCOFF::XMC_##A:                                                         \ | 
|  | return #A; | 
|  | StringRef XCOFF::getMappingClassString(XCOFF::StorageMappingClass SMC) { | 
|  | switch (SMC) { | 
|  | SMC_CASE(PR) | 
|  | SMC_CASE(RO) | 
|  | SMC_CASE(DB) | 
|  | SMC_CASE(GL) | 
|  | SMC_CASE(XO) | 
|  | SMC_CASE(SV) | 
|  | SMC_CASE(SV64) | 
|  | SMC_CASE(SV3264) | 
|  | SMC_CASE(TI) | 
|  | SMC_CASE(TB) | 
|  | SMC_CASE(RW) | 
|  | SMC_CASE(TC0) | 
|  | SMC_CASE(TC) | 
|  | SMC_CASE(TD) | 
|  | SMC_CASE(DS) | 
|  | SMC_CASE(UA) | 
|  | SMC_CASE(BS) | 
|  | SMC_CASE(UC) | 
|  | SMC_CASE(TL) | 
|  | SMC_CASE(UL) | 
|  | SMC_CASE(TE) | 
|  | #undef SMC_CASE | 
|  | } | 
|  |  | 
|  | // TODO: need to add a test case for "Unknown" and other SMC. | 
|  | return "Unknown"; | 
|  | } | 
|  |  | 
|  | #define RELOC_CASE(A)                                                          \ | 
|  | case XCOFF::A:                                                               \ | 
|  | return #A; | 
|  | StringRef XCOFF::getRelocationTypeString(XCOFF::RelocationType Type) { | 
|  | switch (Type) { | 
|  | RELOC_CASE(R_POS) | 
|  | RELOC_CASE(R_RL) | 
|  | RELOC_CASE(R_RLA) | 
|  | RELOC_CASE(R_NEG) | 
|  | RELOC_CASE(R_REL) | 
|  | RELOC_CASE(R_TOC) | 
|  | RELOC_CASE(R_TRL) | 
|  | RELOC_CASE(R_TRLA) | 
|  | RELOC_CASE(R_GL) | 
|  | RELOC_CASE(R_TCL) | 
|  | RELOC_CASE(R_REF) | 
|  | RELOC_CASE(R_BA) | 
|  | RELOC_CASE(R_BR) | 
|  | RELOC_CASE(R_RBA) | 
|  | RELOC_CASE(R_RBR) | 
|  | RELOC_CASE(R_TLS) | 
|  | RELOC_CASE(R_TLS_IE) | 
|  | RELOC_CASE(R_TLS_LD) | 
|  | RELOC_CASE(R_TLS_LE) | 
|  | RELOC_CASE(R_TLSM) | 
|  | RELOC_CASE(R_TLSML) | 
|  | RELOC_CASE(R_TOCU) | 
|  | RELOC_CASE(R_TOCL) | 
|  | } | 
|  | return "Unknown"; | 
|  | } | 
|  | #undef RELOC_CASE | 
|  |  | 
|  | #define LANG_CASE(A)                                                           \ | 
|  | case XCOFF::TracebackTable::A:                                               \ | 
|  | return #A; | 
|  |  | 
|  | StringRef XCOFF::getNameForTracebackTableLanguageId( | 
|  | XCOFF::TracebackTable::LanguageID LangId) { | 
|  | switch (LangId) { | 
|  | LANG_CASE(C) | 
|  | LANG_CASE(Fortran) | 
|  | LANG_CASE(Pascal) | 
|  | LANG_CASE(Ada) | 
|  | LANG_CASE(PL1) | 
|  | LANG_CASE(Basic) | 
|  | LANG_CASE(Lisp) | 
|  | LANG_CASE(Cobol) | 
|  | LANG_CASE(Modula2) | 
|  | LANG_CASE(Rpg) | 
|  | LANG_CASE(PL8) | 
|  | LANG_CASE(Assembly) | 
|  | LANG_CASE(Java) | 
|  | LANG_CASE(ObjectiveC) | 
|  | LANG_CASE(CPlusPlus) | 
|  | } | 
|  | return "Unknown"; | 
|  | } | 
|  | #undef LANG_CASE | 
|  |  | 
|  | XCOFF::CFileCpuId XCOFF::getCpuID(StringRef CPUName) { | 
|  | StringRef CPU = PPC::normalizeCPUName(CPUName); | 
|  | return StringSwitch<XCOFF::CFileCpuId>(CPU) | 
|  | .Cases("generic", "COM", XCOFF::TCPU_COM) | 
|  | .Case("601", XCOFF::TCPU_601) | 
|  | .Cases("602", "603", "603e", "603ev", XCOFF::TCPU_603) | 
|  | .Cases("604", "604e", XCOFF::TCPU_604) | 
|  | .Case("620", XCOFF::TCPU_620) | 
|  | .Case("970", XCOFF::TCPU_970) | 
|  | .Cases("a2", "g3", "g4", "g5", "e500", XCOFF::TCPU_COM) | 
|  | .Cases("pwr3", "pwr4", XCOFF::TCPU_COM) | 
|  | .Cases("pwr5", "PWR5", XCOFF::TCPU_PWR5) | 
|  | .Cases("pwr5x", "PWR5X", XCOFF::TCPU_PWR5X) | 
|  | .Cases("pwr6", "PWR6", XCOFF::TCPU_PWR6) | 
|  | .Cases("pwr6x", "PWR6E", XCOFF::TCPU_PWR6E) | 
|  | .Cases("pwr7", "PWR7", XCOFF::TCPU_PWR7) | 
|  | .Cases("pwr8", "PWR8", XCOFF::TCPU_PWR8) | 
|  | .Cases("pwr9", "PWR9", XCOFF::TCPU_PWR9) | 
|  | .Cases("pwr10", "PWR10", XCOFF::TCPU_PWR10) | 
|  | .Cases("ppc", "PPC", "ppc32", "ppc64", XCOFF::TCPU_COM) | 
|  | .Case("ppc64le", XCOFF::TCPU_PWR8) | 
|  | .Case("future", XCOFF::TCPU_PWR10) | 
|  | .Cases("any", "ANY", XCOFF::TCPU_ANY) | 
|  | .Default(XCOFF::TCPU_INVALID); | 
|  | } | 
|  |  | 
|  | #define TCPU_CASE(A)                                                           \ | 
|  | case XCOFF::TCPU_##A:                                                        \ | 
|  | return #A; | 
|  | StringRef XCOFF::getTCPUString(XCOFF::CFileCpuId TCPU) { | 
|  | switch (TCPU) { | 
|  | TCPU_CASE(INVALID) | 
|  | TCPU_CASE(PPC) | 
|  | TCPU_CASE(PPC64) | 
|  | TCPU_CASE(COM) | 
|  | TCPU_CASE(PWR) | 
|  | TCPU_CASE(ANY) | 
|  | TCPU_CASE(601) | 
|  | TCPU_CASE(603) | 
|  | TCPU_CASE(604) | 
|  | TCPU_CASE(620) | 
|  | TCPU_CASE(A35) | 
|  | TCPU_CASE(PWR5) | 
|  | TCPU_CASE(970) | 
|  | TCPU_CASE(PWR6) | 
|  | TCPU_CASE(PWR5X) | 
|  | TCPU_CASE(PWR6E) | 
|  | TCPU_CASE(PWR7) | 
|  | TCPU_CASE(PWR8) | 
|  | TCPU_CASE(PWR9) | 
|  | TCPU_CASE(PWR10) | 
|  | TCPU_CASE(PWRX) | 
|  | } | 
|  | return "INVALID"; | 
|  | } | 
|  | #undef TCPU_CASE | 
|  |  | 
|  | Expected<SmallString<32>> XCOFF::parseParmsType(uint32_t Value, | 
|  | unsigned FixedParmsNum, | 
|  | unsigned FloatingParmsNum) { | 
|  | SmallString<32> ParmsType; | 
|  | int Bits = 0; | 
|  | unsigned ParsedFixedNum = 0; | 
|  | unsigned ParsedFloatingNum = 0; | 
|  | unsigned ParsedNum = 0; | 
|  | unsigned ParmsNum = FixedParmsNum + FloatingParmsNum; | 
|  |  | 
|  | // In the function PPCFunctionInfo::getParmsType(), when there are no vector | 
|  | // parameters, the 31st bit of ParmsType is always zero even if it indicates a | 
|  | // floating point parameter. The parameter type information is lost. There | 
|  | // are only 8 GPRs used for parameters passing, the floating parameters | 
|  | // also occupy GPRs if there are available, so the 31st bit can never be a | 
|  | // fixed parameter. At the same time, we also do not know whether the zero of | 
|  | // the 31st bit indicates a float or double parameter type here. Therefore, we | 
|  | // ignore the 31st bit. | 
|  | while (Bits < 31 && ParsedNum < ParmsNum) { | 
|  | if (++ParsedNum > 1) | 
|  | ParmsType += ", "; | 
|  | if ((Value & TracebackTable::ParmTypeIsFloatingBit) == 0) { | 
|  | // Fixed parameter type. | 
|  | ParmsType += "i"; | 
|  | ++ParsedFixedNum; | 
|  | Value <<= 1; | 
|  | ++Bits; | 
|  | } else { | 
|  | if ((Value & TracebackTable::ParmTypeFloatingIsDoubleBit) == 0) | 
|  | // Float parameter type. | 
|  | ParmsType += "f"; | 
|  | else | 
|  | // Double parameter type. | 
|  | ParmsType += "d"; | 
|  | ++ParsedFloatingNum; | 
|  | Value <<= 2; | 
|  | Bits += 2; | 
|  | } | 
|  | } | 
|  |  | 
|  | // We have more parameters than the 32 Bits could encode. | 
|  | if (ParsedNum < ParmsNum) | 
|  | ParmsType += ", ..."; | 
|  |  | 
|  | if (Value != 0u || ParsedFixedNum > FixedParmsNum || | 
|  | ParsedFloatingNum > FloatingParmsNum) | 
|  | return createStringError(errc::invalid_argument, | 
|  | "ParmsType encodes can not map to ParmsNum " | 
|  | "parameters in parseParmsType."); | 
|  | return ParmsType; | 
|  | } | 
|  |  | 
|  | SmallString<32> XCOFF::getExtendedTBTableFlagString(uint8_t Flag) { | 
|  | SmallString<32> Res; | 
|  |  | 
|  | if (Flag & ExtendedTBTableFlag::TB_OS1) | 
|  | Res += "TB_OS1 "; | 
|  | if (Flag & ExtendedTBTableFlag::TB_RESERVED) | 
|  | Res += "TB_RESERVED "; | 
|  | if (Flag & ExtendedTBTableFlag::TB_SSP_CANARY) | 
|  | Res += "TB_SSP_CANARY "; | 
|  | if (Flag & ExtendedTBTableFlag::TB_OS2) | 
|  | Res += "TB_OS2 "; | 
|  | if (Flag & ExtendedTBTableFlag::TB_EH_INFO) | 
|  | Res += "TB_EH_INFO "; | 
|  | if (Flag & ExtendedTBTableFlag::TB_LONGTBTABLE2) | 
|  | Res += "TB_LONGTBTABLE2 "; | 
|  |  | 
|  | // Two of the bits that haven't got used in the mask. | 
|  | if (Flag & 0x06) | 
|  | Res += "Unknown "; | 
|  |  | 
|  | // Pop the last space. | 
|  | Res.pop_back(); | 
|  | return Res; | 
|  | } | 
|  |  | 
|  | Expected<SmallString<32>> | 
|  | XCOFF::parseParmsTypeWithVecInfo(uint32_t Value, unsigned FixedParmsNum, | 
|  | unsigned FloatingParmsNum, | 
|  | unsigned VectorParmsNum) { | 
|  | SmallString<32> ParmsType; | 
|  |  | 
|  | unsigned ParsedFixedNum = 0; | 
|  | unsigned ParsedFloatingNum = 0; | 
|  | unsigned ParsedVectorNum = 0; | 
|  | unsigned ParsedNum = 0; | 
|  | unsigned ParmsNum = FixedParmsNum + FloatingParmsNum + VectorParmsNum; | 
|  |  | 
|  | for (int Bits = 0; Bits < 32 && ParsedNum < ParmsNum; Bits += 2) { | 
|  | if (++ParsedNum > 1) | 
|  | ParmsType += ", "; | 
|  |  | 
|  | switch (Value & TracebackTable::ParmTypeMask) { | 
|  | case TracebackTable::ParmTypeIsFixedBits: | 
|  | ParmsType += "i"; | 
|  | ++ParsedFixedNum; | 
|  | break; | 
|  | case TracebackTable::ParmTypeIsVectorBits: | 
|  | ParmsType += "v"; | 
|  | ++ParsedVectorNum; | 
|  | break; | 
|  | case TracebackTable::ParmTypeIsFloatingBits: | 
|  | ParmsType += "f"; | 
|  | ++ParsedFloatingNum; | 
|  | break; | 
|  | case TracebackTable::ParmTypeIsDoubleBits: | 
|  | ParmsType += "d"; | 
|  | ++ParsedFloatingNum; | 
|  | break; | 
|  | default: | 
|  | assert(false && "Unrecognized bits in ParmsType."); | 
|  | } | 
|  | Value <<= 2; | 
|  | } | 
|  |  | 
|  | // We have more parameters than the 32 Bits could encode. | 
|  | if (ParsedNum < ParmsNum) | 
|  | ParmsType += ", ..."; | 
|  |  | 
|  | if (Value != 0u || ParsedFixedNum > FixedParmsNum || | 
|  | ParsedFloatingNum > FloatingParmsNum || ParsedVectorNum > VectorParmsNum) | 
|  | return createStringError( | 
|  | errc::invalid_argument, | 
|  | "ParmsType encodes can not map to ParmsNum parameters " | 
|  | "in parseParmsTypeWithVecInfo."); | 
|  |  | 
|  | return ParmsType; | 
|  | } | 
|  |  | 
|  | Expected<SmallString<32>> XCOFF::parseVectorParmsType(uint32_t Value, | 
|  | unsigned ParmsNum) { | 
|  | SmallString<32> ParmsType; | 
|  | unsigned ParsedNum = 0; | 
|  | for (int Bits = 0; ParsedNum < ParmsNum && Bits < 32; Bits += 2) { | 
|  | if (++ParsedNum > 1) | 
|  | ParmsType += ", "; | 
|  | switch (Value & TracebackTable::ParmTypeMask) { | 
|  | case TracebackTable::ParmTypeIsVectorCharBit: | 
|  | ParmsType += "vc"; | 
|  | break; | 
|  |  | 
|  | case TracebackTable::ParmTypeIsVectorShortBit: | 
|  | ParmsType += "vs"; | 
|  | break; | 
|  |  | 
|  | case TracebackTable::ParmTypeIsVectorIntBit: | 
|  | ParmsType += "vi"; | 
|  | break; | 
|  |  | 
|  | case TracebackTable::ParmTypeIsVectorFloatBit: | 
|  | ParmsType += "vf"; | 
|  | break; | 
|  | } | 
|  |  | 
|  | Value <<= 2; | 
|  | } | 
|  |  | 
|  | // We have more parameters than the 32 Bits could encode. | 
|  | if (ParsedNum < ParmsNum) | 
|  | ParmsType += ", ..."; | 
|  |  | 
|  | if (Value != 0u) | 
|  | return createStringError(errc::invalid_argument, | 
|  | "ParmsType encodes more than ParmsNum parameters " | 
|  | "in parseVectorParmsType."); | 
|  | return ParmsType; | 
|  | } |