Skip to content

Commit be68b5e

Browse files
committed
Full working version. Needs refactor and improvements
1 parent 8329ec0 commit be68b5e

File tree

17 files changed

+611
-74
lines changed

17 files changed

+611
-74
lines changed

pom.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<jackson.version>2.9.5</jackson.version>
1414
<apache.http.client.version>4.5.5</apache.http.client.version>
1515
<junit.version>4.12</junit.version>
16+
<velocity.version>1.7</velocity.version>
1617
</properties>
1718

1819
<dependencies>
@@ -31,15 +32,18 @@
3132
<artifactId>httpclient</artifactId>
3233
<version>${apache.http.client.version}</version>
3334
</dependency>
35+
<dependency>
36+
<groupId>org.apache.velocity</groupId>
37+
<artifactId>velocity</artifactId>
38+
<version>${velocity.version}</version>
39+
</dependency>
3440
<dependency>
3541
<groupId>junit</groupId>
3642
<artifactId>junit</artifactId>
3743
<version>${junit.version}</version>
3844
<scope>test</scope>
3945
</dependency>
4046

41-
42-
4347
</dependencies>
4448

4549
<build>
Lines changed: 77 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,115 @@
11
package net.nandgr.debugger;
22

3+
import com.fasterxml.jackson.core.JsonProcessingException;
34
import com.fasterxml.jackson.databind.ObjectMapper;
4-
import net.nandgr.debugger.asm.json.Asm;
5-
import net.nandgr.debugger.asm.json.Code;
6-
import net.nandgr.debugger.asm.json.Contract;
75
import net.nandgr.debugger.cfg.CFGCreatorDefault;
86
import net.nandgr.debugger.cfg.beans.BytecodeChunk;
97
import net.nandgr.debugger.cfg.beans.ContractBytecode;
108
import net.nandgr.debugger.cfg.beans.OpcodeSource;
119
import net.nandgr.debugger.cfg.graphviz.GraphVizCreator;
10+
import net.nandgr.debugger.disassembler.DisassemblerException;
11+
import net.nandgr.debugger.disassembler.LinkedDisassembler;
12+
import net.nandgr.debugger.report.Report;
13+
import net.nandgr.debugger.report.ReportException;
14+
import net.nandgr.debugger.solc.Solc;
15+
import net.nandgr.debugger.solc.solcjson.Code;
16+
import net.nandgr.debugger.solc.solcjson.Contract;
17+
import net.nandgr.debugger.solc.solcjson.SolcOutput;
1218
import net.nandgr.debugger.trace.TraceService;
1319
import net.nandgr.debugger.trace.response.json.DebugTraceTransactionLog;
14-
import net.nandgr.debugger.trace.response.json.DebugTraceTransactionResponse;
15-
import net.nandgr.eth.Disassembler;
16-
import net.nandgr.eth.Opcode;
1720

1821
import java.io.File;
1922
import java.io.IOException;
2023
import java.nio.file.Files;
21-
import java.rmi.server.ExportException;
22-
import java.util.ArrayList;
24+
import java.nio.file.Path;
25+
import java.nio.file.Paths;
2326
import java.util.List;
2427
import java.util.Map;
2528

