ff7_field_control_flow_test.cpp 3.1 KB

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