decompiler_codegen.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /* ScummVM Tools
  2. *
  3. * ScummVM Tools is the legal property of its developers, whose
  4. * names are too numerous to list here. Please refer to the
  5. * COPYRIGHT file distributed with this source distribution.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. */
  21. #include "decompiler_codegen.h"
  22. #include "decompiler_engine.h"
  23. #include <algorithm>
  24. #include <iostream>
  25. #include <set>
  26. #include <boost/format.hpp>
  27. #include "make_unique.h"
  28. #define GET(vertex) (boost::get(boost::vertex_name, _g, vertex))
  29. #define GET_EDGE(edge) (boost::get(boost::edge_attribute, _g, edge))
  30. void CodeGenerator::onBeforeStartFunction(const Function&)
  31. {
  32. }
  33. void CodeGenerator::onEndFunction(const Function &)
  34. {
  35. addOutputLine("}", true, false);
  36. }
  37. std::string CodeGenerator::constructFuncSignature(const Function &)
  38. {
  39. return "";
  40. }
  41. std::string CodeGenerator::indentString(std::string s)
  42. {
  43. std::stringstream stream;
  44. stream << std::string(kIndentAmount * _indentLevel, ' ') << s;
  45. return stream.str();
  46. }
  47. CodeGenerator::CodeGenerator(Engine *engine, std::ostream &output, ArgOrder binOrder, ArgOrder callOrder)
  48. : _output(output),
  49. _binOrder(binOrder),
  50. _callOrder(callOrder)
  51. {
  52. _engine = engine;
  53. _indentLevel = 0;
  54. mTargetLang = std::make_unique<CTargetLanguage>();
  55. }
  56. typedef std::pair<GraphVertex, ValueStack> DFSEntry;
  57. void CodeGenerator::generatePass(InstVec& insts, const Graph& g)
  58. {
  59. _g = g;
  60. for (FuncMap::iterator fn = _engine->_functions.begin(); fn != _engine->_functions.end(); ++fn)
  61. {
  62. while (!_stack.empty())
  63. {
  64. _stack.pop();
  65. }
  66. GraphVertex entryPoint = fn->second._v;
  67. std::string funcSignature = constructFuncSignature(fn->second);
  68. // Write the function start
  69. bool printFuncSignature = !funcSignature.empty();
  70. if (printFuncSignature)
  71. {
  72. mCurGroup = GET(entryPoint);
  73. if (!(fn == _engine->_functions.begin()))
  74. {
  75. addOutputLine("");
  76. }
  77. onBeforeStartFunction(fn->second);
  78. addOutputLine(funcSignature, false, true);
  79. onStartFunction(fn->second);
  80. }
  81. GroupPtr lastGroup = GET(entryPoint);
  82. // DFS from entry point to process each vertex
  83. Stack<DFSEntry> dfsStack;
  84. std::set<GraphVertex> seen;
  85. dfsStack.push(DFSEntry(entryPoint, ValueStack()));
  86. seen.insert(entryPoint);
  87. while (!dfsStack.empty())
  88. {
  89. DFSEntry e = dfsStack.pop();
  90. GroupPtr tmp = GET(e.first);
  91. if ((*tmp->_start)->_address > (*lastGroup->_start)->_address)
  92. {
  93. lastGroup = tmp;
  94. }
  95. _stack = e.second;
  96. GraphVertex v = e.first;
  97. process(fn->second, insts, v);
  98. OutEdgeRange r = boost::out_edges(v, _g);
  99. for (OutEdgeIterator i = r.first; i != r.second; ++i)
  100. {
  101. GraphVertex target = boost::target(*i, _g);
  102. if (seen.find(target) == seen.end())
  103. {
  104. dfsStack.push(DFSEntry(target, _stack));
  105. seen.insert(target);
  106. }
  107. }
  108. }
  109. // Write the function end
  110. if (printFuncSignature)
  111. {
  112. mCurGroup = lastGroup;
  113. onEndFunction(fn->second);
  114. }
  115. // Print output
  116. GroupPtr p = GET(entryPoint);
  117. while (p != NULL)
  118. {
  119. for (auto it = p->_code.begin(); it != p->_code.end(); ++it)
  120. {
  121. if (it->_unindentBefore)
  122. {
  123. assert(_indentLevel > 0);
  124. _indentLevel--;
  125. }
  126. if (OutputOnlyRequiredLabels())
  127. {
  128. _output << indentString(it->_line) << std::endl;
  129. }
  130. else
  131. {
  132. _output << boost::format("%08X: %s") % (*p->_start)->_address % indentString(it->_line) << std::endl;
  133. }
  134. if (it->_indentAfter)
  135. {
  136. _indentLevel++;
  137. }
  138. }
  139. p = p->_next;
  140. }
  141. }
  142. }
  143. void CodeGenerator::generate(InstVec& insts, const Graph &g)
  144. {
  145. if (OutputOnlyRequiredLabels())
  146. {
  147. // Call twice, once where no output is generated but instructions are
  148. // marked as "needs label", then a 2nd time to actually output the code
  149. mIsLabelPass = true;
  150. generatePass(insts, g);
  151. }
  152. mIsLabelPass = false;
  153. generatePass(insts, g);
  154. }
  155. void CodeGenerator::addOutputLine(std::string s, bool unindentBefore, bool indentAfter)
  156. {
  157. // We don't generate output in the labels pass, we just find instructions that
  158. // require a label to be outputted
  159. if (!mIsLabelPass)
  160. {
  161. mCurGroup->_code.push_back(CodeLine(s, unindentBefore, indentAfter));
  162. }
  163. }
  164. void CodeGenerator::writeAssignment(ValuePtr dst, ValuePtr src)
  165. {
  166. std::stringstream s;
  167. s << dst << " = " << src << mTargetLang->LineTerminator();
  168. addOutputLine(s.str());
  169. }
  170. void CodeGenerator::process(Function& func, InstVec& insts, GraphVertex v)
  171. {
  172. _curVertex = v;
  173. mCurGroup = GET(v);
  174. // Check if we should add else start
  175. if (mCurGroup->_startElse)
  176. {
  177. addOutputLine(mTargetLang->EndBlock(ITargetLanaguge::eToElseBlock) + " " + mTargetLang->Else() + " " + mTargetLang->StartBlock(ITargetLanaguge::eBeginElse), true, true);
  178. }
  179. // Check ingoing edges to see if we want to add any extra output
  180. InEdgeRange ier = boost::in_edges(v, _g);
  181. for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie)
  182. {
  183. GraphVertex in = boost::source(*ie, _g);
  184. GroupPtr inGroup = GET(in);
  185. if (!boost::get(boost::edge_attribute, _g, *ie)._isJump || inGroup->_stackLevel == -1)
  186. {
  187. continue;
  188. }
  189. switch (inGroup->_type)
  190. {
  191. case kDoWhileCondGroupType:
  192. addOutputLine(mTargetLang->DoLoopHeader(), false, true);
  193. break;
  194. case kIfCondGroupType:
  195. if (!mCurGroup->_startElse)
  196. {
  197. addOutputLine(mTargetLang->EndBlock(ITargetLanaguge::eEndOfIf), true, false);
  198. }
  199. break;
  200. case kWhileCondGroupType:
  201. addOutputLine(mTargetLang->EndBlock(ITargetLanaguge::eEndOfWhile), true, false);
  202. break;
  203. default:
  204. break;
  205. }
  206. }
  207. ConstInstIterator it = mCurGroup->_start;
  208. do
  209. {
  210. // If we only want to write labels that targets of goto's then check if this is the pass
  211. // after we've setup mLabelRequired on each instruction. If this is set then it needs a label
  212. // so write one out.
  213. if (OutputOnlyRequiredLabels() && !mIsLabelPass && (*it)->mLabelRequired)
  214. {
  215. addOutputLine(mTargetLang->Label((*it)->_address));
  216. }
  217. processInst(func, insts, *it);
  218. } while (it++ != mCurGroup->_end);
  219. // Add else end if necessary
  220. for (ElseEndIterator elseIt = mCurGroup->_endElse.begin(); elseIt != mCurGroup->_endElse.end(); ++elseIt)
  221. {
  222. if (!(*elseIt)->_coalescedElse)
  223. {
  224. addOutputLine(mTargetLang->EndBlock(ITargetLanaguge::eEndIfElseChain), true, false);
  225. }
  226. }
  227. }
  228. void CodeGenerator::processUncondJumpInst(Function& func, InstVec& insts, const InstPtr inst)
  229. {
  230. switch (mCurGroup->_type)
  231. {
  232. case kBreakGroupType:
  233. addOutputLine(mTargetLang->LoopBreak());
  234. break;
  235. case kContinueGroupType:
  236. addOutputLine(mTargetLang->LoopContinue());
  237. break;
  238. default: // Might be a goto
  239. {
  240. bool printJump = true;
  241. OutEdgeRange jumpTargets = boost::out_edges(_curVertex, _g);
  242. for (OutEdgeIterator target = jumpTargets.first; target != jumpTargets.second && printJump; ++target)
  243. {
  244. Group* next = mCurGroup->_next;
  245. if (next)
  246. {
  247. // Don't output jump to next vertex
  248. if (boost::target(*target, _g) == next->_vertex)
  249. {
  250. printJump = false;
  251. break;
  252. }
  253. // Don't output jump if next vertex starts an else block
  254. if (next->_startElse)
  255. {
  256. printJump = false;
  257. break;
  258. }
  259. OutEdgeRange targetR = boost::out_edges(boost::target(*target, _g), _g);
  260. for (OutEdgeIterator targetE = targetR.first; targetE != targetR.second; ++targetE)
  261. {
  262. // Don't output jump to while loop that has jump to next vertex
  263. if (boost::target(*targetE, _g) == next->_vertex)
  264. {
  265. printJump = false;
  266. }
  267. }
  268. if (printJump)
  269. {
  270. // Check if this instruction is the last instruction in the function
  271. // and its an uncond jump
  272. if (mCurGroup->_type == kDoWhileCondGroupType && inst->_address == func.mEndAddr && inst->isUncondJump())
  273. {
  274. printJump = false;
  275. addOutputLine(mTargetLang->DoLoopFooter(true) + "true" + mTargetLang->DoLoopFooter(false), true, false);
  276. }
  277. }
  278. }
  279. }
  280. if (printJump)
  281. {
  282. const uint32 dstAddr = inst->getDestAddress();
  283. if (mIsLabelPass)
  284. {
  285. // Mark the goto target
  286. for (auto& i : insts)
  287. {
  288. if (i->_address == dstAddr)
  289. {
  290. i->mLabelRequired = true;
  291. break;
  292. }
  293. }
  294. }
  295. addOutputLine(mTargetLang->Goto(dstAddr));
  296. }
  297. }
  298. break;
  299. }
  300. }
  301. void CodeGenerator::writeFunctionCall(std::string functionName, std::string paramsFormat, const std::vector<ValuePtr>& params)
  302. {
  303. std::string strFuncCall = functionName + mTargetLang->FunctionCallBegin();
  304. const char* str = paramsFormat.c_str();
  305. int paramIndex = 0;
  306. while (*str)
  307. {
  308. bool skipArgument = false;
  309. switch (*str)
  310. {
  311. case 'b':
  312. strFuncCall += params[paramIndex]->getUnsigned() ? "true" : "false";
  313. break;
  314. case 'n':
  315. strFuncCall += std::to_string(params[paramIndex]->getUnsigned());
  316. break;
  317. case 'f':
  318. strFuncCall += std::to_string(static_cast<float>(params[paramIndex]->getUnsigned()) / 30.0f);
  319. break;
  320. case '_': // Ignore param
  321. skipArgument = true;
  322. break;
  323. default:
  324. throw std::runtime_error("Unknown param type");
  325. break;
  326. }
  327. paramIndex++;
  328. str++;
  329. if (*str)
  330. {
  331. // There is another param
  332. if (!skipArgument)
  333. {
  334. strFuncCall += mTargetLang->FunctionCallArgumentSeperator() + " ";
  335. }
  336. }
  337. }
  338. strFuncCall += mTargetLang->FunctionCallEnd();
  339. addOutputLine(strFuncCall);
  340. }
  341. void CodeGenerator::processCondJumpInst(const InstPtr inst)
  342. {
  343. std::stringstream s;
  344. switch (mCurGroup->_type)
  345. {
  346. case kIfCondGroupType:
  347. if (mCurGroup->_startElse && mCurGroup->_code.size() == 1)
  348. {
  349. OutEdgeRange oer = boost::out_edges(_curVertex, _g);
  350. bool coalesceElse = false;
  351. for (OutEdgeIterator oe = oer.first; oe != oer.second; ++oe)
  352. {
  353. GroupPtr oGr = GET(boost::target(*oe, _g))->_prev;
  354. if (std::find(oGr->_endElse.begin(), oGr->_endElse.end(), mCurGroup.get()) != oGr->_endElse.end())
  355. {
  356. coalesceElse = true;
  357. }
  358. }
  359. if (coalesceElse)
  360. {
  361. mCurGroup->_code.clear();
  362. mCurGroup->_coalescedElse = true;
  363. s << mTargetLang->EndBlock(ITargetLanaguge::eToElseBlock) << " " << mTargetLang->Else() << " ";
  364. }
  365. }
  366. s << mTargetLang->If(true) << _stack.pop()->negate() << mTargetLang->If(false);
  367. addOutputLine(s.str(), mCurGroup->_coalescedElse, true);
  368. break;
  369. case kWhileCondGroupType:
  370. s << mTargetLang->WhileHeader(true) << _stack.pop()->negate() << mTargetLang->WhileHeader(false) << " " << mTargetLang->StartBlock(ITargetLanaguge::eBeginWhile);
  371. addOutputLine(s.str(), false, true);
  372. break;
  373. case kDoWhileCondGroupType:
  374. s << mTargetLang->EndBlock(ITargetLanaguge::eEndWhile) << " " << mTargetLang->WhileHeader(true) << _stack.pop() << mTargetLang->WhileHeader(false);
  375. addOutputLine(s.str(), true, false);
  376. break;
  377. default:
  378. break;
  379. }
  380. }
  381. void CodeGenerator::processInst(Function& func, InstVec& insts, const InstPtr inst)
  382. {
  383. inst->processInst(func, _stack, _engine, this);
  384. if (inst->isCondJump())
  385. {
  386. processCondJumpInst(inst);
  387. }
  388. else if (inst->isUncondJump())
  389. {
  390. processUncondJumpInst(func, insts, inst);
  391. }
  392. }
  393. void CodeGenerator::addArg(ValuePtr p)
  394. {
  395. if (_callOrder == kFIFOArgOrder)
  396. _argList.push_front(p);
  397. else if (_callOrder == kLIFOArgOrder)
  398. _argList.push_back(p);
  399. }
  400. void CodeGenerator::processSpecialMetadata(const InstPtr inst, char c, int)
  401. {
  402. switch (c)
  403. {
  404. case 'p':
  405. addArg(_stack.pop());
  406. break;
  407. default:
  408. std::cerr << boost::format("WARNING: Unknown character in metadata: %c\n") % c;
  409. break;
  410. }
  411. }