@@ -6,6 +6,7 @@ use heimdall_vm::{
6
6
ext:: exec:: VMTrace ,
7
7
} ;
8
8
use petgraph:: { matrix_graph:: NodeIndex , Graph } ;
9
+ use std:: collections:: HashSet ;
9
10
10
11
/// convert a symbolic execution [`VMTrace`] into a [`Graph`] of blocks, illustrating the
11
12
/// control-flow graph found by the symbolic execution engine.
@@ -15,6 +16,7 @@ pub fn build_cfg(
15
16
contract_cfg : & mut Graph < String , String > ,
16
17
parent_node : Option < NodeIndex < u32 > > ,
17
18
jump_taken : bool ,
19
+ seen_nodes : & mut HashSet < String > ,
18
20
) -> Result < ( ) > {
19
21
let mut cfg_node: String = String :: new ( ) ;
20
22
let mut parent_node = parent_node;
@@ -23,9 +25,11 @@ pub fn build_cfg(
23
25
for operation in & vm_trace. operations {
24
26
let opcode_name = opcode_name ( operation. last_instruction . opcode ) ;
25
27
28
+ let opcode_offset = operation. last_instruction . instruction - 1 ; // start from 0x00
29
+
26
30
let assembly = format ! (
27
31
"{} {} {}" ,
28
- encode_hex_reduced( U256 :: from( operation . last_instruction . instruction ) ) ,
32
+ encode_hex_reduced( U256 :: from( opcode_offset ) ) ,
29
33
opcode_name,
30
34
if opcode_name. contains( "PUSH" ) {
31
35
encode_hex_reduced(
@@ -43,6 +47,12 @@ pub fn build_cfg(
43
47
cfg_node. push_str ( & format ! ( "{}\n " , & assembly) ) ;
44
48
}
45
49
50
+ // check if this node has been seen before
51
+ if seen_nodes. contains ( & cfg_node) {
52
+ return Ok ( ( ) ) ;
53
+ }
54
+ seen_nodes. insert ( cfg_node. clone ( ) ) ;
55
+
46
56
// add the node to the graph
47
57
let node_index = contract_cfg. add_node ( cfg_node) ;
48
58
if let Some ( parent_node) = parent_node {
@@ -63,8 +73,29 @@ pub fn build_cfg(
63
73
. last_instruction
64
74
. opcode ==
65
75
JUMPDEST ,
76
+ seen_nodes,
66
77
) ?;
67
78
}
68
79
69
80
Ok ( ( ) )
70
81
}
82
+
83
+ #[ cfg( test) ]
84
+ mod tests {
85
+ use super :: * ;
86
+ use crate :: { cfg, CfgArgsBuilder } ;
87
+ use tokio:: test;
88
+
89
+ #[ test]
90
+ async fn test_build_cfg ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
91
+ let args = CfgArgsBuilder :: new ( )
92
+ . target ( "0x6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256" . to_string ( ) )
93
+ . build ( ) ?;
94
+
95
+ let result = cfg ( args) . await ?;
96
+
97
+ println ! ( "Contract Cfg: {:#?}" , result) ;
98
+
99
+ Ok ( ( ) )
100
+ }
101
+ }
0 commit comments