2629
public class Main {
2730

28-
public static void main(String[] args) throws Exception {
29-
30-
String name = "Impl.sol";
31-
String code = "608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c045f2d1461005c57806367e0badb14610093578063cd16ecbf146100be575b600080fd5b34801561006857600080fd5b5061009160048036038101908080359060200190929190803590602001909291905050506100eb565b005b34801561009f57600080fd5b506100a86100fd565b6040518082815260200191505060405180910390f35b3480156100ca57600080fd5b506100e960048036038101908080359060200190929190505050610106565b005b81600081905550806001819055505050565b60008054905090565b80600081905550505600a165627a7a7230582039dcdb7685335c75b3515b47d970516fe695dfb1f28195e1909aaf4f869118550029";
32-
File asmFile = new File("asm.asm");
33-
34-
byte[] bytes = Files.readAllBytes(asmFile.toPath());
35-
String asm = new String(bytes);
31+
public static void main(String[] args){
32+
// Will be parameters
33+
String nodeUrl = "http://127.0.0.1:8545";
34+
String txHash = "0xc296ffe00b37d7740f22f2227f39b210a4928756f9472a37cab61951cf9fbffa";
35+
String solidityFile = "/home/nando/ethereum/temp/Impl.sol";
3636

3737
ObjectMapper objectMapper = new ObjectMapper();
38-
Asm asmObject = objectMapper.readValue(asm, Asm.class);
39-
List<Code> asmCode = asmObject.getContracts().get("Impl.sol:Impl").getAsm().getData().get("0").getCode();
40-
41-
asmCode.removeIf(elem -> elem.getName().equals("tag"));
4238

43-
Disassembler disassembler = new Disassembler(code);
44-
45-
List<Opcode> opcodes = disassembler.getOpcodes();
39+
if (!Solc.checkSolcInClasspath()) {
40+
System.out.println("solc was not found in classpath");
41+
System.exit(0);
42+
}
4643

47-
if (opcodes.size()-1 != asmCode.size()) {
48-
// TODO move to a new exception somewhere
49-
throw new Exception("Asm does not match with bytecode. Opcodes size: " + opcodes.size() + ", asm size: " + asmCode.size());
44+
TraceService traceService = new TraceService(nodeUrl);
45+
Map<Integer, DebugTraceTransactionLog> traceData = null;
46+
try {
47+
traceData = traceService.getTraceData(txHash);
48+
} catch (IOException e) {
49+
System.out.println("Failed when getting transaction trace");
50+
e.printStackTrace();
51+
System.exit(0);
52+
}
53+
Path path = Paths.get(solidityFile);
54+
String sourceCode = null;
55+
try {
56+
sourceCode = new String(Files.readAllBytes(path));
57+
} catch (IOException e) {
58+
System.out.println("Failed when reading source code from source file");
59+
e.printStackTrace();
60+
System.exit(0);
61+
}
62+
String fileName = path.getFileName().toString();
63+
String contractName = fileName.substring(0, fileName.lastIndexOf("."));
64+
65+
Solc solc = new Solc(solidityFile);
66+
SolcOutput solcOutput = null;
67+
try {
68+
solcOutput = solc.compile();
69+
} catch (IOException | InterruptedException e) {
70+
System.out.println("Failed when compiling source");
71+
e.printStackTrace();
72+
System.exit(0);
5073
}
5174

52-
List<OpcodeSource> opcodeSources = new ArrayList<>();
53-
for (int i = 0; i < asmCode.size(); i++) {
54-
OpcodeSource opcodeSource = new OpcodeSource(opcodes.get(i));
55-
Code currentAsmOpcode = asmCode.get(i);
56-
opcodeSource.setBegin(currentAsmOpcode.getBegin());
57-
opcodeSource.setEnd(currentAsmOpcode.getEnd());
58-
opcodeSources.add(opcodeSource);
75+
Contract contract = solcOutput.getContracts().get(solidityFile + ":" + contractName);
76+
List<Code> asmCode = contract.getAsm().getData().get("0").getCode();
77+
String code = contract.getBinRuntime();
78+
79+
LinkedDisassembler disassembler = new LinkedDisassembler(code);
80+
List<OpcodeSource> opcodeSources = null;
81+
try {
82+
opcodeSources = disassembler.getOpcodeSources(asmCode);
83+
} catch (DisassemblerException e) {
84+
System.out.println("Failed when disassembling");
85+
e.printStackTrace();
86+
System.exit(0);
5987
}
6088

6189
CFGCreatorDefault cfgCreatorDefault = new CFGCreatorDefault();
6290

6391
ContractBytecode contractBytecode = cfgCreatorDefault.createContractBytecode(opcodeSources);
6492
Map<Integer, BytecodeChunk> runtimeChunks = contractBytecode.getRuntime().getChunks();
6593

66-
TraceService traceService = new TraceService("http://127.0.0.1:8545");
67-
Map<Integer, DebugTraceTransactionLog> traceData = traceService.getTraceData("0xc296ffe00b37d7740f22f2227f39b210a4928756f9472a37cab61951cf9fbffa");
94+
String traceMapJson = null;
95+
try {
96+
traceMapJson = objectMapper.writeValueAsString(traceData);
97+
} catch (JsonProcessingException e) {
98+
System.out.println("Failed when mapping trace data");
99+
e.printStackTrace();
100+
System.exit(0);
101+
}
68102

69103
GraphVizCreator graphVizCreator = new GraphVizCreator(runtimeChunks, traceData);
70104
String graph = graphVizCreator.buildStringGraph();
71-
System.out.println(graph);
72105

73-
// for (Map.Entry<Integer, BytecodeChunk> integerBytecodeChunkEntry : contractBytecode.getRuntime().getChunks().entrySet()) {
74-
// for (Opcode opcode : integerBytecodeChunkEntry.getValue().getOpcodes()) {
75-
// Integer key = integerBytecodeChunkEntry.getKey();
76-
// System.out.println(Integer.toHexString(key) + "-> " + opcode.toString());
77-
// }
78-
// }
79-
80-
// for (OpcodeSource opcode : opcodeSources) {
81-
// System.out.println(opcode.toString());
82-
// }
106+
Report report = new Report(sourceCode, traceMapJson, graph);
107+
try {
108+
report.createReport();
109+
} catch (ReportException e) {
110+
System.out.println("Failed when creating report");
111+
e.printStackTrace();
112+
System.exit(0);
113+
}
83114
}
84115
}

src/main/java/net/nandgr/debugger/asm/json/Contract.java

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/main/java/net/nandgr/debugger/cfg/beans/BytecodeChunk.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public String toString() {
5353
"id=" + id +
5454
", branchA=" + branchA +
5555
", branchB=" + branchB +
56-
", opcodes=" + opcodes +
56+
", disassembler=" + opcodes +
5757
'}';
5858
}
5959
}

src/main/java/net/nandgr/debugger/cfg/graphviz/GraphVizCreator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ private String buildLabel(BytecodeChunk bytecodeChunk) {
4343
StringBuilder sb= new StringBuilder("< <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">").append(System.lineSeparator());
4444
for (OpcodeSource opcodeSource : bytecodeChunk.getOpcodes()) {
4545
String id = opcodeSource.getOffset() + "#" + opcodeSource.getBegin() + "#" + opcodeSource.getEnd();
46-
sb.append("<TR><TD ID=\"" + id +"\" HREF=\" \">")
46+
sb.append("<TR><TD ID=\"").append(id).append("#offset\" HREF=\" \">")
4747
.append(opcodeSource.getOffset())
48-
.append("</TD><TD ID=\"" + id + "\" HREF=\" \">")
48+
.append("</TD><TD ID=\"").append(id).append("#instr\" HREF=\" \">")
4949
.append(opcodeSource.getOpcode())
5050
.append("</TD></TR>").append(System.lineSeparator());
5151
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package net.nandgr.debugger.disassembler;
2+
3+
public class DisassemblerException extends Exception {
4+
5+
public DisassemblerException(String message) {
6+
super(message);
7+
}
8+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package net.nandgr.debugger.disassembler;
2+
3+
import net.nandgr.debugger.cfg.beans.OpcodeSource;
4+
import net.nandgr.debugger.solc.solcjson.Code;
5+
import net.nandgr.eth.Disassembler;
6+
import net.nandgr.eth.Opcode;
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
10+
public class LinkedDisassembler extends Disassembler {
11+
12+
public LinkedDisassembler(String code) {
13+
super(code);
14+
}
15+
16+
public List<OpcodeSource> getOpcodeSources(List<Code> asmCode) throws DisassemblerException {
17+
List<Opcode> opcodes = super.getOpcodes();
18+
asmCode.removeIf(elem -> elem.getName().equals("tag"));
19+
20+
if (opcodes.size()-1 != asmCode.size()) {
21+
// TODO move to a new exception somewhere
22+
throw new DisassemblerException("SolcOutput does not match with bytecode. Opcodes size: " + opcodes.size() + ", asm size: " + asmCode.size());
23+
}
24+
25+
List<OpcodeSource> opcodeSources = new ArrayList<>();
26+
for (int i = 0; i < asmCode.size(); i++) {
27+
OpcodeSource opcodeSource = new OpcodeSource(opcodes.get(i));
28+
Code currentAsmOpcode = asmCode.get(i);
29+
opcodeSource.setBegin(currentAsmOpcode.getBegin());
30+
opcodeSource.setEnd(currentAsmOpcode.getEnd());
31+
opcodeSources.add(opcodeSource);
32+
}
33+
34+
return opcodeSources;
35+
}
36+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package net.nandgr.debugger.report;
2+
3+
import org.apache.velocity.Template;
4+
import org.apache.velocity.VelocityContext;
5+
import org.apache.velocity.app.VelocityEngine;
6+
import java.io.File;
7+
import java.io.IOException;
8+
import java.io.StringWriter;
9+
import java.nio.file.Files;
10+
import java.util.Properties;
11+
12+
public class Report {
13+
14+
private static final String REPORT_FILE_NAME = "debug.html";
15+
private static final String TEMPLATE_FILE = "template/graph_template.html";
16+
17+
private final String source;
18+
private final String trace;
19+
private final String graph;
20+
21+
public Report(String source, String trace, String graph) {
22+
this.source = source;
23+
this.trace = trace;
24+
this.graph = graph;
25+
}
26+
27+
public void createReport() throws ReportException {
28+
File debugFile = new File(REPORT_FILE_NAME);
29+
try {
30+
if (!debugFile.createNewFile()) {
31+
throw new ReportException("Report file cannot be created");
32+
}
33+
} catch (IOException e) {
34+
throw new ReportException("Failed creating report", e);
35+
}
36+
37+
VelocityEngine velocityEngine = new VelocityEngine();
38+
Properties p = new Properties();
39+
p.setProperty("resource.loader", "class");
40+
p.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
41+
velocityEngine.init(p);
42+
Template template = velocityEngine.getTemplate(TEMPLATE_FILE);
43+
VelocityContext velocityContext = new VelocityContext();
44+
velocityContext.put("trace", trace);
45+
velocityContext.put("graph", graph);
46+
velocityContext.put("source", source);
47+
StringWriter stringWriter = new StringWriter();
48+
template.merge(velocityContext, stringWriter);
49+
try {
50+
Files.write(debugFile.toPath(), stringWriter.toString().getBytes());
51+
} catch (IOException e) {
52+
throw new ReportException("Failed when writing into report file", e);
53+
}
54+
}
55+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package net.nandgr.debugger.report;
2+
3+
public class ReportException extends Exception {
4+
5+
public ReportException(String message) {
6+
super(message);
7+
}
8+
9+
public ReportException(String message, Throwable cause) {
10+
super(message, cause);
11+
}
12+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package net.nandgr.debugger.solc;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import net.nandgr.debugger.solc.solcjson.SolcOutput;
5+
6+
import java.io.BufferedReader;
7+
import java.io.File;
8+
import java.io.IOException;
9+
import java.io.InputStreamReader;
10+
import java.nio.file.Files;
11+
import java.nio.file.Paths;
12+
import java.util.Arrays;
13+
import java.util.concurrent.TimeUnit;
14+
import java.util.regex.Pattern;
15+
16+
public class Solc {
17+
18+
private final String fileName;
19+
20+
public Solc(String fileName) {
21+
this.fileName = fileName;
22+
}
23+
24+
public SolcOutput compile() throws IOException, InterruptedException {
25+
String json = compileSource();
26+
ObjectMapper objectMapper = new ObjectMapper();
27+
return objectMapper.readValue(json, SolcOutput.class);
28+
}
29+
30+
private String compileSource() throws InterruptedException, IOException {
31+
ProcessBuilder builder = new ProcessBuilder("solc", "--pretty-json", "--combined-json","asm,bin-runtime", fileName);
32+
33+
builder.inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE);
34+
Process p = builder.start();
35+
BufferedReader buf = new BufferedReader(new InputStreamReader(p.getInputStream()));
36+
String line;
37+
StringBuilder output = new StringBuilder();
38+
while ((line = buf.readLine()) != null) {
39+
output.append(line).append(System.lineSeparator());
40+
}
41+
42+
p.waitFor(5, TimeUnit.MINUTES);
43+
buf.close();
44+
return output.toString();
45+
}
46+
47+
public static boolean checkSolcInClasspath() {
48+
final String SOLC_EXEC_NAME = "solc";
49+
return Arrays.stream(System.getenv("PATH").split(Pattern.quote(File.pathSeparator)))
50+
.map(Paths::get)
51+
.anyMatch(path -> Files.exists(path.resolve(SOLC_EXEC_NAME)));
52+
}
53+
}

0 commit comments

Comments
 (0)