ff7_field_control_flow_test.cpp 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #include <gmock/gmock.h>
  2. #include "../ControlFlow.h"
  3. #include "decompiler/ff7_field/ff7_field_disassembler.h"
  4. #include "decompiler/ff7_field/ff7_field_engine.h"
  5. #include "decompiler/ff7_field/ff7_field_codegen.h"
  6. #include "util.h"
  7. #include "ff7_field_dummy_formatter.h"
  8. // Verify next 3 instructions are NOP's and return address of final NOP
  9. static uint32 Is3Nops(InstVec& insts, uint32& pos)
  10. {
  11. for (int i = 0; i < 3; i++)
  12. {
  13. pos++;
  14. EXPECT_EQ(insts[pos]->opcode_, eOpcodes::NOP);
  15. EXPECT_EQ(insts[pos]->params_.size(), 0);
  16. }
  17. return insts[pos]->_address;
  18. }
  19. // Each forward jump type has its own script that starts with the
  20. // jump opcode followed by 2 NOP's, the 3rd NOP is the end of the script
  21. // and should be the target address of the jump.
  22. static void CheckForwardJump(eOpcodes opCode, size_t paramsSize, InstVec& insts, uint32& pos)
  23. {
  24. pos++;
  25. const InstPtr& jumpInst = insts[pos];
  26. ASSERT_EQ(jumpInst->opcode_, opCode);
  27. ASSERT_EQ(jumpInst->params_.size(), paramsSize);
  28. const uint32 lastNopAddr = Is3Nops(insts, pos);
  29. ASSERT_EQ(jumpInst->GetDestAddress(), lastNopAddr);
  30. }
  31. // Verify next instructions is a NOP and return address of final NOP
  32. static uint32 IsNop(InstVec& insts, uint32& pos)
  33. {
  34. pos++;
  35. EXPECT_EQ(insts[pos]->opcode_, eOpcodes::NOP);
  36. EXPECT_EQ(insts[pos]->params_.size(), 0);
  37. return insts[pos]->_address;
  38. }
  39. // For a backwards jump we start with 3 NOPS and the last instruction is the jump itself which
  40. // should be targeting the second/middle NOP
  41. static void CheckBackwardJump(eOpcodes opCode, size_t paramsSize, InstVec& insts, uint32& pos)
  42. {
  43. IsNop(insts, pos);
  44. // Second is the target, so check is NOP & grab addr
  45. const uint32 firstNopAddr = IsNop(insts, pos);
  46. IsNop(insts, pos);
  47. // Grab the final instruction, the jump itself
  48. pos++;
  49. const InstPtr& jumpInst = insts[pos];
  50. ASSERT_EQ(jumpInst->opcode_, opCode);
  51. ASSERT_EQ(jumpInst->params_.size(), paramsSize);
  52. ASSERT_EQ(jumpInst->GetDestAddress(), firstNopAddr);
  53. }
  54. TEST(FF7Field, ControlFlow)
  55. {
  56. InstVec insts;
  57. DummyFormatter formatter;
  58. FieldEngine engine(formatter, "test");
  59. auto d = engine.GetDisassembler(insts);
  60. d->open("decompiler/test/ff7_control_flow_test.dat");
  61. d->disassemble();
  62. d->dumpDisassembly(std::cout);
  63. std::cout << std::endl;
  64. uint32 pos = 0;
  65. ASSERT_EQ(insts[pos]->opcode_, eOpcodes::RET);
  66. ASSERT_EQ(insts[pos]->params_.size(), 0);
  67. CheckForwardJump(eOpcodes::IFUB, 6, insts, pos);
  68. CheckForwardJump(eOpcodes::IFSWL, 6, insts, pos);
  69. CheckForwardJump(eOpcodes::JMPF, 1, insts, pos);
  70. CheckForwardJump(eOpcodes::JMPFL, 1, insts, pos);
  71. CheckForwardJump(eOpcodes::IFKEY, 2, insts, pos);
  72. CheckForwardJump(eOpcodes::IFKEYON, 2, insts, pos);
  73. CheckForwardJump(eOpcodes::IFKEYOFF, 2, insts, pos);
  74. CheckForwardJump(eOpcodes::IFPRTYQ, 2, insts, pos);
  75. CheckForwardJump(eOpcodes::IFMEMBQ, 2, insts, pos);
  76. CheckBackwardJump(eOpcodes::JMPB, 1, insts, pos);
  77. CheckBackwardJump(eOpcodes::JMPBL, 1, insts, pos);
  78. }