mirror of
https://github.com/capstone-engine/capstone.git
synced 2024-11-23 13:39:46 +00:00
0c90fe13f5
* Replace asserts with macros for AArch64, Alpha, LoongArch, Mips, SystemZ inc files. * Add missing clearing of MCInst * Ensure correct dir name is used. * Replace asserts in inc files for PPC, ARM, TriCore * Replace all asserts in modules with CS_ASSERT. Also enable the CS_ASSERTs if CMAKE_BUILD_TYPE=Debug * Formatting
635 lines
16 KiB
C
635 lines
16 KiB
C
/* Capstone Disassembly Engine, http://www.capstone-engine.org */
|
|
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2022, */
|
|
/* Rot127 <unisono@quyllur.org> 2022-2023 */
|
|
/* Automatically translated source file from LLVM. */
|
|
|
|
/* LLVM-commit: <commit> */
|
|
/* LLVM-tag: <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 */
|
|
|
|
//===-- MipsInstPrinter.cpp - Convert Mips 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 Mips MCInst to a .s file.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <capstone/platform.h>
|
|
|
|
#include "MipsMapping.h"
|
|
#include "MipsInstPrinter.h"
|
|
|
|
#define GET_SUBTARGETINFO_ENUM
|
|
#include "MipsGenSubtargetInfo.inc"
|
|
|
|
#define GET_INSTRINFO_ENUM
|
|
#include "MipsGenInstrInfo.inc"
|
|
|
|
#define GET_REGINFO_ENUM
|
|
#include "MipsGenRegisterInfo.inc"
|
|
|
|
#define CONCAT(a, b) CONCAT_(a, b)
|
|
#define CONCAT_(a, b) a##_##b
|
|
|
|
#define DEBUG_TYPE "asm-printer"
|
|
|
|
#define PRINT_ALIAS_INSTR
|
|
#include "MipsGenAsmWriter.inc"
|
|
|
|
static bool isReg(const MCInst *MI, unsigned OpNo, unsigned R)
|
|
{
|
|
return MCOperand_getReg(MCInst_getOperand((MCInst *)MI, (OpNo))) == R;
|
|
}
|
|
|
|
static const char *MipsFCCToString(Mips_CondCode CC)
|
|
{
|
|
switch (CC) {
|
|
case Mips_FCOND_F:
|
|
case Mips_FCOND_T:
|
|
return "f";
|
|
case Mips_FCOND_UN:
|
|
case Mips_FCOND_OR:
|
|
return "un";
|
|
case Mips_FCOND_OEQ:
|
|
case Mips_FCOND_UNE:
|
|
return "eq";
|
|
case Mips_FCOND_UEQ:
|
|
case Mips_FCOND_ONE:
|
|
return "ueq";
|
|
case Mips_FCOND_OLT:
|
|
case Mips_FCOND_UGE:
|
|
return "olt";
|
|
case Mips_FCOND_ULT:
|
|
case Mips_FCOND_OGE:
|
|
return "ult";
|
|
case Mips_FCOND_OLE:
|
|
case Mips_FCOND_UGT:
|
|
return "ole";
|
|
case Mips_FCOND_ULE:
|
|
case Mips_FCOND_OGT:
|
|
return "ule";
|
|
case Mips_FCOND_SF:
|
|
case Mips_FCOND_ST:
|
|
return "sf";
|
|
case Mips_FCOND_NGLE:
|
|
case Mips_FCOND_GLE:
|
|
return "ngle";
|
|
case Mips_FCOND_SEQ:
|
|
case Mips_FCOND_SNE:
|
|
return "seq";
|
|
case Mips_FCOND_NGL:
|
|
case Mips_FCOND_GL:
|
|
return "ngl";
|
|
case Mips_FCOND_LT:
|
|
case Mips_FCOND_NLT:
|
|
return "lt";
|
|
case Mips_FCOND_NGE:
|
|
case Mips_FCOND_GE:
|
|
return "nge";
|
|
case Mips_FCOND_LE:
|
|
case Mips_FCOND_NLE:
|
|
return "le";
|
|
case Mips_FCOND_NGT:
|
|
case Mips_FCOND_GT:
|
|
return "ngt";
|
|
}
|
|
CS_ASSERT_RET_VAL(0 && "Impossible condition code!", NULL);
|
|
return "";
|
|
}
|
|
|
|
const char *Mips_LLVM_getRegisterName(unsigned RegNo, bool noRegName);
|
|
|
|
static void printRegName(MCInst *MI, SStream *OS, MCRegister Reg)
|
|
{
|
|
int syntax_opt = MI->csh->syntax;
|
|
if (!(syntax_opt & CS_OPT_SYNTAX_NO_DOLLAR)) {
|
|
SStream_concat1(OS, '$');
|
|
}
|
|
SStream_concat0(OS, Mips_LLVM_getRegisterName(Reg, syntax_opt & CS_OPT_SYNTAX_NOREGNAME));
|
|
}
|
|
|
|
void Mips_LLVM_printInst(MCInst *MI, uint64_t Address, SStream *O) {
|
|
bool useAliasDetails = map_use_alias_details(MI);
|
|
if (!useAliasDetails) {
|
|
SStream_Close(O);
|
|
printInstruction(MI, Address, O);
|
|
SStream_Open(O);
|
|
map_set_fill_detail_ops(MI, false);
|
|
}
|
|
|
|
if (printAliasInstr(MI, Address, O) ||
|
|
printAlias4(MI, Address, O)) {
|
|
MCInst_setIsAlias(MI, true);
|
|
} else {
|
|
printInstruction(MI, Address, O);
|
|
}
|
|
|
|
if (!useAliasDetails) {
|
|
map_set_fill_detail_ops(MI, true);
|
|
}
|
|
}
|
|
|
|
void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
|
|
{
|
|
switch (MCInst_getOpcode(MI)) {
|
|
default:
|
|
break;
|
|
case Mips_AND16_NM:
|
|
case Mips_XOR16_NM:
|
|
case Mips_OR16_NM:
|
|
if (MCInst_getNumOperands(MI) == 2 && OpNo == 2)
|
|
OpNo = 0; // rt, rs -> rt, rs, rt
|
|
break;
|
|
case Mips_ADDu4x4_NM:
|
|
case Mips_MUL4x4_NM:
|
|
if (MCInst_getNumOperands(MI) == 2 && OpNo > 0)
|
|
OpNo = OpNo - 1; // rt, rs -> rt, rt, rs
|
|
break;
|
|
}
|
|
|
|
MCOperand *Op = MCInst_getOperand(MI, (OpNo));
|
|
if (MCOperand_isReg(Op)) {
|
|
add_cs_detail(MI, Mips_OP_GROUP_Operand, OpNo);
|
|
printRegName(MI, O, MCOperand_getReg(Op));
|
|
return;
|
|
}
|
|
|
|
|
|
if (MCOperand_isImm(Op)) {
|
|
switch (MCInst_getOpcode(MI)) {
|
|
case Mips_LI48_NM:
|
|
case Mips_ANDI16_NM:
|
|
case Mips_ANDI_NM:
|
|
case Mips_ORI_NM:
|
|
case Mips_XORI_NM:
|
|
case Mips_TEQ_NM:
|
|
case Mips_TNE_NM:
|
|
case Mips_SIGRIE_NM:
|
|
case Mips_SDBBP_NM:
|
|
case Mips_SDBBP16_NM:
|
|
case Mips_BREAK_NM:
|
|
case Mips_BREAK16_NM:
|
|
case Mips_SYSCALL_NM:
|
|
case Mips_SYSCALL16_NM:
|
|
case Mips_WAIT_NM:
|
|
CONCAT(printUImm, CONCAT(32, 0))
|
|
(MI, OpNo, O);
|
|
break;
|
|
default:
|
|
add_cs_detail(MI, Mips_OP_GROUP_Operand, OpNo);
|
|
printInt64(O, MCOperand_getImm(Op));
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void printJumpOperand(MCInst *MI, unsigned OpNo, SStream *O)
|
|
{
|
|
add_cs_detail(MI, Mips_OP_GROUP_JumpOperand, OpNo);
|
|
MCOperand *Op = MCInst_getOperand(MI, (OpNo));
|
|
if (MCOperand_isReg(Op))
|
|
return printRegName(MI, O, MCOperand_getReg(Op));
|
|
|
|
// only the upper bits are needed.
|
|
uint64_t Base = MI->address & ~0x0fffffffull;
|
|
uint64_t Target = MCOperand_getImm(Op);
|
|
printInt64(O, Base | Target);
|
|
}
|
|
|
|
static void printBranchOperand(MCInst *MI, uint64_t Address, unsigned OpNo, SStream *O)
|
|
{
|
|
add_cs_detail(MI, Mips_OP_GROUP_BranchOperand, OpNo);
|
|
MCOperand *Op = MCInst_getOperand(MI, (OpNo));
|
|
if (MCOperand_isReg(Op))
|
|
return printRegName(MI, O, MCOperand_getReg(Op));
|
|
|
|
uint64_t Target = Address + MCOperand_getImm(Op);
|
|
printInt64(O, Target);
|
|
}
|
|
|
|
#define DEFINE_printUImm(Bits) \
|
|
static void CONCAT(printUImm, CONCAT(Bits, 0))(MCInst * MI, int opNum, \
|
|
SStream *O) \
|
|
{ \
|
|
add_cs_detail(MI, CONCAT(Mips_OP_GROUP_UImm, CONCAT(Bits, 0)), opNum); \
|
|
MCOperand *MO = MCInst_getOperand(MI, (opNum)); \
|
|
if (MCOperand_isImm(MO)) { \
|
|
uint64_t Imm = MCOperand_getImm(MO); \
|
|
Imm &= (((uint64_t)1) << Bits) - 1; \
|
|
printUInt64(O, Imm); \
|
|
return; \
|
|
} \
|
|
MCOperand *Op = MCInst_getOperand(MI, (opNum)); \
|
|
printRegName(MI, O, MCOperand_getReg(Op)); \
|
|
}
|
|
|
|
#define DEFINE_printUImm_2(Bits, Offset) \
|
|
static void CONCAT(printUImm, CONCAT(Bits, Offset))(MCInst * MI, int opNum, \
|
|
SStream *O) \
|
|
{ \
|
|
add_cs_detail(MI, CONCAT(Mips_OP_GROUP_UImm, CONCAT(Bits, Offset)), \
|
|
opNum); \
|
|
MCOperand *MO = MCInst_getOperand(MI, (opNum)); \
|
|
if (MCOperand_isImm(MO)) { \
|
|
uint64_t Imm = MCOperand_getImm(MO); \
|
|
Imm -= Offset; \
|
|
Imm &= (1 << Bits) - 1; \
|
|
Imm += Offset; \
|
|
printUInt64(O, Imm); \
|
|
return; \
|
|
} \
|
|
MCOperand *Op = MCInst_getOperand(MI, (opNum)); \
|
|
printRegName(MI, O, MCOperand_getReg(Op)); \
|
|
}
|
|
|
|
DEFINE_printUImm(0);
|
|
DEFINE_printUImm(1);
|
|
DEFINE_printUImm(10);
|
|
DEFINE_printUImm(12);
|
|
DEFINE_printUImm(16);
|
|
DEFINE_printUImm(2);
|
|
DEFINE_printUImm(20);
|
|
DEFINE_printUImm(26);
|
|
DEFINE_printUImm(3);
|
|
DEFINE_printUImm(32);
|
|
DEFINE_printUImm(4);
|
|
DEFINE_printUImm(5);
|
|
DEFINE_printUImm(6);
|
|
DEFINE_printUImm(7);
|
|
DEFINE_printUImm(8);
|
|
DEFINE_printUImm_2(2, 1);
|
|
DEFINE_printUImm_2(5, 1);
|
|
DEFINE_printUImm_2(5, 32);
|
|
DEFINE_printUImm_2(5, 33);
|
|
DEFINE_printUImm_2(6, 1);
|
|
DEFINE_printUImm_2(6, 2);
|
|
|
|
static void printMemOperand(MCInst *MI, int opNum, SStream *O)
|
|
{
|
|
// Load/Store memory operands -- imm($reg)
|
|
// If PIC target the target is loaded as the
|
|
// pattern lw $25,%call16($28)
|
|
|
|
// opNum can be invalid if instruction had reglist as operand.
|
|
// MemOperand is always last operand of instruction (base + offset).
|
|
switch (MCInst_getOpcode(MI)) {
|
|
default:
|
|
break;
|
|
case Mips_SWM32_MM:
|
|
case Mips_LWM32_MM:
|
|
case Mips_SWM16_MM:
|
|
case Mips_SWM16_MMR6:
|
|
case Mips_LWM16_MM:
|
|
case Mips_LWM16_MMR6:
|
|
opNum = MCInst_getNumOperands(MI) - 2;
|
|
break;
|
|
}
|
|
|
|
set_mem_access(MI, true);
|
|
// Index register is encoded as immediate value
|
|
// in case of nanoMIPS indexed instructions
|
|
switch (MCInst_getOpcode(MI)) {
|
|
// No offset needed for paired LL/SC
|
|
case Mips_LLWP_NM:
|
|
case Mips_SCWP_NM:
|
|
break;
|
|
case Mips_LWX_NM:
|
|
case Mips_LWXS_NM:
|
|
case Mips_LWXS16_NM:
|
|
case Mips_LBX_NM:
|
|
case Mips_LBUX_NM:
|
|
case Mips_LHX_NM:
|
|
case Mips_LHUX_NM:
|
|
case Mips_LHXS_NM:
|
|
case Mips_LHUXS_NM:
|
|
case Mips_SWX_NM:
|
|
case Mips_SWXS_NM:
|
|
case Mips_SBX_NM:
|
|
case Mips_SHX_NM:
|
|
case Mips_SHXS_NM:
|
|
if (!MCOperand_isReg(MCInst_getOperand(MI, (opNum + 1)))) {
|
|
add_cs_detail(MI, Mips_OP_GROUP_MemOperand, (opNum + 1));
|
|
printRegName(MI, O, MCOperand_getImm(MCInst_getOperand(
|
|
MI, (opNum + 1))));
|
|
break;
|
|
}
|
|
// Fall through
|
|
default:
|
|
printOperand((MCInst *)MI, opNum + 1, O);
|
|
break;
|
|
}
|
|
SStream_concat0(O, "(");
|
|
printOperand((MCInst *)MI, opNum, O);
|
|
SStream_concat0(O, ")");
|
|
set_mem_access(MI, false);
|
|
}
|
|
|
|
static void printMemOperandEA(MCInst *MI, int opNum, SStream *O)
|
|
{
|
|
// when using stack locations for not load/store instructions
|
|
// print the same way as all normal 3 operand instructions.
|
|
printOperand((MCInst *)MI, opNum, O);
|
|
SStream_concat0(O, ", ");
|
|
printOperand((MCInst *)MI, opNum + 1, O);
|
|
}
|
|
|
|
static void printFCCOperand(MCInst *MI, int opNum, SStream *O)
|
|
{
|
|
MCOperand *MO = MCInst_getOperand(MI, (opNum));
|
|
SStream_concat0(O,
|
|
MipsFCCToString((Mips_CondCode)MCOperand_getImm(MO)));
|
|
}
|
|
|
|
static bool printAlias(const char *Str, const MCInst *MI, uint64_t Address,
|
|
unsigned OpNo, SStream *OS, bool IsBranch)
|
|
{
|
|
SStream_concat(OS, "%s%s", "\t", Str);
|
|
SStream_concat0(OS, "\t");
|
|
if (IsBranch)
|
|
printBranchOperand((MCInst *)MI, Address, OpNo, OS);
|
|
else
|
|
printOperand((MCInst *)MI, OpNo, OS);
|
|
return true;
|
|
}
|
|
|
|
static bool printAlias2(const char *Str, const MCInst *MI, uint64_t Address,
|
|
unsigned OpNo0, unsigned OpNo1, SStream *OS, bool IsBranch)
|
|
{
|
|
printAlias(Str, MI, Address, OpNo0, OS, IsBranch);
|
|
SStream_concat0(OS, ", ");
|
|
if (IsBranch)
|
|
printBranchOperand((MCInst *)MI, Address, OpNo1, OS);
|
|
else
|
|
printOperand((MCInst *)MI, OpNo1, OS);
|
|
return true;
|
|
}
|
|
|
|
static bool printAlias3(const char *Str, const MCInst *MI, uint64_t Address,
|
|
unsigned OpNo0, unsigned OpNo1, unsigned OpNo2, SStream *OS)
|
|
{
|
|
printAlias(Str, MI, Address, OpNo0, OS, false);
|
|
SStream_concat0(OS, ", ");
|
|
printOperand((MCInst *)MI, OpNo1, OS);
|
|
SStream_concat0(OS, ", ");
|
|
printOperand((MCInst *)MI, OpNo2, OS);
|
|
return true;
|
|
}
|
|
|
|
static bool printAlias4(const MCInst *MI, uint64_t Address, SStream *OS)
|
|
{
|
|
switch (MCInst_getOpcode(MI)) {
|
|
case Mips_BEQ:
|
|
case Mips_BEQ_MM:
|
|
// beq $zero, $zero, $L2 => b $L2
|
|
// beq $r0, $zero, $L2 => beqz $r0, $L2
|
|
return (isReg(MI, 0, Mips_ZERO) &&
|
|
isReg(MI, 1, Mips_ZERO) &&
|
|
printAlias("b", MI, Address, 2, OS, true)) ||
|
|
(isReg(MI, 1, Mips_ZERO) &&
|
|
printAlias2("beqz", MI, Address, 0, 2, OS, true));
|
|
case Mips_BEQ64:
|
|
// beq $r0, $zero, $L2 => beqz $r0, $L2
|
|
return isReg(MI, 1, Mips_ZERO_64) &&
|
|
printAlias2("beqz", MI, Address, 0, 2, OS, true);
|
|
case Mips_BNE:
|
|
case Mips_BNE_MM:
|
|
// bne $r0, $zero, $L2 => bnez $r0, $L2
|
|
return isReg(MI, 1, Mips_ZERO) &&
|
|
printAlias2("bnez", MI, Address, 0, 2, OS, true);
|
|
case Mips_BNE64:
|
|
// bne $r0, $zero, $L2 => bnez $r0, $L2
|
|
return isReg(MI, 1, Mips_ZERO_64) &&
|
|
printAlias2("bnez", MI, Address, 0, 2, OS, true);
|
|
case Mips_BGEZAL:
|
|
// bgezal $zero, $L1 => bal $L1
|
|
return isReg(MI, 0, Mips_ZERO) &&
|
|
printAlias("bal", MI, Address, 1, OS, true);
|
|
case Mips_BC1T:
|
|
// bc1t $fcc0, $L1 => bc1t $L1
|
|
return isReg(MI, 0, Mips_FCC0) &&
|
|
printAlias("bc1t", MI, Address, 1, OS, true);
|
|
case Mips_BC1F:
|
|
// bc1f $fcc0, $L1 => bc1f $L1
|
|
return isReg(MI, 0, Mips_FCC0) &&
|
|
printAlias("bc1f", MI, Address, 1, OS, true);
|
|
case Mips_JALR:
|
|
// jalr $zero, $r1 => jr $r1
|
|
// jalr $ra, $r1 => jalr $r1
|
|
return (isReg(MI, 0, Mips_ZERO) &&
|
|
printAlias("jr", MI, Address, 1, OS, false)) ||
|
|
(isReg(MI, 0, Mips_RA) &&
|
|
printAlias("jalr", MI, Address, 1, OS, false));
|
|
case Mips_JALR64:
|
|
// jalr $zero, $r1 => jr $r1
|
|
// jalr $ra, $r1 => jalr $r1
|
|
return (isReg(MI, 0, Mips_ZERO_64) &&
|
|
printAlias("jr", MI, Address, 1, OS, false)) ||
|
|
(isReg(MI, 0, Mips_RA_64) &&
|
|
printAlias("jalr", MI, Address, 1, OS, false));
|
|
case Mips_NOR:
|
|
case Mips_NOR_MM:
|
|
case Mips_NOR_MMR6:
|
|
// nor $r0, $r1, $zero => not $r0, $r1
|
|
return isReg(MI, 2, Mips_ZERO) &&
|
|
printAlias2("not", MI, Address, 0, 1, OS, false);
|
|
case Mips_NOR64:
|
|
// nor $r0, $r1, $zero => not $r0, $r1
|
|
return isReg(MI, 2, Mips_ZERO_64) &&
|
|
printAlias2("not", MI, Address, 0, 1, OS, false);
|
|
case Mips_OR:
|
|
case Mips_ADDu:
|
|
// or $r0, $r1, $zero => move $r0, $r1
|
|
// addu $r0, $r1, $zero => move $r0, $r1
|
|
return isReg(MI, 2, Mips_ZERO) &&
|
|
printAlias2("move", MI, Address, 0, 1, OS, false);
|
|
case Mips_LI48_NM:
|
|
case Mips_LI16_NM:
|
|
// li[16/48] $r0, imm => li $r0, imm
|
|
return printAlias2("li", MI, Address, 0, 1, OS, false);
|
|
case Mips_ADDIU_NM:
|
|
case Mips_ADDIUNEG_NM:
|
|
if (isReg(MI, 1, Mips_ZERO_NM))
|
|
return printAlias2("li", MI, Address, 0, 2, OS, false);
|
|
else
|
|
return printAlias3("addiu", MI, Address, 0, 1, 2, OS);
|
|
case Mips_ADDIU48_NM:
|
|
case Mips_ADDIURS5_NM:
|
|
case Mips_ADDIUR1SP_NM:
|
|
case Mips_ADDIUR2_NM:
|
|
case Mips_ADDIUGPB_NM:
|
|
case Mips_ADDIUGPW_NM:
|
|
return printAlias3("addiu", MI, Address, 0, 1, 2, OS);
|
|
case Mips_ANDI16_NM:
|
|
case Mips_ANDI_NM:
|
|
// andi[16/32] $r0, $r1, imm => andi $r0, $r1, imm
|
|
return printAlias3("andi", MI, Address, 0, 1, 2, OS);
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static void printRegisterList(MCInst *MI, int opNum, SStream *O)
|
|
{
|
|
// - 2 because register List is always first operand of instruction and it is
|
|
// always followed by memory operand (base + offset).
|
|
add_cs_detail(MI, Mips_OP_GROUP_RegisterList, opNum);
|
|
for (int i = opNum, e = MCInst_getNumOperands(MI) - 2; i != e; ++i) {
|
|
if (i != opNum)
|
|
SStream_concat0(O, ", ");
|
|
printRegName(MI, O, MCOperand_getReg(MCInst_getOperand(MI, (i))));
|
|
}
|
|
}
|
|
|
|
static void printNanoMipsRegisterList(MCInst *MI, int OpNum, SStream *O)
|
|
{
|
|
add_cs_detail(MI, Mips_OP_GROUP_NanoMipsRegisterList, OpNum);
|
|
for (unsigned I = OpNum; I < MCInst_getNumOperands(MI); I++) {
|
|
SStream_concat0(O, ", ");
|
|
printRegName(MI, O, MCOperand_getReg(MCInst_getOperand(MI, (I))));
|
|
}
|
|
}
|
|
|
|
static void printHi20(MCInst *MI, int OpNum, SStream *O)
|
|
{
|
|
MCOperand *MO = MCInst_getOperand(MI, (OpNum));
|
|
if (MCOperand_isImm(MO)) {
|
|
add_cs_detail(MI, Mips_OP_GROUP_Hi20, OpNum);
|
|
SStream_concat0(O, "%hi(");
|
|
printUInt64(O, MCOperand_getImm(MO));
|
|
SStream_concat0(O, ")");
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
static void printHi20PCRel(MCInst *MI, uint64_t Address, int OpNum, SStream *O)
|
|
{
|
|
MCOperand *MO = MCInst_getOperand(MI, (OpNum));
|
|
if (MCOperand_isImm(MO)) {
|
|
add_cs_detail(MI, Mips_OP_GROUP_Hi20PCRel, OpNum);
|
|
SStream_concat0(O, "%pcrel_hi(");
|
|
printUInt64(O, MCOperand_getImm(MO) + Address);
|
|
SStream_concat0(O, ")");
|
|
} else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
static void printPCRel(MCInst *MI, uint64_t Address, int OpNum, SStream *O)
|
|
{
|
|
MCOperand *MO = MCInst_getOperand(MI, (OpNum));
|
|
if (MCOperand_isImm(MO)) {
|
|
add_cs_detail(MI, Mips_OP_GROUP_PCRel, OpNum);
|
|
printUInt64(O, MCOperand_getImm(MO) + Address);
|
|
}
|
|
else
|
|
printOperand(MI, OpNum, O);
|
|
}
|
|
|
|
const char *Mips_LLVM_getRegisterName(unsigned RegNo, bool noRegName)
|
|
{
|
|
if (!RegNo || RegNo >= MIPS_REG_ENDING) {
|
|
return NULL;
|
|
}
|
|
if (noRegName) {
|
|
return getRegisterName(RegNo);
|
|
}
|
|
switch(RegNo) {
|
|
case MIPS_REG_AT:
|
|
case MIPS_REG_AT_64:
|
|
return "at";
|
|
case MIPS_REG_A0:
|
|
case MIPS_REG_A0_64:
|
|
return "a0";
|
|
case MIPS_REG_A1:
|
|
case MIPS_REG_A1_64:
|
|
return "a1";
|
|
case MIPS_REG_A2:
|
|
case MIPS_REG_A2_64:
|
|
return "a2";
|
|
case MIPS_REG_A3:
|
|
case MIPS_REG_A3_64:
|
|
return "a3";
|
|
case MIPS_REG_K0:
|
|
case MIPS_REG_K0_64:
|
|
return "k0";
|
|
case MIPS_REG_K1:
|
|
case MIPS_REG_K1_64:
|
|
return "k1";
|
|
case MIPS_REG_S0:
|
|
case MIPS_REG_S0_64:
|
|
return "s0";
|
|
case MIPS_REG_S1:
|
|
case MIPS_REG_S1_64:
|
|
return "s1";
|
|
case MIPS_REG_S2:
|
|
case MIPS_REG_S2_64:
|
|
return "s2";
|
|
case MIPS_REG_S3:
|
|
case MIPS_REG_S3_64:
|
|
return "s3";
|
|
case MIPS_REG_S4:
|
|
case MIPS_REG_S4_64:
|
|
return "s4";
|
|
case MIPS_REG_S5:
|
|
case MIPS_REG_S5_64:
|
|
return "s5";
|
|
case MIPS_REG_S6:
|
|
case MIPS_REG_S6_64:
|
|
return "s6";
|
|
case MIPS_REG_S7:
|
|
case MIPS_REG_S7_64:
|
|
return "s7";
|
|
case MIPS_REG_T0:
|
|
case MIPS_REG_T0_64:
|
|
return "t0";
|
|
case MIPS_REG_T1:
|
|
case MIPS_REG_T1_64:
|
|
return "t1";
|
|
case MIPS_REG_T2:
|
|
case MIPS_REG_T2_64:
|
|
return "t2";
|
|
case MIPS_REG_T3:
|
|
case MIPS_REG_T3_64:
|
|
return "t3";
|
|
case MIPS_REG_T4:
|
|
case MIPS_REG_T4_64:
|
|
return "t4";
|
|
case MIPS_REG_T5:
|
|
case MIPS_REG_T5_64:
|
|
return "t5";
|
|
case MIPS_REG_T6:
|
|
case MIPS_REG_T6_64:
|
|
return "t6";
|
|
case MIPS_REG_T7:
|
|
case MIPS_REG_T7_64:
|
|
return "t7";
|
|
case MIPS_REG_T8:
|
|
case MIPS_REG_T8_64:
|
|
return "t8";
|
|
case MIPS_REG_T9:
|
|
case MIPS_REG_T9_64:
|
|
return "t9";
|
|
case MIPS_REG_V0:
|
|
case MIPS_REG_V0_64:
|
|
return "v0";
|
|
case MIPS_REG_V1:
|
|
case MIPS_REG_V1_64:
|
|
return "v1";
|
|
default:
|
|
return getRegisterName(RegNo);
|
|
}
|
|
}
|