CodeGenerator.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*
  2. * Copyright (C) 2022 The V-Gears Team
  3. *
  4. * This file is part of V-Gears
  5. *
  6. * V-Gears is free software: you can redistribute it and/or modify it under
  7. * terms of the GNU General Public License as published by the Free Software
  8. * Foundation, version 3.0 (GPLv3) of the License.
  9. *
  10. * V-Gears is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <algorithm>
  16. #include <iostream>
  17. #include <set>
  18. #include <boost/format.hpp>
  19. #include "decompiler/CodeGenerator.h"
  20. #include "decompiler/Engine.h"
  21. #include "decompiler/LuaLanguage.h"
  22. #define GET(vertex) (boost::get(boost::vertex_name, graph_, vertex))
  23. #define GET_EDGE(edge) (boost::get(boost::edge_attribute, graph_, edge))
  24. CodeGenerator::CodeGenerator(Engine *engine, std::ostream &output, ARGUMENT_ORDER bin_order, ARGUMENT_ORDER call_order):
  25. output_(output), bin_order_(bin_order), call_order_(call_order)
  26. {
  27. engine_ = engine;
  28. indent_level_ = 0;
  29. target_lang_ = std::make_unique<LuaLanguage>();
  30. }
  31. CodeGenerator::~CodeGenerator(){}
  32. LuaLanguage& CodeGenerator::GetLanguage(){
  33. assert(target_lang_);
  34. return *target_lang_;
  35. }
  36. void CodeGenerator::WriteFunctionCall(
  37. std::string function_name, std::string param_format, const std::vector<ValuePtr>& params
  38. ){
  39. std::string func_call = function_name + target_lang_->FunctionCallBegin();
  40. const char* format = param_format.c_str();
  41. int param_index = 0;
  42. while (*format){
  43. bool skip_argument = false;
  44. switch (*format){
  45. case 'b': func_call += params[param_index]->GetUnsigned() ? "true" : "false"; break;
  46. case 'n': func_call += std::to_string(params[param_index]->GetUnsigned()); break;
  47. case 'f':
  48. func_call += std::to_string(static_cast<float>(params[param_index]->GetUnsigned()) / 30.0f);
  49. break;
  50. case '_': skip_argument = true; break;// Ignore param
  51. default: throw std::runtime_error("Unknown param type");
  52. }
  53. param_index ++;
  54. format ++;
  55. if (*format) {
  56. // There is another param.
  57. if (!skip_argument) func_call += target_lang_->FunctionCallArgumentSeperator() + " ";
  58. }
  59. }
  60. func_call += target_lang_->FunctionCallEnd();
  61. AddOutputLine(func_call);
  62. }
  63. void CodeGenerator::Generate(InstVec& insts, const Graph &graph){
  64. if (OutputOnlyRequiredLabels()){
  65. // Call twice, once where no output is generated but instructions are
  66. // marked as "needs label", then a 2nd time to actually output the code
  67. is_label_pass_ = true;
  68. GeneratePass(insts, graph);
  69. }
  70. is_label_pass_ = false;
  71. GeneratePass(insts, graph);
  72. }
  73. void CodeGenerator::AddOutputLine(std::string line, bool unindent_before, bool indent_after){
  74. // Don't generate output in the labels pass, just find
  75. // instructions that require a label to be outputted.
  76. if (!is_label_pass_) cur_group_->code.push_back(CodeLine(line, unindent_before, indent_after));
  77. }
  78. void CodeGenerator::WriteTodo(std::string class_name, std::string instruction){
  79. AddOutputLine("-- UNIMPLMENTED INSTRUCTION: \"" + instruction + "\")");
  80. }
  81. void CodeGenerator::WriteAssignment(ValuePtr dst, ValuePtr src) {
  82. std::stringstream s;
  83. s << dst << " = " << src << target_lang_->LineTerminator();
  84. AddOutputLine(s.str());
  85. }
  86. void CodeGenerator::AddArg(ValuePtr arg) {
  87. if (call_order_ == FIFO_ARGUMENT_ORDER) arg_list_.push_front(arg);
  88. else if (call_order_ == LIFO_ARGUMENT_ORDER) arg_list_.push_back(arg);
  89. }
  90. void CodeGenerator::ProcessSpecialMetadata(const InstPtr inst, char c, int) {
  91. switch (c){
  92. case 'p': AddArg(stack_.Pop()); break;
  93. default:
  94. std::cerr << boost::format("WARNING: Unknown character in metadata: %c\n") % c;
  95. break;
  96. }
  97. }
  98. ValueList CodeGenerator::GetArgList(){return arg_list_;}
  99. ARGUMENT_ORDER CodeGenerator::GetBinaryOrder(){return bin_order_;}
  100. void CodeGenerator::ProcessInst(Function& function, InstVec& insts, const InstPtr inst){
  101. inst->ProcessInst(function, stack_, engine_, this);
  102. if (inst->IsCondJump()) ProcessCondJumpInst(inst);
  103. else if (inst->IsUncondJump()) ProcessUncondJumpInst(function, insts, inst);
  104. }
  105. void CodeGenerator::ProcessUncondJumpInst(Function& function, InstVec& insts, const InstPtr inst){
  106. switch (cur_group_->type){
  107. case GROUP_TYPE_BREAK: AddOutputLine(target_lang_->LoopBreak()); break;
  108. case GROUP_TYPE_CONTINUE: AddOutputLine(target_lang_->LoopContinue()); break;
  109. default: // Might be a goto.
  110. {
  111. bool print_jump = true;
  112. OutEdgeRange jump_targets = boost::out_edges(cur_vertex_, graph_);
  113. for (
  114. OutEdgeIterator target = jump_targets.first; target != jump_targets.second && print_jump; ++ target
  115. ){
  116. Group* next = cur_group_->next;
  117. if (next){
  118. // Don't output jump to next vertex.
  119. if (boost::target(*target, graph_) == next->vertex){
  120. print_jump = false;
  121. break;
  122. }
  123. // Don't output jump if next vertex starts an else block.
  124. if (next->start_else){
  125. print_jump = false;
  126. break;
  127. }
  128. OutEdgeRange target_range = boost::out_edges(
  129. boost::target(*target, graph_), graph_
  130. );
  131. for (
  132. OutEdgeIterator target_it = target_range.first; target_it != target_range.second; ++ target_it
  133. ){
  134. // Don't output jump to while loop that has jump to next vertex.
  135. if (boost::target(*target_it, graph_) == next->vertex) print_jump = false;
  136. }
  137. if (print_jump){
  138. // Check if this instruction is the last instruction in the function
  139. // and its an uncond jump.
  140. if (
  141. cur_group_->type == GROUP_TYPE_DO_WHILE && inst->GetAddress() == function.end_addr
  142. && inst->IsUncondJump()
  143. ){
  144. print_jump = false;
  145. AddOutputLine(
  146. target_lang_->DoLoopFooter(true) + "true"
  147. + target_lang_->DoLoopFooter(false), true, false
  148. );
  149. }
  150. }
  151. }
  152. }
  153. if (print_jump){
  154. const uint32 dst_addr = inst->GetDestAddress();
  155. if (is_label_pass_){
  156. // Mark the goto target.
  157. for (auto& i : insts){
  158. if (i->GetAddress() == dst_addr){
  159. i->SetLabelRequired(true);
  160. break;
  161. }
  162. }
  163. }
  164. AddOutputLine(target_lang_->Goto(dst_addr));
  165. }
  166. }
  167. break;
  168. }
  169. }
  170. void CodeGenerator::ProcessCondJumpInst(const InstPtr inst){
  171. std::stringstream s;
  172. switch (cur_group_->type){
  173. case GROUP_TYPE_IF:
  174. if (cur_group_->start_else && cur_group_->code.size() == 1){
  175. OutEdgeRange oer = boost::out_edges(cur_vertex_, graph_);
  176. bool coalesce_else = false;
  177. for (OutEdgeIterator oe = oer.first; oe != oer.second; ++ oe){
  178. GroupPtr oGr = GET(boost::target(*oe, graph_))->prev;
  179. if (std::find(oGr->end_else.begin(), oGr->end_else.end(), cur_group_.get()) != oGr->end_else.end())
  180. coalesce_else = true;
  181. }
  182. if (coalesce_else){
  183. cur_group_->code.clear();
  184. cur_group_->coalesced_else = true;
  185. s << target_lang_->EndBlock(LuaLanguage::TO_ELSE_BLOCK)
  186. << " " << target_lang_->Else() << " ";
  187. }
  188. }
  189. s << target_lang_->If(true) << stack_.Pop()->Negate() << target_lang_->If(false);
  190. AddOutputLine(s.str(), cur_group_->coalesced_else, true);
  191. break;
  192. case GROUP_TYPE_WHILE:
  193. s << target_lang_->WhileHeader(true) << stack_.Pop()->Negate() << target_lang_->WhileHeader(false) << " "
  194. << target_lang_->StartBlock(LuaLanguage::BEGIN_WHILE);
  195. AddOutputLine(s.str(), false, true);
  196. break;
  197. case GROUP_TYPE_DO_WHILE:
  198. s << target_lang_->EndBlock(LuaLanguage::END_WHILE) << " "
  199. << target_lang_->WhileHeader(true) << stack_.Pop() << target_lang_->WhileHeader(false);
  200. AddOutputLine(s.str(), true, false);
  201. break;
  202. default:
  203. break;
  204. }
  205. }
  206. std::string CodeGenerator::IndentString(std::string s){
  207. std::stringstream stream;
  208. stream << std::string(INDENT_SPACES * indent_level_, ' ') << s;
  209. return stream.str();
  210. }
  211. std::string CodeGenerator::ConstructFuncSignature(const Function& function){return "";}
  212. void CodeGenerator::OnBeforeStartFunction(const Function& function){}
  213. void CodeGenerator::OnEndFunction(const Function& function){AddOutputLine("}", true, false);}
  214. void CodeGenerator::OnStartFunction(const Function& function){}
  215. bool CodeGenerator::OutputOnlyRequiredLabels() const{return false;}
  216. typedef std::pair<GraphVertex, ValueStack> DFSEntry;
  217. void CodeGenerator::GeneratePass(InstVec& insts, const Graph& graph){
  218. graph_ = graph;
  219. for (FuncMap::iterator fn = engine_->functions.begin(); fn != engine_->functions.end(); ++ fn){
  220. while (!stack_.IsEmpty()) stack_.Pop();
  221. GraphVertex entry_point = fn->second.vertex;
  222. std::string func_signature = ConstructFuncSignature(fn->second);
  223. // Write the function start.
  224. bool print_func_signature = !func_signature.empty();
  225. if (print_func_signature){
  226. cur_group_ = GET(entry_point);
  227. if (!(fn == engine_->functions.begin())) AddOutputLine("");
  228. OnBeforeStartFunction(fn->second);
  229. AddOutputLine(func_signature, false, true);
  230. OnStartFunction(fn->second);
  231. }
  232. GroupPtr last_group = GET(entry_point);
  233. // DFS from entry point to process each vertex.
  234. Stack<DFSEntry> dfs_stack;
  235. std::set<GraphVertex> seen;
  236. dfs_stack.Push(DFSEntry(entry_point, ValueStack()));
  237. seen.insert(entry_point);
  238. while (!dfs_stack.IsEmpty()){
  239. DFSEntry e = dfs_stack.Pop();
  240. GroupPtr tmp = GET(e.first);
  241. if ((*tmp->start)->GetAddress() > (*last_group->start)->GetAddress()) last_group = tmp;
  242. stack_ = e.second;
  243. GraphVertex v = e.first;
  244. Process(fn->second, insts, v);
  245. OutEdgeRange r = boost::out_edges(v, graph_);
  246. for (OutEdgeIterator i = r.first; i != r.second; ++ i){
  247. GraphVertex target = boost::target(*i, graph_);
  248. if (seen.find(target) == seen.end()){
  249. dfs_stack.Push(DFSEntry(target, stack_));
  250. seen.insert(target);
  251. }
  252. }
  253. }
  254. // Write the function end
  255. if (print_func_signature){
  256. cur_group_ = last_group;
  257. OnEndFunction(fn->second);
  258. }
  259. // Print output.
  260. GroupPtr p = GET(entry_point);
  261. while (p != NULL){
  262. for (auto it = p->code.begin(); it != p->code.end(); ++ it){
  263. if (it->unindent_before){
  264. assert(indent_level_ > 0);
  265. indent_level_--;
  266. }
  267. if (OutputOnlyRequiredLabels()) output_ << IndentString(it->line) << std::endl;
  268. else{
  269. output_ << (
  270. boost::format("%08X: %s") % (*p->start)->GetAddress() % IndentString(it->line)
  271. ) << std::endl;
  272. }
  273. if (it->indent_after) indent_level_++;
  274. }
  275. p = p->next;
  276. }
  277. }
  278. }
  279. void CodeGenerator::Process(Function& function, InstVec& insts, GraphVertex vertex){
  280. cur_vertex_ = vertex;
  281. cur_group_ = GET(vertex);
  282. // Check if we should add else start
  283. if (cur_group_->start_else){
  284. AddOutputLine(
  285. target_lang_->EndBlock(LuaLanguage::TO_ELSE_BLOCK) + " " + target_lang_->Else()
  286. + " " + target_lang_->StartBlock(LuaLanguage::BEGIN_ELSE), true, true
  287. );
  288. }
  289. // Check ingoing edges to see if we want to add any extra output
  290. InEdgeRange ier = boost::in_edges(vertex, graph_);
  291. for (InEdgeIterator ie = ier.first; ie != ier.second; ++ ie){
  292. GraphVertex in = boost::source(*ie, graph_);
  293. GroupPtr in_group = GET(in);
  294. if (!boost::get(boost::edge_attribute, graph_, *ie).is_jump || in_group->stack_level == -1) continue;
  295. switch (in_group->type){
  296. case GROUP_TYPE_DO_WHILE:
  297. AddOutputLine(target_lang_->DoLoopHeader(), false, true);
  298. break;
  299. case GROUP_TYPE_IF:
  300. if (!cur_group_->start_else) AddOutputLine(target_lang_->EndBlock(LuaLanguage::END_OF_IF), true, false);
  301. break;
  302. case GROUP_TYPE_WHILE:
  303. AddOutputLine(target_lang_->EndBlock(LuaLanguage::END_OF_WHILE), true, false);
  304. break;
  305. default:
  306. break;
  307. }
  308. }
  309. ConstInstIterator it = cur_group_->start;
  310. do{
  311. // If we only want to write labels that targets of goto's then check
  312. // if this is the pass after we've setup mLabelRequired on each
  313. // instruction. If this is set then it needs a label so write one out.
  314. if (OutputOnlyRequiredLabels() && !is_label_pass_ && (*it)->LabelRequired())
  315. AddOutputLine(target_lang_->Label((*it)->GetAddress()));
  316. ProcessInst(function, insts, *it);
  317. } while (it++ != cur_group_->end);
  318. // Add else end if necessary
  319. for (ElseEndIterator else_it = cur_group_->end_else.begin(); else_it != cur_group_->end_else.end(); ++ else_it){
  320. if (!(*else_it)->coalesced_else)
  321. AddOutputLine(target_lang_->EndBlock(LuaLanguage::END_OF_IF_ELSE_CHAIN), true, false);
  322. }
  323. }