ff7_field_control_flow_test.cpp 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  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 "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, FF7::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(FF7::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, FF7::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(FF7::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. FF7::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, FF7::eOpcodes::RET);
  66. ASSERT_EQ(insts[pos]->_params.size(), 0);
  67. CheckForwardJump(FF7::eOpcodes::IFUB, 6, insts, pos);
  68. CheckForwardJump(FF7::eOpcodes::IFSWL, 6, insts, pos);
  69. CheckForwardJump(FF7::eOpcodes::JMPF, 1, insts, pos);
  70. CheckForwardJump(FF7::eOpcodes::JMPFL, 1, insts, pos);
  71. CheckForwardJump(FF7::eOpcodes::IFKEY, 2, insts, pos);
  72. CheckForwardJump(FF7::eOpcodes::IFKEYON, 2, insts, pos);
  73. CheckForwardJump(FF7::eOpcodes::IFKEYOFF, 2, insts, pos);
  74. CheckForwardJump(FF7::eOpcodes::IFPRTYQ, 2, insts, pos);
  75. CheckForwardJump(FF7::eOpcodes::IFMEMBQ, 2, insts, pos);
  76. CheckBackwardJump(FF7::eOpcodes::JMPB, 1, insts, pos);
  77. CheckBackwardJump(FF7::eOpcodes::JMPBL, 1, insts, pos);
  78. }