44import net .nandgr .debugger .cfg .beans .BytecodeSection ;
55import net .nandgr .debugger .cfg .beans .ContractBytecode ;
66import net .nandgr .debugger .cfg .beans .OpcodeSource ;
7+ import net .nandgr .debugger .node .response .json .DebugTraceTransactionLog ;
78import net .nandgr .eth .Opcode ;
89import net .nandgr .eth .Opcodes ;
910import java .math .BigInteger ;
@@ -20,10 +21,11 @@ public class CFGCreatorDefault {
2021 Opcodes .JUMP ,
2122 Opcodes .STOP ,
2223 Opcodes .REVERT ,
23- Opcodes .RETURN
24+ Opcodes .RETURN ,
25+ Opcodes .INVALID
2426 ).collect (Collectors .toList ());
2527
26- public ContractBytecode createContractBytecode (List <OpcodeSource > contractOpcodes ) {
28+ public ContractBytecode createContractBytecode (List <OpcodeSource > contractOpcodes , Map < Integer , DebugTraceTransactionLog > trace ) {
2729 BigInteger codeOffset = BigInteger .valueOf (0 );
2830 BytecodeSection constructorSection = null ;
2931 boolean constructorFound = false ;
@@ -52,11 +54,51 @@ public ContractBytecode createContractBytecode(List<OpcodeSource> contractOpcode
5254
5355 Map <Integer , BytecodeChunk > functionsChunks = splitInChunks (functionsOpcodes );
5456 createRelations (functionsChunks );
57+ checkChunksWithTrace (functionsChunks , trace );
5558 BytecodeSection functionsSection = new BytecodeSection (functionsChunks );
5659
5760 return new ContractBytecode (constructorSection , functionsSection );
5861 }
5962
63+ private void checkChunksWithTrace (Map <Integer , BytecodeChunk > functionsChunks , Map <Integer , DebugTraceTransactionLog > trace ) {
64+ for (Map .Entry <Integer , BytecodeChunk > entry : functionsChunks .entrySet ()) {
65+ BytecodeChunk chunk = entry .getValue ();
66+ OpcodeSource lastOpcode = chunk .getOpcodes ().get (chunk .getOpcodes ().size () - 1 );
67+
68+ if (trace .containsKey (lastOpcode .getOffset ()) && chunk .hasEmptyRelations () && isJumpOpcode (lastOpcode )) {
69+ DebugTraceTransactionLog jumpTrace = trace .get (lastOpcode .getOffset ());
70+ Integer jumpDestination = Integer .valueOf (jumpTrace .getStack ().get (jumpTrace .getStack ().size () - 1 ), 16 );
71+ BytecodeChunk destChunk ;
72+ if (functionsChunks .containsKey (jumpDestination )) {
73+ destChunk = functionsChunks .get (jumpDestination );
74+ } else {
75+ destChunk = searchDestinationChunk (functionsChunks , jumpDestination );
76+ }
77+ chunk .setBranchA (destChunk );
78+ }
79+ }
80+ }
81+
82+ private boolean isJumpOpcode (OpcodeSource lastOpcode ) {
83+ return isJump (lastOpcode ) || lastOpcode .getOpcode ().equals (Opcodes .JUMPI );
84+ }
85+
86+ private boolean isJump (OpcodeSource lastOpcode ) {
87+ return lastOpcode .getOpcode ().equals (Opcodes .JUMP );
88+ }
89+
90+ private BytecodeChunk searchDestinationChunk (Map <Integer , BytecodeChunk > functionsChunks , Integer jumpDestination ) {
91+ for (Map .Entry <Integer , BytecodeChunk > entry : functionsChunks .entrySet ()) {
92+ BytecodeChunk chunk = entry .getValue ();
93+ for (OpcodeSource opcodeSource : chunk .getOpcodes ()) {
94+ if (opcodeSource .getOffset () == jumpDestination ) {
95+ return chunk ;
96+ }
97+ }
98+ }
99+ return null ;
100+ }
101+
60102 private static void adjustOffsets (List <OpcodeSource > functionsOpcodes , int offset ) {
61103 for (Opcode opcode : functionsOpcodes ) {
62104 opcode .setOffset (opcode .getOffset () - offset );
0 commit comments