Graph.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  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. #pragma once
  16. #include <ostream>
  17. #include <utility>
  18. #include <vector>
  19. #include <boost/format.hpp>
  20. #include <boost/version.hpp>
  21. #ifdef _MSC_VER
  22. #pragma warning (push)
  23. #pragma warning(disable:4512)
  24. #pragma warning(disable:4100)
  25. #endif
  26. #include <boost/graph/graph_traits.hpp>
  27. #include <boost/graph/adjacency_list.hpp>
  28. #include <boost/graph/graphviz.hpp>
  29. #ifdef _MSC_VER
  30. #pragma warning (pop)
  31. #endif
  32. #include <boost/intrusive_ptr.hpp>
  33. #include "instruction/Instruction.h"
  34. #include "RefCounted.h"
  35. /**
  36. * Enumeration representing the different kinds of groups.
  37. */
  38. enum GROUP_TYPE {
  39. /**
  40. * Normal group.
  41. */
  42. GROUP_TYPE_NORMAL,
  43. /**
  44. * Group is the condition check for a while-loop.
  45. */
  46. GROUP_TYPE_WHILE,
  47. /**
  48. * Group is the condition check for a do-while-loop.
  49. */
  50. GROUP_TYPE_DO_WHILE,
  51. /**
  52. * Group is the condition check for an if.
  53. */
  54. GROUP_TYPE_IF,
  55. /**
  56. * Group is a break.
  57. */
  58. GROUP_TYPE_BREAK,
  59. /**
  60. * Group is a continue.
  61. */
  62. GROUP_TYPE_CONTINUE
  63. };
  64. struct Group;
  65. typedef boost::intrusive_ptr<Group> GroupPtr;
  66. typedef boost::property<boost::vertex_name_t, GroupPtr> GroupProperty;
  67. typedef boost::property<boost::vertex_index_t, int, GroupProperty> GraphProperty;
  68. /**
  69. * Structure representing whether or not an edge is a jump.
  70. */
  71. struct IsJump {
  72. /**
  73. * Whether or not the edge is a jump.
  74. */
  75. bool is_jump = false;
  76. /**
  77. * Parameterless constructor.
  78. *
  79. * Required for use with STL and Boost, should not be called manually.
  80. */
  81. IsJump();
  82. /**
  83. * Constructor.
  84. *
  85. * @param[in] jump Whether or not the edge is a jump.
  86. */
  87. IsJump(bool jump);
  88. /**
  89. * Output edge information as a graphviz edge property.
  90. *
  91. * @param[out] output The stream to output to.
  92. * @param[in] is_jump The IsJump to output.
  93. * @return The stream used for output.
  94. */
  95. friend std::ostream &operator<<(std::ostream &output, IsJump is_jump){
  96. if (is_jump.is_jump) output << "empty";
  97. else output << "normal";
  98. return output;
  99. }
  100. };
  101. namespace boost {
  102. /**
  103. * Property writer for the IsJump property.
  104. */
  105. template <class Name> class ArrowheadWriter{
  106. public:
  107. /**
  108. * Constructor.
  109. *
  110. * @param[in] name The name of the attribute to use.
  111. */
  112. explicit ArrowheadWriter(Name name): name(name){}
  113. /**
  114. * Outputs the arrowhead edge property.
  115. *
  116. * @param[out] out The stream to output to.
  117. * @param[in] v The vertex or edge to output the attribute for.
  118. */
  119. template <class VertexOrEdge> void operator()(
  120. std::ostream& out, const VertexOrEdge& v
  121. ) const {
  122. out << "[arrowhead=\"" << get(name, v) << "\"]";
  123. }
  124. private:
  125. /**
  126. * The name of the attribute to use.
  127. */
  128. Name name;
  129. };
  130. /**
  131. * Creates an arrowhead property writer.
  132. *
  133. * @param[in] n The name of the attribute to use.
  134. */
  135. template <class Name> inline ArrowheadWriter<Name> MakeArrowheadWriter(Name n) {
  136. return ArrowheadWriter<Name>(n);
  137. }
  138. }
  139. typedef boost::property<boost::edge_attribute_t, IsJump> EdgeProperty;
  140. typedef boost::adjacency_list<boost::setS, boost::listS, boost::bidirectionalS, GraphProperty, EdgeProperty> Graph;
  141. typedef Graph::vertex_descriptor GraphVertex;
  142. typedef Graph::vertex_iterator VertexIterator;
  143. typedef Graph::edge_descriptor GraphEdge;
  144. typedef Graph::out_edge_iterator OutEdgeIterator;
  145. typedef Graph::in_edge_iterator InEdgeIterator;
  146. typedef std::pair<VertexIterator, VertexIterator> VertexRange;
  147. typedef std::pair<OutEdgeIterator, OutEdgeIterator> OutEdgeRange;
  148. typedef std::pair<InEdgeIterator, InEdgeIterator> InEdgeRange;
  149. /**
  150. * Structure representing a line of code.
  151. */
  152. struct CodeLine {
  153. /**
  154. * The line of code.
  155. */
  156. std::string line = "0";
  157. /**
  158. * Whether or not to add an indentation level before outputting the line.
  159. */
  160. bool unindent_before = false;
  161. /**
  162. * Whether to remove an indentation level after outputting the line.
  163. */
  164. bool indent_after = false;
  165. /**
  166. * Constructor for CodeLine.
  167. *
  168. * @param[in] line The line of code.
  169. * @param[in] unindent_before Whether or not to remove an indentation
  170. * level before the line. Defaults to false.
  171. * @param[in] indent_after Whether or not to add an indentation level
  172. * after the line. Defaults to false.
  173. */
  174. CodeLine(const std::string& line, bool unindent_before, bool indent_after);
  175. };
  176. typedef std::vector<Group *> ElseEnds; // Weak references to groups ending else blocks.
  177. typedef ElseEnds::iterator ElseEndIterator;
  178. /**
  179. * Structure representing a group of instructions.
  180. */
  181. struct Group : public RefCounted {
  182. /**
  183. * Vertex the group belongs to.
  184. */
  185. GraphVertex vertex;
  186. /**
  187. * First instruction in the group.
  188. */
  189. InstIterator start;
  190. /**
  191. * Last instruction in the group.
  192. */
  193. InstIterator end;
  194. /**
  195. * Level of the stack upon entry.
  196. */
  197. int stack_level;
  198. /**
  199. * Type of the group.
  200. */
  201. GROUP_TYPE type;
  202. /**
  203. * Group is start of an else block.
  204. */
  205. bool start_else;
  206. /**
  207. * Group is end of an else block.
  208. */
  209. ElseEnds end_else;
  210. /**
  211. * Pointer to the previous group, when ordered by address.
  212. *
  213. * Used for short-circuit analysis.
  214. */
  215. Group *prev;
  216. /**
  217. * Pointer to the next group, when ordered by address.
  218. */
  219. Group *next;
  220. /**
  221. * Decompiled lines of code.
  222. */
  223. std::vector<CodeLine> code;
  224. /**
  225. * Indicates if an starting else coalesces with another block.
  226. *
  227. * True if an else starting has been coalesced with another block
  228. * (e.g. "else if"). If true, an else starting here should not be
  229. * closed explicitly, but left to the other block.
  230. */
  231. bool coalesced_else;
  232. /**
  233. * Parameterless constructor.
  234. *
  235. * Required for use with STL and Boost, should not be called manually.
  236. */
  237. Group();
  238. /**
  239. * Constructor.
  240. *
  241. * @param[in] vertex The vertex the group belongs to.
  242. * @param[in] start First instruction in the group.
  243. * @param[in] end Last instruction in the group.
  244. * @param[in] prev Pointer to the previous group, when ordered by
  245. * address.
  246. */
  247. Group(GraphVertex vertex, InstIterator start, InstIterator end, GroupPtr prev);
  248. /**
  249. * Output a group to an stream as a graphviz label.
  250. *
  251. * @param[out] output The stream to output to.
  252. * @param[in] group The Group to output.
  253. * @return The stream used for output.
  254. */
  255. friend std::ostream &operator<<(std::ostream &output, GroupPtr group){
  256. output << "{Block type: ";
  257. switch(group->type) {
  258. case GROUP_TYPE_NORMAL: output << "Normal"; break;
  259. case GROUP_TYPE_WHILE: output << "While condition"; break;
  260. case GROUP_TYPE_DO_WHILE: output << "Do-while condition"; break;
  261. case GROUP_TYPE_IF: output << "If condition"; break;
  262. case GROUP_TYPE_BREAK: output << "Break"; break;
  263. case GROUP_TYPE_CONTINUE: output << "Continue"; break;
  264. }
  265. output << "\\n";
  266. output << "Expected stack level: " << group->stack_level << "\\n";
  267. if (group->start_else) output << "Start of else\\n";
  268. for (ElseEndIterator it = group->end_else.begin(); it != group->end_else.end(); ++ it)
  269. output << boost::format("End of else at %08x\\n") % (*(*it)->start)->GetAddress();
  270. output << "|";
  271. ConstInstIterator inst = group->start;
  272. do {
  273. std::stringstream stream;
  274. stream << *inst;
  275. #if (BOOST_VERSION >= 104500)
  276. output << stream.str();
  277. #else
  278. std::string s = stream.str();
  279. for (std::string::iterator it = s.begin(); it != s.end(); ++it)
  280. if (*it == '"') output << "\\\"";
  281. else if (*it == '|') output << "\\|";
  282. else if (*it == '{') output << "\\{";
  283. else if (*it == '}') output << "\\}";
  284. else output << *it;
  285. #endif
  286. output << "\\n";
  287. } while (inst ++ != group->end);
  288. output << "}";
  289. return output;
  290. }
  291. };
  292. class Engine;
  293. /**
  294. * Type used to set properties for dot output.
  295. */
  296. struct GraphProperties {
  297. public:
  298. /**
  299. * Constructor.
  300. *
  301. * @param[in] engine The engine with function information for the
  302. * script.
  303. * @param[in] graph he graph for the script.
  304. */
  305. GraphProperties(Engine *engine, const Graph &graph);
  306. /**
  307. * Copy constructor.
  308. *
  309. * @param[in] rhs Graph properties to copy.
  310. */
  311. GraphProperties(const GraphProperties& rhs);
  312. /**
  313. * Copy constructor.
  314. *
  315. * @param[in] rhs Graph properties to copy.
  316. */
  317. GraphProperties& operator = (const GraphProperties& rhs);
  318. /**
  319. * Print properties of the graph.
  320. *
  321. * Called by write_graphviz from Boost.Graph
  322. *
  323. * @param[out] out The stream write_graphviz is writing to.
  324. */
  325. void operator()(std::ostream& out) const;
  326. private:
  327. /**
  328. * Engine containing function information for the script.
  329. */
  330. Engine *engine;
  331. /**
  332. * Pointer to the to the graph for the script.
  333. */
  334. const Graph* graph;
  335. };