r2dec-js icon indicating copy to clipboard operation
r2dec-js copied to clipboard

[SuperH] pdd and pdg returns different flow graphs

Open wargio opened this issue 5 years ago • 1 comments

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:

  1. } while (? != ?) on r2dec
  2. 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

wargio avatar Sep 20 '19 08:09 wargio

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.

wargio avatar Sep 20 '19 08:09 wargio