summaryrefslogtreecommitdiff
path: root/arch/powerpc
diff options
context:
space:
mode:
authorGalen Williamson <galen@vector35.com>2024-11-06 08:44:58 -0500
committerGalen Williamson <galen@vector35.com>2024-11-06 19:24:25 -0500
commite8cdd50599f33495e23db7649a6dbccd65c08154 (patch)
tree96c4569b5d73a8d7d8b9b97fb12d10bd80c1b15f /arch/powerpc
parentf1b87ea3ecd5f2293a788e747598a764e898f2fa (diff)
Fixes Vector35/binaryninja-api#5968: "PowerPC flag names no longer recognized (due to changes in capstone register numbering)": handles new capstone flag numbers, allows assembling `isel` instructions with capstone syntax, disassembles flag registers with capstone syntax
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/arch_ppc.cpp64
-rw-r--r--arch/powerpc/assembler.cpp10
-rw-r--r--arch/powerpc/disassembler.cpp17
-rw-r--r--arch/powerpc/disassembler.h2
-rw-r--r--arch/powerpc/il.cpp2
-rw-r--r--arch/powerpc/test_disasm.cpp2
6 files changed, 57 insertions, 40 deletions
diff --git a/arch/powerpc/arch_ppc.cpp b/arch/powerpc/arch_ppc.cpp
index b9087aef..545e2be3 100644
--- a/arch/powerpc/arch_ppc.cpp
+++ b/arch/powerpc/arch_ppc.cpp
@@ -666,7 +666,7 @@ class PowerpcArchitecture: public Architecture
case PPC_OP_REG:
//MYLOG("pushing a register\n");
if (capstoneWorkaround || (insn->id == PPC_INS_ISEL && i == 3))
- result.emplace_back(RegisterToken, GetFlagName(op->reg - PPC_REG_R0));
+ result.emplace_back(RegisterToken, GetFlagName(op->reg));
else
result.emplace_back(RegisterToken, GetRegisterName(op->reg));
break;
@@ -965,43 +965,45 @@ class PowerpcArchitecture: public Architecture
{
MYLOG("%s(%d)\n", __func__, flag);
- switch(flag) {
+ switch(powerpc_crx_to_reg(flag)) {
case IL_FLAG_LT: return "lt";
case IL_FLAG_GT: return "gt";
case IL_FLAG_EQ: return "eq";
case IL_FLAG_SO: return "so";
- case IL_FLAG_LT_1: return "cr1_lt";
- case IL_FLAG_GT_1: return "cr1_gt";
- case IL_FLAG_EQ_1: return "cr1_eq";
- case IL_FLAG_SO_1: return "cr1_so";
- case IL_FLAG_LT_2: return "cr2_lt";
- case IL_FLAG_GT_2: return "cr2_gt";
- case IL_FLAG_EQ_2: return "cr2_eq";
- case IL_FLAG_SO_2: return "cr2_so";
- case IL_FLAG_LT_3: return "cr3_lt";
- case IL_FLAG_GT_3: return "cr3_gt";
- case IL_FLAG_EQ_3: return "cr3_eq";
- case IL_FLAG_SO_3: return "cr3_so";
- case IL_FLAG_LT_4: return "cr4_lt";
- case IL_FLAG_GT_4: return "cr4_gt";
- case IL_FLAG_EQ_4: return "cr4_eq";
- case IL_FLAG_SO_4: return "cr4_so";
- case IL_FLAG_LT_5: return "cr5_lt";
- case IL_FLAG_GT_5: return "cr5_gt";
- case IL_FLAG_EQ_5: return "cr5_eq";
- case IL_FLAG_SO_5: return "cr5_so";
- case IL_FLAG_LT_6: return "cr6_lt";
- case IL_FLAG_GT_6: return "cr6_gt";
- case IL_FLAG_EQ_6: return "cr6_eq";
- case IL_FLAG_SO_6: return "cr6_so";
- case IL_FLAG_LT_7: return "cr7_lt";
- case IL_FLAG_GT_7: return "cr7_gt";
- case IL_FLAG_EQ_7: return "cr7_eq";
- case IL_FLAG_SO_7: return "cr7_so";
+ case IL_FLAG_LT_1: return "cr1lt";
+ case IL_FLAG_GT_1: return "cr1gt";
+ case IL_FLAG_EQ_1: return "cr1eq";
+ case IL_FLAG_SO_1: return "cr1so";
+ case IL_FLAG_LT_2: return "cr2lt";
+ case IL_FLAG_GT_2: return "cr2gt";
+ case IL_FLAG_EQ_2: return "cr2eq";
+ case IL_FLAG_SO_2: return "cr2so";
+ case IL_FLAG_LT_3: return "cr3lt";
+ case IL_FLAG_GT_3: return "cr3gt";
+ case IL_FLAG_EQ_3: return "cr3eq";
+ case IL_FLAG_SO_3: return "cr3so";
+ case IL_FLAG_LT_4: return "cr4lt";
+ case IL_FLAG_GT_4: return "cr4gt";
+ case IL_FLAG_EQ_4: return "cr4eq";
+ case IL_FLAG_SO_4: return "cr4so";
+ case IL_FLAG_LT_5: return "cr5lt";
+ case IL_FLAG_GT_5: return "cr5gt";
+ case IL_FLAG_EQ_5: return "cr5eq";
+ case IL_FLAG_SO_5: return "cr5so";
+ case IL_FLAG_LT_6: return "cr6lt";
+ case IL_FLAG_GT_6: return "cr6gt";
+ case IL_FLAG_EQ_6: return "cr6eq";
+ case IL_FLAG_SO_6: return "cr6so";
+ case IL_FLAG_LT_7: return "cr7lt";
+ case IL_FLAG_GT_7: return "cr7gt";
+ case IL_FLAG_EQ_7: return "cr7eq";
+ case IL_FLAG_SO_7: return "cr7so";
case IL_FLAG_XER_SO: return "xer_so";
case IL_FLAG_XER_OV: return "xer_ov";
case IL_FLAG_XER_CA: return "xer_ca";
- default: return "ERR_FLAG_NAME";
+ default:
+ // LogWarn("Unknown flag: %#x/%d", flag, flag);
+ return "ERR_FLAG_NAME";
}
}
diff --git a/arch/powerpc/assembler.cpp b/arch/powerpc/assembler.cpp
index d0c04ce2..6ba26b97 100644
--- a/arch/powerpc/assembler.cpp
+++ b/arch/powerpc/assembler.cpp
@@ -1299,7 +1299,7 @@ map<string, info> lookup = {
{ "addc . GPR , GPR , GPR",{0x7C000015,0x03FFF800}}, // 011111xxxxxxxxxxxxxxx00000010101 addc. r0, r0, r0
{ "mulhwu GPR , GPR , GPR",{0x7C000016,0x03FFF800}}, // 011111xxxxxxxxxxxxxxx00000010110 mulhwu r0, r0, r0
{ "mulhwu . GPR , GPR , GPR",{0x7C000017,0x03FFF800}}, // 011111xxxxxxxxxxxxxxx00000010111 mulhwu. r0, r0, r0
-{ "isel GPR , NUM , GPR , NUM",{0x7C00001E,0x03E0FFC0}}, // 011111xxxxx00000xxxxxxxxxx011110 isel r0, 0, r0, 0
+{ "isel GPR , NUM , GPR , CREG FLAG",{0x7C00001E,0x03E0FFC0}}, // 011111xxxxx00000xxxxxxxxxx011110 isel r0, 0, r0, 0
{ "mfcr GPR",{0x7C000026,0x03E00000}}, // 011111xxxxx000000000000000100110 mfcr r0
{ "lwarx GPR , NUM , GPR",{0x7C000028,0x03E0F800}}, // 011111xxxxx00000xxxxx00000101000 lwarx r0, 0, r0
{ "ldx GPR , NUM , GPR",{0x7C00002A,0x03E0F800}}, // 011111xxxxx00000xxxxx00000101010 ldx r0, 0, r0
@@ -1498,7 +1498,7 @@ map<string, info> lookup = {
{ "mtspefscr GPR",{0x7C0083A6,0x03E00000}}, // 011111xxxxx000001000001110100110 mtspefscr r0
{ "lvsl VREG , GPR , GPR",{0x7C01000C,0x03FFF800}}, // 011111xxxxxxxxxxxxxxx00000001100 lvsl v0, r1, r0
{ "lvebx VREG , GPR , GPR",{0x7C01000E,0x03FFF800}}, // 011111xxxxxxxxxxxxxxx00000001110 lvebx v0, r1, r0
-{ "isel GPR , GPR , GPR , NUM",{0x7C01001E,0x03FFFFC0}}, // 011111xxxxxxxxxxxxxxxxxxxx011110 isel r0, r1, r0, 0
+{ "isel GPR , GPR , GPR , CREG FLAG",{0x7C01001E,0x03FFFFC0}}, // 011111xxxxxxxxxxxxxxxxxxxx011110 isel r0, r1, r0, cr0eq
{ "lwarx GPR , GPR , GPR",{0x7C010028,0x03FFF800}}, // 011111xxxxxxxxxxxxxxx00000101000 lwarx r0, r1, r0
{ "ldx GPR , GPR , GPR",{0x7C01002A,0x03FFF800}}, // 011111xxxxxxxxxxxxxxx00000101010 ldx r0, r1, r0
{ "lwzx GPR , GPR , GPR",{0x7C01002E,0x03FFF800}}, // 011111xxxxxxxxxxxxxxx00000101110 lwzx r0, r1, r0
@@ -2312,7 +2312,7 @@ int tokenize(string src, vector<token>& result, string& err)
}
/* wtf? */
else {
- err = "error at: " + string(inbuf);
+ err = "error at: " + string(inbuf) + " in " + src;
goto cleanup;
}
}
@@ -2776,7 +2776,7 @@ int assemble_single(string src, uint32_t addr, uint8_t *result, string& err,
vector<token> toks_child;
if(tokenize(src, toks_src, err)) {
- err = "invalid syntax";
+ err += "invalid syntax in " + src;
return -1;
}
@@ -2786,7 +2786,7 @@ int assemble_single(string src, uint32_t addr, uint8_t *result, string& err,
MYLOG("src:%s has signature:%s\n", src.c_str(), sig_src.c_str());
if(lookup.find(sig_src) == lookup.end()) {
- err = "invalid syntax";
+ err = "invalid syntax in " + sig_src;
return -1;
}
diff --git a/arch/powerpc/disassembler.cpp b/arch/powerpc/disassembler.cpp
index 480ab658..66e40d32 100644
--- a/arch/powerpc/disassembler.cpp
+++ b/arch/powerpc/disassembler.cpp
@@ -106,7 +106,7 @@ powerpc_decompose(const uint8_t *data, int size, uint32_t addr, bool lil_end,
// bool update_cr0;
// uint8_t op_count;
// cs_ppc_op operands[8];
- // } cs_ppc;
+ // } cs_ppc;
// and each operand is:
// typedef struct cs_ppc_op {
@@ -183,3 +183,18 @@ powerpc_reg_to_str(uint32_t rid)
return cs_reg_name(handle_lil, rid);
}
+extern "C" const uint32_t
+powerpc_crx_to_reg(uint32_t rid)
+{
+ if (rid >= PPC_REG_CR0EQ && rid <= PPC_REG_CR7EQ)
+ return (rid - PPC_REG_CR0EQ) * 4 + 2;
+ else if (rid >= PPC_REG_CR0GT && rid <= PPC_REG_CR7GT)
+ return (rid - PPC_REG_CR0GT) * 4 + 1;
+ else if (rid >= PPC_REG_CR0LT && rid <= PPC_REG_CR7LT)
+ return (rid - PPC_REG_CR0LT) * 4 + 0;
+ else if (rid >= PPC_REG_CR0UN && rid <= PPC_REG_CR7UN)
+ return (rid - PPC_REG_CR0UN) * 4 + 3;
+ else
+ return rid;
+}
+
diff --git a/arch/powerpc/disassembler.h b/arch/powerpc/disassembler.h
index e1d3ca55..d586a517 100644
--- a/arch/powerpc/disassembler.h
+++ b/arch/powerpc/disassembler.h
@@ -66,4 +66,4 @@ extern "C" int powerpc_decompose(const uint8_t *data, int size, uint32_t addr,
extern "C" int powerpc_disassemble(struct decomp_result *, char *buf, size_t len);
extern "C" const char *powerpc_reg_to_str(uint32_t rid);
-
+extern "C" const uint32_t powerpc_crx_to_reg(uint32_t rid);
diff --git a/arch/powerpc/il.cpp b/arch/powerpc/il.cpp
index 76cf7419..4d074aa4 100644
--- a/arch/powerpc/il.cpp
+++ b/arch/powerpc/il.cpp
@@ -860,7 +860,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
REQUIRE4OPS
{
LowLevelILLabel trueLabel, falseLabel, doneLabel;
- uint32_t crBit = oper3->reg - PPC_REG_R0;
+ uint32_t crBit = powerpc_crx_to_reg(oper3->reg);
uint32_t cr = crBit / 4;
switch (crBit % 4)
diff --git a/arch/powerpc/test_disasm.cpp b/arch/powerpc/test_disasm.cpp
index b893d2ab..5ee7d1dd 100644
--- a/arch/powerpc/test_disasm.cpp
+++ b/arch/powerpc/test_disasm.cpp
@@ -28,7 +28,7 @@ int disas_instr_word(uint32_t instr_word, char *buf)
struct cs_detail *detail = &(res.detail);
struct cs_ppc *ppc = &(detail->ppc);
- if(powerpc_decompose((const uint8_t *)&instr_word, 4, 0, true, &res)) {
+ if(powerpc_decompose((const uint8_t *)&instr_word, 4, 0, true, &res, false)) {
if(print_errors) printf("ERROR: powerpc_decompose()\n");
goto cleanup;
}