/* Capstone Disassembly Engine, http://www.capstone-engine.org */ /* By Nguyen Anh Quynh , 2013-2022, */ /* Rot127 2022-2023 */ /* Automatically translated source file from LLVM. */ /* LLVM-commit: */ /* LLVM-tag: */ /* Only small edits allowed. */ /* For multiple similar edits, please create a Patch for the translator. */ /* Capstone's C++ file translator: */ /* https://github.com/capstone-engine/capstone/tree/next/suite/auto-sync */ //===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly syntax -----==// // // 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 // //===----------------------------------------------------------------------===// // // This class prints an Sparc MCInst to a .s file. // //===----------------------------------------------------------------------===// #include #include #include #include #include "../../MCInstPrinter.h" #include "../../Mapping.h" #include "SparcInstPrinter.h" #include "SparcLinkage.h" #include "SparcMCTargetDesc.h" #include "SparcMapping.h" #include "SparcDisassemblerExtension.h" #define CONCAT(a, b) CONCAT_(a, b) #define CONCAT_(a, b) a##_##b #define DEBUG_TYPE "asm-printer" static void printCustomAliasOperand( MCInst *MI, uint64_t Address, unsigned OpIdx, unsigned PrintMethodIdx, SStream *OS); static void printOperand(MCInst *MI, int opNum, SStream *O); #define GET_INSTRUCTION_NAME #define PRINT_ALIAS_INSTR #include "SparcGenAsmWriter.inc" static void printRegName(SStream *OS, MCRegister Reg) { SStream_concat1(OS, '%'); SStream_concat0(OS, getRegisterName(Reg, Sparc_NoRegAltName)); } static void printRegNameAlt(SStream *OS, MCRegister Reg, unsigned AltIdx) { SStream_concat1(OS, '%'); SStream_concat0(OS, getRegisterName(Reg, AltIdx)); } static void printInst(MCInst *MI, uint64_t Address, SStream *O) { bool isAlias = false; bool useAliasDetails = map_use_alias_details(MI); map_set_fill_detail_ops(MI, useAliasDetails); if (!printAliasInstr(MI, Address, O) && !printSparcAliasInstr(MI, O)) { MCInst_setIsAlias(MI, false); } else { isAlias = true; MCInst_setIsAlias(MI, isAlias); if (useAliasDetails) { return; } } if (!isAlias || !useAliasDetails) { map_set_fill_detail_ops(MI, !(isAlias && useAliasDetails)); if (isAlias) SStream_Close(O); printInstruction(MI, Address, O); if (isAlias) SStream_Open(O); } } bool printSparcAliasInstr(MCInst *MI, SStream *O) { switch (MCInst_getOpcode(MI)) { default: return false; case Sparc_JMPLrr: case Sparc_JMPLri: { if (MCInst_getNumOperands(MI) != 3) return false; if (!MCOperand_isReg(MCInst_getOperand(MI, (0)))) return false; switch (MCOperand_getReg(MCInst_getOperand(MI, (0)))) { default: return false; case Sparc_G0: // jmp $addr | ret | retl if (MCOperand_isImm(MCInst_getOperand(MI, (2))) && MCOperand_getImm(MCInst_getOperand(MI, (2))) == 8) { switch (MCOperand_getReg( MCInst_getOperand(MI, (1)))) { default: break; case Sparc_I7: SStream_concat0(O, "\tret"); return true; case Sparc_O7: SStream_concat0(O, "\tretl"); return true; } } SStream_concat0(O, "\tjmp "); printMemOperand(MI, 1, O); return true; case Sparc_O7: // call $addr SStream_concat0(O, "\tcall "); printMemOperand(MI, 1, O); return true; } } case Sparc_V9FCMPS: case Sparc_V9FCMPD: case Sparc_V9FCMPQ: case Sparc_V9FCMPES: case Sparc_V9FCMPED: case Sparc_V9FCMPEQ: { if (Sparc_getFeatureBits(MI->csh->mode, Sparc_FeatureV9) || (MCInst_getNumOperands(MI) != 3) || (!MCOperand_isReg(MCInst_getOperand(MI, (0)))) || (MCOperand_getReg(MCInst_getOperand(MI, (0))) != Sparc_FCC0)) return false; // if V8, skip printing %fcc0. switch (MCInst_getOpcode(MI)) { default: case Sparc_V9FCMPS: SStream_concat0(O, "\tfcmps "); break; case Sparc_V9FCMPD: SStream_concat0(O, "\tfcmpd "); break; case Sparc_V9FCMPQ: SStream_concat0(O, "\tfcmpq "); break; case Sparc_V9FCMPES: SStream_concat0(O, "\tfcmpes "); break; case Sparc_V9FCMPED: SStream_concat0(O, "\tfcmped "); break; case Sparc_V9FCMPEQ: SStream_concat0(O, "\tfcmpeq "); break; } printOperand(MI, 1, O); SStream_concat0(O, ", "); printOperand(MI, 2, O); return true; } } } static void printOperand(MCInst *MI, int opNum, SStream *O) { Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_Operand, opNum); MCOperand *MO = MCInst_getOperand(MI, (opNum)); if (MCOperand_isReg(MO)) { unsigned Reg = MCOperand_getReg(MO); if (Sparc_getFeatureBits(MI->csh->mode, Sparc_FeatureV9)) printRegNameAlt(O, Reg, Sparc_RegNamesStateReg); else printRegName(O, Reg); return; } if (MCOperand_isImm(MO)) { switch (MCInst_getOpcode(MI)) { default: printInt32(O, (int)MCOperand_getImm(MO)); return; case Sparc_TICCri: // Fall through case Sparc_TICCrr: // Fall through case Sparc_TRAPri: // Fall through case Sparc_TRAPrr: // Fall through case Sparc_TXCCri: // Fall through case Sparc_TXCCrr: // Fall through // Only seven-bit values up to 127. printInt8(O, ((int)MCOperand_getImm(MO) & 0x7f)); return; } } CS_ASSERT(MCOperand_isExpr(MO) && "Unknown operand kind in printOperand"); } void printMemOperand(MCInst *MI, int opNum, SStream *O) { Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_MemOperand, opNum); MCOperand *Op1 = MCInst_getOperand(MI, (opNum)); MCOperand *Op2 = MCInst_getOperand(MI, (opNum + 1)); bool PrintedFirstOperand = false; if (MCOperand_isReg(Op1) && MCOperand_getReg(Op1) != Sparc_G0) { printOperand(MI, opNum, O); PrintedFirstOperand = true; } // Skip the second operand iff it adds nothing (literal 0 or %g0) and we've // already printed the first one const bool SkipSecondOperand = PrintedFirstOperand && ((MCOperand_isReg(Op2) && MCOperand_getReg(Op2) == Sparc_G0) || (MCOperand_isImm(Op2) && MCOperand_getImm(Op2) == 0)); if (!SkipSecondOperand) { if (PrintedFirstOperand) SStream_concat0(O, "+"); printOperand(MI, opNum + 1, O); } } void printCCOperand(MCInst *MI, int opNum, SStream *O) { Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_CCOperand, opNum); int CC = (int)MCOperand_getImm(MCInst_getOperand(MI, (opNum))); switch (MCInst_getOpcode(MI)) { default: break; case Sparc_FBCOND: case Sparc_FBCONDA: case Sparc_FBCOND_V9: case Sparc_FBCONDA_V9: case Sparc_BPFCC: case Sparc_BPFCCA: case Sparc_BPFCCNT: case Sparc_BPFCCANT: case Sparc_MOVFCCrr: case Sparc_V9MOVFCCrr: case Sparc_MOVFCCri: case Sparc_V9MOVFCCri: case Sparc_FMOVS_FCC: case Sparc_V9FMOVS_FCC: case Sparc_FMOVD_FCC: case Sparc_V9FMOVD_FCC: case Sparc_FMOVQ_FCC: case Sparc_V9FMOVQ_FCC: // Make sure CC is a fp conditional flag. CC = (CC < SPARC_CC_FCC_BEGIN) ? (CC + SPARC_CC_FCC_BEGIN) : CC; break; case Sparc_CBCOND: case Sparc_CBCONDA: // Make sure CC is a cp conditional flag. CC = (CC < SPARC_CC_CPCC_BEGIN) ? (CC + SPARC_CC_CPCC_BEGIN) : CC; break; case Sparc_BPR: case Sparc_BPRA: case Sparc_BPRNT: case Sparc_BPRANT: case Sparc_MOVRri: case Sparc_MOVRrr: case Sparc_FMOVRS: case Sparc_FMOVRD: case Sparc_FMOVRQ: // Make sure CC is a register conditional flag. CC = (CC < SPARC_CC_REG_BEGIN) ? (CC + SPARC_CC_REG_BEGIN) : CC; break; } SStream_concat0(O, SPARCCondCodeToString((sparc_cc)CC)); } bool printGetPCX(MCInst *MI, unsigned opNum, SStream *O) { printf("FIXME: Implement SparcInstPrinter::printGetPCX."); return true; } void printMembarTag(MCInst *MI, int opNum, SStream *O) { Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_MembarTag, opNum); static const char *const TagNames[] = { "#LoadLoad", "#StoreLoad", "#LoadStore", "#StoreStore", "#Lookaside", "#MemIssue", "#Sync" }; unsigned Imm = MCOperand_getImm(MCInst_getOperand(MI, (opNum))); if (Imm > 127) { printUInt32(O, Imm); return; } bool First = true; for (unsigned i = 0; i < sizeof(TagNames); i++) { if (Imm & (1ull << i)) { SStream_concat(O, "%s", (First ? "" : " | ")); SStream_concat0(O, TagNames[i]); First = false; } } } #define GET_ASITAG_IMPL #include "SparcGenSystemOperands.inc" void printASITag(MCInst *MI, int opNum, SStream *O) { Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_ASITag, opNum); unsigned Imm = MCOperand_getImm(MCInst_getOperand(MI, (opNum))); const Sparc_ASITag_ASITag *ASITag = Sparc_ASITag_lookupASITagByEncoding(Imm); if (Sparc_getFeatureBits(MI->csh->mode, Sparc_FeatureV9) && ASITag) { SStream_concat1(O, '#'); SStream_concat0(O, ASITag->Name); } else printUInt32(O, Imm); } void Sparc_LLVM_printInst(MCInst *MI, uint64_t Address, const char *Annot, SStream *O) { printInst(MI, Address, O); } const char *Sparc_LLVM_getRegisterName(unsigned RegNo, unsigned AltIdx) { return getRegisterName(RegNo, AltIdx); }