ControlFlow.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  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/ControlFlow.h"
  20. #include "../../include/decompiler/Stack.h"
  21. /**
  22. * Adds a vertex to a group.
  23. *
  24. * @param vertex[in] Vertex to add.
  25. * @param group[in] Group to add the vertex to.
  26. */
  27. #define PUT(vertex, group) boost::put(boost::vertex_name, graph_, vertex, group);
  28. /**
  29. * Adds an edge to the graph.
  30. *
  31. * @param edge[in] The edge to add.
  32. * @param is_jump[in] Indicates if the edge is a jump.
  33. */
  34. #define PUT_EDGE(edge, is_jump) boost::put(boost::edge_attribute, graph_, edge, is_jump);
  35. /**
  36. * Adds a vertex to the graph.
  37. *
  38. * @param vertex[in] The vertex to add.
  39. * @param id[in] The vertext index.
  40. */
  41. #define PUT_ID(vertex, id) boost::put(boost::vertex_index, graph_, vertex, id);
  42. /**
  43. * Retrieves a vertex.
  44. *
  45. * @param vertex[in] The vertex.
  46. * @return The retrieved vertex.
  47. */
  48. #define GET(vertex) (boost::get(boost::vertex_name, graph_, vertex))
  49. /**
  50. * Retrieves an edge.
  51. *
  52. * @param edge[in] The edge.
  53. * @return The retrieved edge.
  54. */
  55. #define GET_EDGE(edge) (boost::get(boost::edge_attribute, graph_, edge))
  56. ControlFlow::ControlFlow(InstVec& insts, Engine& engine): insts_(insts),engine_(engine){
  57. // Automatically add a function if we're not supposed to look for more functions
  58. // and no functions are defined.
  59. // This avoids a special case for when no real functions exist in the script.
  60. if (engine_.functions.empty()){
  61. engine_.functions[(*insts.begin())->GetAddress()]= Function(
  62. (*insts.begin())->GetAddress(), (insts.back())->GetAddress()
  63. );
  64. }
  65. GroupPtr prev = NULL;
  66. int id = 0;
  67. // Create vertices.
  68. for (InstIterator it = insts.begin(); it != insts.end(); ++ it){
  69. GraphVertex cur = boost::add_vertex(graph_);
  70. addr_map_[(*it)->GetAddress()] = cur;
  71. PUT(cur, new Group(cur, it, it, prev));
  72. PUT_ID(cur, id);
  73. id ++;
  74. // Add reference to vertex if function starts here.
  75. if (engine_.functions.find((*it)->GetAddress()) != engine_.functions.end()){
  76. engine_.functions[(*it)->GetAddress()].vertex = cur;
  77. }
  78. prev = GET(cur);
  79. }
  80. // Add regular edges.
  81. FuncMap::iterator fn;
  82. GraphVertex last ={};
  83. bool add_edge = false;
  84. prev = NULL;
  85. for (InstIterator it = insts.begin(); it != insts.end(); ++it){
  86. if (engine_.functions.find((*it)->GetAddress()) != engine_.functions.end())
  87. add_edge = false;
  88. GraphVertex cur = Find(it);
  89. if (add_edge){
  90. GraphEdge e = boost::add_edge(last, cur, graph_).first;
  91. PUT_EDGE(e, false);
  92. }
  93. last = cur;
  94. add_edge = !((*it)->IsUncondJump() || (*it)->IsReturn());
  95. prev = GET(cur);
  96. }
  97. // Add jump edges.
  98. for (InstIterator it = insts.begin(); it != insts.end(); ++ it){
  99. if ((*it)->IsJump()){
  100. GraphEdge e = boost::add_edge(Find(it), Find((*it)->GetDestAddress()), graph_).first;
  101. PUT_EDGE(e, true);
  102. }
  103. }
  104. }
  105. const Graph& ControlFlow::GetGraph() const{return graph_;}
  106. GraphVertex ControlFlow::Find(const InstPtr inst){return addr_map_[inst->GetAddress()];}
  107. GraphVertex ControlFlow::Find(ConstInstIterator it){return addr_map_[(*it)->GetAddress()];}
  108. GraphVertex ControlFlow::Find(uint32 address){
  109. std::map<uint32, GraphVertex>::iterator it = addr_map_.find(address);
  110. if (it == addr_map_.end()){
  111. std::cerr << "Request for instruction at unknown address "
  112. << boost::format("0x%08x") % address << std::endl;
  113. }
  114. return it->second;
  115. }
  116. void ControlFlow::Merge(GraphVertex graph_1, GraphVertex graph_2){
  117. // Update property.
  118. GroupPtr gr1 = GET(graph_1);
  119. GroupPtr gr2 = GET(graph_2);
  120. gr1->end = gr2->end;
  121. PUT(graph_1, gr1);
  122. // Update address map.
  123. ConstInstIterator it = gr2->start;
  124. do{
  125. addr_map_[(*it)->GetAddress()] = graph_1;
  126. ++ it;
  127. } while (gr2->start != gr2->end && it != gr2->end);
  128. // Add outgoing edges from graph_2.
  129. OutEdgeRange r = boost::out_edges(graph_2, graph_);
  130. for (OutEdgeIterator e = r.first; e != r.second; ++e){
  131. GraphEdge newE = boost::add_edge(graph_1, boost::target(*e, graph_), graph_).first;
  132. PUT_EDGE(newE, GET_EDGE(*e));
  133. }
  134. // Update _next pointer.
  135. gr1->next = gr2->next;
  136. if (gr2->next != NULL) gr2->next->prev = gr2->prev;
  137. // Remove edges to/from graph_2
  138. boost::clear_vertex(graph_2, graph_);
  139. // Remove vertex.
  140. boost::remove_vertex(graph_2, graph_);
  141. }
  142. typedef std::pair<GraphVertex, int> LevelEntry;
  143. void ControlFlow::SetStackLevel(GraphVertex graph, int level){
  144. Stack<LevelEntry> level_stack;
  145. std::set<GraphVertex> seen;
  146. level_stack.Push(LevelEntry(graph, level));
  147. seen.insert(graph);
  148. while (!level_stack.IsEmpty()){
  149. LevelEntry e = level_stack.Pop();
  150. GroupPtr gr = GET(e.first);
  151. if (gr->stack_level != -1){
  152. if (gr->stack_level != e.second)
  153. std::cerr << boost::format(
  154. "WARNING: Inconsistency in expected stack level for instruction "
  155. "at address 0x%08x (current: %d, requested: %d)\n"
  156. ) % (*gr->start)->GetAddress() % gr->stack_level % e.second;
  157. continue;
  158. }
  159. gr->stack_level = e.second;
  160. OutEdgeRange r = boost::out_edges(e.first, graph_);
  161. for (OutEdgeIterator oe = r.first; oe != r.second; ++ oe){
  162. GraphVertex target = boost::target(*oe, graph_);
  163. if (seen.find(target) == seen.end()){
  164. level_stack.Push(LevelEntry(target, e.second + (*gr->start)->GetStackChange()));
  165. seen.insert(target);
  166. }
  167. }
  168. }
  169. }
  170. void ControlFlow::CreateGroups(){
  171. if (
  172. !engine_.functions.empty()
  173. //&& GET(engine_.functions.begin()->second.GetVertex())->_stackLevel != -1
  174. //&& GET(engine_.functions.begin()->second.vertex_)->_stackLevel != -1
  175. && GET(engine_.functions.begin()->second.vertex)->stack_level != -1
  176. ){
  177. return;
  178. }
  179. for (
  180. FuncMap::iterator fn = engine_.functions.begin();
  181. fn != engine_.functions.end();
  182. ++ fn
  183. ){
  184. SetStackLevel(fn->second.vertex, 0);
  185. }
  186. ConstInstIterator cur_inst, next_inst;
  187. next_inst = insts_.begin();
  188. next_inst ++;
  189. int stack_level = 0;
  190. int expected_stack_level = 0;
  191. for (cur_inst = insts_.begin(); next_inst != insts_.end(); ++ cur_inst, ++ next_inst){
  192. GraphVertex cur = Find(cur_inst);
  193. GraphVertex next = Find(next_inst);
  194. GroupPtr group_cur = GET(cur);
  195. GroupPtr group_next = GET(next);
  196. // Don't process unreachable code.
  197. if (group_cur->stack_level < 0){
  198. stack_level = group_next->stack_level;
  199. continue;
  200. }
  201. expected_stack_level = group_cur->stack_level;
  202. // If expected stack level decreases in next vertex, then
  203. // use next vertex level as expected level.
  204. if (expected_stack_level > group_next->stack_level && group_next->stack_level >= 0){
  205. expected_stack_level = group_next->stack_level;
  206. // Also set the stack level of the current group
  207. // to remember that we expect it to be lower.
  208. group_cur->stack_level = expected_stack_level;
  209. }
  210. stack_level += (*cur_inst)->GetStackChange();
  211. // For stack operations, the new stack level becomes the
  212. // expected stack level starting from the next group.
  213. if ((*cur_inst)->IsStackOp()){
  214. expected_stack_level = stack_level;
  215. group_next->stack_level = stack_level;
  216. }
  217. // Group ends after a jump.
  218. if ((*cur_inst)->IsJump()){
  219. stack_level = group_next->stack_level;
  220. continue;
  221. }
  222. // Group ends with a return.
  223. if ((*cur_inst)->IsReturn()){
  224. stack_level = group_next->stack_level;
  225. continue;
  226. }
  227. // Group ends before target of a jump.
  228. if (in_degree(next, graph_) != 1){
  229. stack_level = group_next->stack_level;
  230. continue;
  231. }
  232. // This part is only relevant if we use the stack level.
  233. if (!engine_.UsePureGrouping()){
  234. // If group has no instructions with stack effect >= 0, don't merge on balanced stack.
  235. bool forceMerge = true;
  236. ConstInstIterator it = group_cur->start;
  237. do{
  238. if ((*it)->GetStackChange() >= 0) forceMerge = false;
  239. ++ it;
  240. } while (group_cur->start != group_cur->end && it != group_cur->end);
  241. // Group ends when stack is balanced, unless just before conditional jump.
  242. if (stack_level == expected_stack_level && !forceMerge && !(*next_inst)->IsCondJump())
  243. continue;
  244. }
  245. // All checks passed, merge groups
  246. Merge(cur, next);
  247. }
  248. // FIXME: The short-circuit detection is disabled because short-circuited
  249. // groups require some special handling in the code generation. It's not
  250. // entirely clear how to handle it properly, though: It has to be deduced
  251. // which effect is created by the conditional jumps in the middle of a
  252. // block, which seems to get fairly complex when there are multiple groups
  253. // that are merged by the short-circuit detection.
  254. //detectShortCircuit();
  255. }
  256. void ControlFlow::DetectShortCircuit(){
  257. ConstInstIterator last_inst = insts_.end();
  258. -- last_inst;
  259. GraphVertex cur = Find(last_inst);
  260. GroupPtr gr = GET(cur);
  261. while (gr->prev != NULL){
  262. bool do_merge = false;
  263. cur = Find(gr->start);
  264. GraphVertex prev = Find(gr->prev->start);
  265. // Block is candidate for short-circuit merging if it and the
  266. // preceding block both end with conditional jumps.
  267. if (out_degree(cur, graph_) == 2 && out_degree(prev, graph_) == 2){
  268. do_merge = true;
  269. OutEdgeRange range_cur = boost::out_edges(cur, graph_);
  270. std::vector<GraphVertex> succs;
  271. // Find possible target vertices.
  272. for (OutEdgeIterator it = range_cur.first; it != range_cur.second; ++ it)
  273. succs.push_back(boost::target(*it, graph_));
  274. // Check if vertex would add new targets - if yes, don't merge.
  275. OutEdgeRange range_prev = boost::out_edges(prev, graph_);
  276. for (OutEdgeIterator it = range_prev.first; it != range_prev.second; ++ it){
  277. GraphVertex target = boost::target(*it, graph_);
  278. do_merge &= (
  279. std::find(succs.begin(), succs.end(), target) != succs.end() || target == cur
  280. );
  281. }
  282. if (do_merge){
  283. gr = gr->prev;
  284. Merge(prev, cur);
  285. continue;
  286. }
  287. }
  288. gr = gr->prev;
  289. }
  290. }
  291. const Graph &ControlFlow::Analyze(){
  292. DetectDoWhile();
  293. DetectWhile();
  294. DetectBreak();
  295. DetectContinue();
  296. DetectIf();
  297. DetectElse();
  298. return graph_;
  299. }
  300. void ControlFlow::DetectWhile(){
  301. VertexRange vertex_range = boost::vertices(graph_);
  302. for (VertexIterator v = vertex_range.first; v != vertex_range.second; ++ v){
  303. GroupPtr gr = GET(*v);
  304. // Undetermined block that ends with conditional jump.
  305. if (out_degree(*v, graph_) == 2 && gr->type == GROUP_TYPE_NORMAL){
  306. InEdgeRange ier = boost::in_edges(*v, graph_);
  307. bool is_while = false;
  308. for (InEdgeIterator e = ier.first; e != ier.second; ++ e){
  309. GroupPtr source_gr = GET(boost::source(*e, graph_));
  310. // Block has ingoing edge from block later in the
  311. // code that isn't a do-while condition.
  312. if (
  313. (*source_gr->start)->GetAddress() > (*gr->start)->GetAddress()
  314. && source_gr->type != GROUP_TYPE_DO_WHILE
  315. ){
  316. is_while = true;
  317. }
  318. }
  319. if (is_while) gr->type = GROUP_TYPE_WHILE;
  320. }
  321. }
  322. }
  323. void ControlFlow::DetectDoWhile(){
  324. VertexRange vertex_range = boost::vertices(graph_);
  325. for (VertexIterator v = vertex_range.first; v != vertex_range.second; ++ v){
  326. GroupPtr gr = GET(*v);
  327. // Undetermined block that ends with conditional jump...
  328. if (out_degree(*v, graph_) == 2 && gr->type == GROUP_TYPE_NORMAL){
  329. OutEdgeRange oer = boost::out_edges(*v, graph_);
  330. for (OutEdgeIterator e = oer.first; e != oer.second; ++e){
  331. GroupPtr target_gr = GET(boost::target(*e, graph_));
  332. // ...to earlier in code.
  333. if ((*target_gr->start)->GetAddress() < (*gr->start)->GetAddress())
  334. gr->type = GROUP_TYPE_DO_WHILE;
  335. }
  336. }
  337. }
  338. }
  339. void ControlFlow::DetectBreak(){
  340. VertexRange vertex_range = boost::vertices(graph_);
  341. for (VertexIterator v = vertex_range.first; v != vertex_range.second; ++ v){
  342. GroupPtr gr = GET(*v);
  343. // Undetermined block with unconditional jump...
  344. if (
  345. gr->type == GROUP_TYPE_NORMAL
  346. && ((*gr->end)->IsUncondJump())
  347. && out_degree(*v, graph_) == 1
  348. ){
  349. OutEdgeIterator oe = boost::out_edges(*v, graph_).first;
  350. GraphVertex target = boost::target(*oe, graph_);
  351. GroupPtr target_gr = GET(target);
  352. // ...to somewhere later in the code...
  353. if ((*gr->start)->GetAddress() >= (*target_gr->start)->GetAddress()) continue;
  354. InEdgeRange ier = boost::in_edges(target, graph_);
  355. for (InEdgeIterator ie = ier.first; ie != ier.second; ++ ie){
  356. GroupPtr source_gr = GET(boost::source(*ie, graph_));
  357. // ...to block immediately after a do-while condition,
  358. // or to jump target of a while condition.
  359. if (
  360. (target_gr->prev == source_gr && source_gr->type == GROUP_TYPE_DO_WHILE)
  361. || source_gr->type == GROUP_TYPE_WHILE
  362. ){
  363. if (ValidateBreakOrContinue(gr, source_gr)) gr->type = GROUP_TYPE_BREAK;
  364. }
  365. }
  366. }
  367. }
  368. }
  369. void ControlFlow::DetectContinue(){
  370. VertexRange vertex_range = boost::vertices(graph_);
  371. for (VertexIterator v = vertex_range.first; v != vertex_range.second; ++ v){
  372. GroupPtr gr = GET(*v);
  373. // Undetermined block with unconditional jump...
  374. if (
  375. gr->type == GROUP_TYPE_NORMAL
  376. && ((*gr->end)->IsUncondJump())
  377. && out_degree(*v, graph_) == 1
  378. ){
  379. OutEdgeIterator oe = boost::out_edges(*v, graph_).first;
  380. GraphVertex target = boost::target(*oe, graph_);
  381. GroupPtr target_gr = GET(target);
  382. // ...to a while or do-while condition...
  383. if (
  384. target_gr->type == GROUP_TYPE_WHILE || target_gr->type == GROUP_TYPE_DO_WHILE
  385. ){
  386. bool is_continue = true;
  387. // ...unless...
  388. OutEdgeRange toer = boost::out_edges(target, graph_);
  389. bool after_jump_jargets = true;
  390. for (OutEdgeIterator toe = toer.first; toe != toer.second; ++ toe){
  391. // ...it is targeting a while condition which jumps to the next sequential group
  392. if (
  393. target_gr->type == GROUP_TYPE_WHILE
  394. && GET(boost::target(*toe, graph_)) == gr->next
  395. ){
  396. is_continue = false;
  397. }
  398. // ...or the instruction is placed after all jump targets from condition.
  399. if (
  400. (*GET(boost::target(*toe, graph_))->start)->GetAddress()
  401. > (*gr->start)->GetAddress()
  402. ){
  403. after_jump_jargets = false;
  404. }
  405. }
  406. if (after_jump_jargets) is_continue = false;
  407. if (is_continue && ValidateBreakOrContinue(gr, target_gr))
  408. gr->type = GROUP_TYPE_CONTINUE;
  409. }
  410. }
  411. }
  412. }
  413. bool ControlFlow::ValidateBreakOrContinue(GroupPtr group, GroupPtr condition_group){
  414. GroupPtr from;
  415. GroupPtr to;
  416. GroupPtr cursor;
  417. if (condition_group->type == GROUP_TYPE_DO_WHILE){
  418. to = condition_group;
  419. from = group;
  420. }
  421. else{
  422. to = group;
  423. from = condition_group->next;
  424. }
  425. GROUP_TYPE ogt = (
  426. condition_group->type == GROUP_TYPE_DO_WHILE ? GROUP_TYPE_WHILE : GROUP_TYPE_DO_WHILE
  427. );
  428. // Verify that destination deals with innermost while/do-while.
  429. for (cursor = from; cursor->next != NULL && cursor != to; cursor = cursor->next){
  430. if (cursor->type == condition_group->type){
  431. OutEdgeRange oer_validate = boost::out_edges(Find(cursor->start), graph_);
  432. for (
  433. OutEdgeIterator oe_validate = oer_validate.first;
  434. oe_validate != oer_validate.second;
  435. ++ oe_validate
  436. ){
  437. GraphVertex v_validate = boost::target(*oe_validate, graph_);
  438. GroupPtr g_validate = GET(v_validate);
  439. // For all other loops of same type found in range,
  440. // all targets must fall within that range.
  441. if (
  442. (*g_validate->start)->GetAddress() < (*from->start)->GetAddress()
  443. || (*g_validate->start)->GetAddress() > (*to->start)->GetAddress()
  444. ){
  445. return false;
  446. }
  447. InEdgeRange ier_validate = boost::in_edges(v_validate, graph_);
  448. for (
  449. InEdgeIterator ie_validate = ier_validate.first;
  450. ie_validate != ier_validate.second;
  451. ++ ie_validate
  452. ){
  453. GroupPtr ig_validate = GET(boost::source(*ie_validate, graph_));
  454. // All loops of other type going into range must be placed within range.
  455. if (
  456. ig_validate->type == ogt
  457. && (
  458. (*ig_validate->start)->GetAddress() < (*from->start)->GetAddress()
  459. || (*ig_validate->start)->GetAddress() > (*to->start)->GetAddress()
  460. )
  461. ){
  462. return false;
  463. }
  464. }
  465. }
  466. }
  467. }
  468. return true;
  469. }
  470. void ControlFlow::DetectIf(){
  471. VertexRange vr = boost::vertices(graph_);
  472. for (VertexIterator v = vr.first; v != vr.second; ++v){
  473. GroupPtr gr = GET(*v);
  474. // If: Undetermined block with conditional jump.
  475. if (gr->type == GROUP_TYPE_NORMAL && ((*gr->end)->IsCondJump()))
  476. gr->type = GROUP_TYPE_IF;
  477. }
  478. }
  479. void ControlFlow::DetectElse(){
  480. VertexRange vr = boost::vertices(graph_);
  481. for (VertexIterator v = vr.first; v != vr.second; ++v){
  482. GroupPtr gr = GET(*v);
  483. if (gr->type == GROUP_TYPE_IF){
  484. OutEdgeRange oer = boost::out_edges(*v, graph_);
  485. GraphVertex target;
  486. uint32 max_address = 0;
  487. GroupPtr target_gr;
  488. // Find jump target.
  489. for (OutEdgeIterator oe = oer.first; oe != oer.second; ++ oe){
  490. target_gr = GET(boost::target(*oe, graph_));
  491. if ((*target_gr->start)->GetAddress() > max_address){
  492. target = boost::target(*oe, graph_);
  493. max_address = (*target_gr->start)->GetAddress();
  494. }
  495. }
  496. target_gr = GET(target);
  497. // Else: Jump target of if immediately preceded by an unconditional jump...
  498. if (!(*target_gr->prev->end)->IsUncondJump()) continue;
  499. // ...which is not a break or a continue...
  500. if (
  501. target_gr->prev->type == GROUP_TYPE_CONTINUE
  502. || target_gr->prev->type == GROUP_TYPE_BREAK
  503. ){
  504. continue;
  505. }
  506. // ...to later in the code.
  507. OutEdgeIterator toe = boost::out_edges(
  508. Find((*target_gr->prev->start)->GetAddress()), graph_
  509. ).first;
  510. GroupPtr target_target_gr = GET(boost::target(*toe, graph_));
  511. if ((*target_target_gr->start)->GetAddress() > (*target_gr->end)->GetAddress()){
  512. if (ValidateElseBlock(gr, target_gr, target_target_gr)){
  513. target_gr->start_else = true;
  514. target_target_gr->prev->end_else.push_back(target_gr.get());
  515. }
  516. }
  517. }
  518. }
  519. }
  520. bool ControlFlow::ValidateElseBlock(GroupPtr if_group, GroupPtr start, GroupPtr end){
  521. for (GroupPtr cursor = start; cursor != end; cursor = cursor->next){
  522. if (
  523. cursor->type == GROUP_TYPE_IF
  524. || cursor->type == GROUP_TYPE_WHILE
  525. || cursor->type == GROUP_TYPE_DO_WHILE
  526. ){
  527. // Validate outgoing edges of conditions.
  528. OutEdgeRange oer = boost::out_edges(Find(cursor->start), graph_);
  529. for (OutEdgeIterator oe = oer.first; oe != oer.second; ++ oe){
  530. GraphVertex target = boost::target(*oe, graph_);
  531. GroupPtr target_gr = GET(target);
  532. // Each edge from condition must not leave the range [start, end].
  533. if (
  534. (*start->start)->GetAddress() > (*target_gr->start)->GetAddress()
  535. || (*target_gr->start)->GetAddress() > (*end->start)->GetAddress()
  536. ){
  537. return false;
  538. }
  539. }
  540. }
  541. // If previous group ends an else, that else must start inside the range.
  542. for (
  543. ElseEndIterator it = cursor->prev->end_else.begin();
  544. it != cursor->prev->end_else.end();
  545. ++ it
  546. ){
  547. if ((*(*it)->start)->GetAddress() < (*start->start)->GetAddress()) return false;
  548. }
  549. // Unless group is a simple unconditional jump...
  550. if ((*cursor->start)->IsUncondJump()) continue;
  551. // ...validate ingoing edges
  552. InEdgeRange ier = boost::in_edges(Find(cursor->start), graph_);
  553. for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie){
  554. GraphVertex source = boost::source(*ie, graph_);
  555. GroupPtr source_gr = GET(source);
  556. // Edges going to conditions...
  557. if (
  558. source_gr->type == GROUP_TYPE_IF
  559. || source_gr->type == GROUP_TYPE_WHILE
  560. || source_gr->type == GROUP_TYPE_DO_WHILE
  561. ){
  562. // ...must not come from outside the range [start, end]...
  563. if (
  564. (*start->start)->GetAddress() > (*source_gr->start)->GetAddress()
  565. || (*source_gr->start)->GetAddress() > (*end->start)->GetAddress()
  566. ){
  567. // ...unless source is simple unconditional jump...
  568. if ((*source_gr->start)->IsUncondJump()) continue;
  569. // ...or the edge is from the if condition associated with this else.
  570. if (if_group == source_gr) continue;
  571. return false;
  572. }
  573. }
  574. }
  575. }
  576. return true;
  577. }