r2dec-js
r2dec-js copied to clipboard
[SuperH] pdd and pdg returns different flow graphs
Following up on a current r2dec SH4 usecase... here you have a pdda
:
; assembly | /* r2dec pseudo code output */
| /* sh4.out @ 0x8009c20 */
| #include <stdint.h>
|
; (fcn) sym.afunc () | void afunc () {
0x08009c20 mov.l r8, @-r15 | r15 -= 4;
| *(r15) = (int32_t) r8;
0x08009c22 mov.w @(0x186,PC), r3 | r3 = (int16_t) *(0x8009da8);
0x08009c24 mov.l r9, @-r15 | r15 -= 4;
| *(r15) = (int32_t) r9;
0x08009c26 mov.l r10, @-r15 | r15 -= 4;
| *(r15) = (int32_t) r10;
0x08009c28 mov.l r11, @-r15 | r15 -= 4;
| *(r15) = (int32_t) r11;
0x08009c2a mov.l r12, @-r15 | r15 -= 4;
| *(r15) = (int32_t) r12;
0x08009c2c mov.l r13, @-r15 | r15 -= 4;
| *(r15) = (int32_t) r13;
0x08009c2e mov.l r14, @-r15 | r15 -= 4;
| *(r15) = (int32_t) r14;
0x08009c30 sts.l pr, @-r15 | r15 -= 4;
| *(r15) = (int32_t) pr;
0x08009c32 mov.w @(0x178,PC), r0 | r0 = (int16_t) *(0x8009daa);
0x08009c34 sub r3, r15 | r15 -= r3;
0x08009c36 mov r15, r14 | r14 = r15;
0x08009c38 mov r14, r1 | r1 = r14;
0x08009c3a add r14, r0 | r0 += r14;
0x08009c3c mov r14, r2 | r2 = r14;
0x08009c3e add 0x30, r1 | r1 += 0x30;
0x08009c40 mov.l @(0x178,PC), r10 | r10 = (int32_t) *(0x8009db8);
0x08009c42 add 0x10, r2 | r2 += 0x10;
0x08009c44 mov.l r1, @(0x10,r0) | *((r0 + 0x10)) = (int32_t) r1;
0x08009c46 mov.l r2, @(0x8,r0) | *((r0 + 0x8)) = (int32_t) r2;
0x08009c48 add 0xF0, r1 | r1 += 0xf0;
0x08009c4a mov.l @(0x10,r0), r8 | r8 = (int32_t) *((r0 + 0x10));
0x08009c4c mov 0x2C, r9 | r9 = 0x2c;
0x08009c4e mov.l r1, @(0xC,r0) | *((r0 + 0xc)) = (int32_t) r1;
| do {
0x08009c50 mov.l @(0x16C,PC), r2 | r2 = (int32_t) *(0x8009dbc);
0x08009c52 mov.l @(0x170,PC), r5 | r5 = (int32_t) *(0x8009dc2);
0x08009c54 mov r8, r4 | r4 = r8;
0x08009c56 jsr @r2 | void (*r2)() ();
0x08009c58 dt r9 | r9 -= r9;
0x08009c5a add 0x10, r8 | r8 += 0x10;
0x08009c5c bf.s 0x08009c50 |
| } while (? != ?);
| }
And then a GHidra decompile of the same func over here:
undefined4 afunc(void)
{
char cVar1;
undefined4 uVar2;
undefined4 uVar3;
uint uVar4;
undefined4 uVar5;
int iVar6;
undefined *puVar7;
int iVar8;
uint uVar9;
undefined *puVar10;
undefined auStack1648 [16];
undefined auStack1632 [16];
undefined auStack1616 [16];
undefined auStack1600 [704];
undefined auStack896 [16];
undefined auStack880 [704];
char local_b0 [64];
undefined auStack112 [64];
int local_30;
undefined *local_2c;
undefined *local_28;
undefined *local_24;
puVar7 = auStack1600;
local_2c = auStack1632;
local_28 = auStack1616;
iVar8 = 0x2c;
local_24 = puVar7;
do {
(*(code *)0x0)(puVar7,0x701b8);
iVar8 = iVar8 + -1;
puVar7 = puVar7 + 0x10;
} while (iVar8 != 0);
uVar2 = (*(code *)0x0)();
(*(code *)0x0)(auStack1648,uVar2);
iVar6 = 0;
(*(code *)0x0)(local_2c,0x701b8);
iVar8 = (*(code *)0x0)(0x701bc,local_28);
if ((iVar6 == -1) && (iVar8 == -1)) {
iVar8 = 0x701d0;
}
else {
local_30 = (*(code *)0x0)(&DAT_000701f8,0x70214);
if (local_30 == 0) {
iVar8 = 0x70218;
}
else {
iVar8 = 0x2c;
puVar7 = auStack880;
do {
(*(code *)0x0)(puVar7,0x701b8);
iVar8 = iVar8 + -1;
puVar7 = puVar7 + 0x10;
} while (iVar8 != 0);
(*(code *)0x0)(local_b0,0x40,local_30);
(*(code *)0x0)(local_b0,0x7023c);
iVar8 = (*(code *)0x0)(local_b0);
iVar6 = (*(code *)0x0)();
if (iVar8 == iVar6) {
(*(code *)0x0)(0x200,0x40,local_30);
do {
while( true ) {
while( true ) {
iVar8 = (*(code *)0x0)(local_b0,0x40,local_30);
if (iVar8 == 0) {
(*(code *)0x0)(local_30);
iVar8 = (*(code *)0x0)(local_28,auStack896);
if ((iVar8 != 0) ||
(((iVar8 = (*(code *)0x0)(local_2c,0x701b8), iVar8 == 0 ||
(iVar8 = (*(code *)0x0)(auStack1648,local_2c), iVar8 != 0)) &&
(iVar8 = (*(code *)0x0)(local_2c,0x701b8), iVar8 != 0)))) {
(*(code *)0x0)(0x702cc,auStack1648,local_2c);
return 0;
}
uVar9 = 0;
puVar10 = auStack880;
puVar7 = local_24;
do {
iVar8 = (*(code *)0x0)(puVar10,0x701b8);
if (iVar8 != 0) {
uVar2 = (*(code *)0x0)(uVar9 & 0xffff);
(*(code *)0x0)(auStack112,0x70284,uVar2);
iVar6 = 0;
iVar8 = (*(code *)0x0)(auStack112,0x2f);
if (iVar8 != 0) {
iVar6 = 0;
*(undefined *)(iVar8 + 1) = 0;
}
iVar8 = (*(code *)0x0)(auStack112,puVar7);
if ((iVar6 == -1 && iVar8 == -1) ||
(iVar8 = (*(code *)0x0)(puVar10,puVar7), iVar8 != 0)) {
(*(code *)0x0)(0x70288);
(*(code *)0x0)(&LAB_000702a8,uVar9,puVar10,puVar7);
return 0;
}
}
puVar7 = puVar7 + 0x10;
uVar9 = uVar9 + 1;
puVar10 = puVar10 + 0x10;
if (0x2b < (int)uVar9) {
return 0x200;
}
} while( true );
}
uVar9 = 0;
while( true ) {
uVar4 = (*(code *)0x0)(local_b0);
if (uVar4 <= uVar9) break;
cVar1 = (*(code *)0x0)((int)local_b0[uVar9]);
local_b0[uVar9] = cVar1;
uVar9 = uVar9 + 1;
}
uVar2 = (*(code *)0x0)(local_b0,0x7023c);
uVar3 = (*(code *)0x0)(0,0x7023c);
iVar8 = (*(code *)0x0)(uVar2,0x70264);
if (iVar8 != 0) break;
(*(code *)0x0)(auStack896,uVar3);
}
iVar8 = (*(code *)0x0)(uVar2,0x7026c);
if (iVar8 != 0) break;
(*(code *)0x0)(local_2c,uVar3);
(*(code *)0x0)(0x70270,local_2c);
}
uVar9 = 0;
puVar7 = auStack880;
while ((int)uVar9 < 0x2c) {
uVar5 = (*(code *)0x0)(uVar9 & 0xffff);
iVar8 = (*(code *)0x0)(uVar5,uVar2);
if (iVar8 == 0) {
(*(code *)0x0)(puVar7,uVar3);
break;
}
puVar7 = puVar7 + 0x10;
uVar9 = uVar9 + 1;
}
} while( true );
}
uVar2 = (*(code *)0x0)(local_b0);
uVar3 = (*(code *)0x0)();
(*(code *)0x0)(0x70240,uVar2,uVar3);
iVar8 = local_30;
}
}
(*(code *)0x0)(iVar8);
return 0;
}
I'm a bit concerned about:
-
} while (? != ?)
on r2dec - The relative length and complexity of both dissassemblies... to put it simply: which one should I trust more? :-S
Happy to share the bin privately if that helps, unless you are already around r2-bins?
/cc @radare
Originally posted by @brainstorm in https://github.com/wargio/r2dec-js/issues/178#issuecomment-533336917
R2dec relies on agf
flow graph, so i think there is an issue on the anal plugin for the SuperH.
Regarding } while (? != ?);
, well, i didn't implement the flags update on superh. you can guess easily that the add
operation updates the flag internally in the SuperH CPU and they are used to branch after.