From ddf7c3bc3865985aa89aa7cc8bee55f9774b2ba5 Mon Sep 17 00:00:00 2001 From: caipeichao Date: Sat, 10 Dec 2016 13:08:57 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 21d08e7e..5a69a2f4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,35 @@ + java-callgraph: Java Call Graph Utilities ========================================= +# 项目背景 + +笔者试图阅读一些开源项目的源码,发现几个问题: + +- 代码量过于庞大,不知从何看起。 +- 一行行阅读代码无法看到整体结构。 +- 下断点一行行跟踪代码费事费力。 + +此项目解决源码阅读问题,让您快速掌握软件的整体结构,帮助理解软件运行机制。 + +# 使用方法 + +先把代码拉下来,然后执行编译: + + +mvn package -DskipTests + + +这时产生一个文件`javacg-0.1-SNAPSHOT-dycg-agent.jar`,用于做JavaAgent。 + +然后运行需要研究的项目,加上如下参数: + +-javaagent:javacg-dycg-agent.jar="incl=mylib.*,mylib2.*,java.nio.*;excl=java.nio.charset.*" + +运行完成后将会得到一个Xmind文件,用Xmind打开,就可以看到运行的整个过程。 + +# 原始文档 + A suite of programs for generating static and dynamic call graphs in Java. * javacg-static: Reads classes from a jar file, walks down the method bodies and @@ -12,7 +41,7 @@ A suite of programs for generating static and dynamic call graphs in Java. #### Compile -The java-callgraph package is build with maven. Install maven and do: +The java-callgraph package is build with maven. Install maven and do: mvn install From 4c0b787c13745cd6e5080516b9eb4b3a71f2829d Mon Sep 17 00:00:00 2001 From: caipeichao Date: Sat, 10 Dec 2016 13:10:23 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 5a69a2f4..8949dd0e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ java-callgraph: Java Call Graph Utilities -========================================= # 项目背景 From 3685a032132b3d613850acc7429800cb36299ae8 Mon Sep 17 00:00:00 2001 From: caipeichao Date: Sat, 10 Dec 2016 15:46:55 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BB=A5json=E6=96=B9=E5=BC=8F=E8=BE=93?= =?UTF-8?q?=E5=87=BA=E8=BF=BD=E8=B8=AA=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assembly-dyn.xml | 1 + assembly-test.xml | 21 +++ pom.xml | 7 + .../gr/gousiosg/javacg/dyn/CallTrace.java | 47 +++++++ .../gr/gousiosg/javacg/dyn/Instrumenter.java | 7 +- .../java/gr/gousiosg/javacg/dyn/LogFile.java | 61 +++++++++ .../gr/gousiosg/javacg/dyn/MethodStack.java | 120 ----------------- .../gousiosg/javacg/test/TestOneThread.java | 25 ++++ test/test_one_thread.sh | 9 ++ to_xmind.py | 124 ++++++++++++++++++ 10 files changed, 298 insertions(+), 124 deletions(-) create mode 100644 assembly-test.xml create mode 100644 src/main/java/gr/gousiosg/javacg/dyn/CallTrace.java create mode 100644 src/main/java/gr/gousiosg/javacg/dyn/LogFile.java delete mode 100644 src/main/java/gr/gousiosg/javacg/dyn/MethodStack.java create mode 100644 src/main/java/gr/gousiosg/javacg/test/TestOneThread.java create mode 100644 test/test_one_thread.sh create mode 100644 to_xmind.py diff --git a/assembly-dyn.xml b/assembly-dyn.xml index 5c342dcf..5094d853 100644 --- a/assembly-dyn.xml +++ b/assembly-dyn.xml @@ -14,6 +14,7 @@ true javassist:javassist + com.alibaba:fastjson provided diff --git a/assembly-test.xml b/assembly-test.xml new file mode 100644 index 00000000..95cbba51 --- /dev/null +++ b/assembly-test.xml @@ -0,0 +1,21 @@ + + + test + + jar + + false + + + + + gr/gousiosg/javacg/test/*.class + + target/classes + / + + + diff --git a/pom.xml b/pom.xml index 21046a41..62808177 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,12 @@ 3.12.1.GA provided + + com.alibaba + fastjson + 1.2.8 + provided + @@ -37,6 +43,7 @@ assembly-dyn.xml assembly-st.xml + assembly-test.xml diff --git a/src/main/java/gr/gousiosg/javacg/dyn/CallTrace.java b/src/main/java/gr/gousiosg/javacg/dyn/CallTrace.java new file mode 100644 index 00000000..a3cbfbe2 --- /dev/null +++ b/src/main/java/gr/gousiosg/javacg/dyn/CallTrace.java @@ -0,0 +1,47 @@ +package gr.gousiosg.javacg.dyn; + +import com.alibaba.fastjson.JSONObject; + +import java.util.Stack; + +/** + * Created by caipeichao on 16/12/10. + */ +public class CallTrace { + + private static ThreadLocal threadLocal = new ThreadLocal() { + @Override + public CallTrace initialValue() { + return new CallTrace(); + } + }; + + private Stack stack = new Stack(); + + public static void push(String className, String method) { + threadLocal.get().localPush(className, method); + } + + public static void pop() { + threadLocal.get().localPop(); + } + + private void localPush(String className, String method) { + JSONObject json = new JSONObject(); + json.put("@timestamp", System.currentTimeMillis()); + json.put("thread", Thread.currentThread().getId()); + json.put("class", className); + json.put("method", method); + json.put("direction", "in"); + json.put("depth", stack.size()); + stack.push(json); + LogFile.log(json); + } + + private void localPop() { + JSONObject json = stack.pop(); + json.put("@timestamp", System.currentTimeMillis()); + json.put("direction", "out"); + LogFile.log(json); + } +} diff --git a/src/main/java/gr/gousiosg/javacg/dyn/Instrumenter.java b/src/main/java/gr/gousiosg/javacg/dyn/Instrumenter.java index 3aee29b8..149345d0 100644 --- a/src/main/java/gr/gousiosg/javacg/dyn/Instrumenter.java +++ b/src/main/java/gr/gousiosg/javacg/dyn/Instrumenter.java @@ -102,7 +102,7 @@ public static void premain(String argument, Instrumentation instrumentation) { } public byte[] transform(ClassLoader loader, String className, Class clazz, - java.security.ProtectionDomain domain, byte[] bytes) { + java.security.ProtectionDomain domain, byte[] bytes) { boolean enhanceClass = false; String name = className.replace("/", "."); @@ -170,9 +170,8 @@ private void enhanceMethod(CtBehavior method, String className) if (method.getName().equals(name)) methodName = ""; - method.insertBefore("gr.gousiosg.javacg.dyn.MethodStack.push(\"" + className - + ":" + methodName + "\");"); - method.insertAfter("gr.gousiosg.javacg.dyn.MethodStack.pop();"); + method.insertBefore(String.format("gr.gousiosg.javacg.dyn.CallTrace.push(\"%s\",\"%s\");", className, methodName)); + method.insertAfter("gr.gousiosg.javacg.dyn.CallTrace.pop();"); } private static void err(String msg) { diff --git a/src/main/java/gr/gousiosg/javacg/dyn/LogFile.java b/src/main/java/gr/gousiosg/javacg/dyn/LogFile.java new file mode 100644 index 00000000..a1db5966 --- /dev/null +++ b/src/main/java/gr/gousiosg/javacg/dyn/LogFile.java @@ -0,0 +1,61 @@ +package gr.gousiosg.javacg.dyn; + +import com.alibaba.fastjson.JSONObject; + +import java.io.BufferedWriter; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; + +/** + * Created by caipeichao on 16/12/10. + */ +public class LogFile { + private static final LogFile INSTANCE = new LogFile(); + + public static void log(JSONObject json) { + INSTANCE.internalLog(json); + } + + private final BufferedWriter writer; + + public LogFile() { + // 初始化日志文件 + FileOutputStream fout = null; + try { + fout = new FileOutputStream("calltrace.json"); + } catch (FileNotFoundException e) { + } + this.writer = new BufferedWriter(new OutputStreamWriter(fout, Charset.forName("utf8"))); + + // 退出时关闭日志文件 + this.closeWhenExit(); + } + + public void internalLog(JSONObject json) { + try { + String x = json.toJSONString(); + this.writer.write(x); + this.writer.newLine(); + } catch (IOException e) { + } + } + + public void close() { + try { + writer.close(); + } catch (IOException e) { + } + } + + private void closeWhenExit() { + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + close(); + } + }); + } + +} diff --git a/src/main/java/gr/gousiosg/javacg/dyn/MethodStack.java b/src/main/java/gr/gousiosg/javacg/dyn/MethodStack.java deleted file mode 100644 index 90cc7a0f..00000000 --- a/src/main/java/gr/gousiosg/javacg/dyn/MethodStack.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2011 - Georgios Gousios - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package gr.gousiosg.javacg.dyn; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Stack; - -public class MethodStack { - - private static Stack stack = new Stack(); - private static Map, Integer> callgraph = new HashMap, Integer>(); - static FileWriter fw; - static StringBuffer sb; - static long threadid = -1L; - - static { - Runtime.getRuntime().addShutdownHook(new Thread() { - public void run() { - try { - fw.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - //Sort by number of calls - List> keys = new ArrayList>(); - keys.addAll(callgraph.keySet()); - Collections.sort(keys, new Comparator() { - public int compare(Object o1, Object o2) { - Integer v1 = callgraph.get(o1); - Integer v2 = callgraph.get(o2); - return v1.compareTo(v2); - } - }); - - for (Pair key : keys) { - System.out.println(key + " " + callgraph.get(key)); - } - } - }); - File log = new File("calltrace.txt"); - try { - fw = new FileWriter(log); - } catch (Exception e) { - e.printStackTrace(); - } - sb = new StringBuffer(); - } - - public static void push(String callname) throws IOException { - if (threadid == -1) - threadid = Thread.currentThread().getId(); - - if (Thread.currentThread().getId() != threadid) - return; - - if (!stack.isEmpty()) { - Pair p = new Pair(stack.peek(), callname); - if (callgraph.containsKey(p)) - callgraph.put(p, callgraph.get(p) + 1); - else - callgraph.put(p, 1); - } - sb.setLength(0); - sb.append(">[").append(stack.size()).append("]"); - sb.append("[").append(Thread.currentThread().getId()).append("]"); - sb.append(callname).append("=").append(System.nanoTime()).append("\n"); - fw.write(sb.toString()); - stack.push(callname); - } - - public static void pop() throws IOException { - if (threadid == -1) - threadid = Thread.currentThread().getId(); - - if (Thread.currentThread().getId() != threadid) - return; - - String returnFrom = stack.pop(); - sb.setLength(0); - sb.append("<[").append(stack.size()).append("]"); - sb.append("[").append(Thread.currentThread().getId()).append("]"); - sb.append(returnFrom).append("=").append(System.nanoTime()).append("\n"); - fw.write(sb.toString()); - } -} \ No newline at end of file diff --git a/src/main/java/gr/gousiosg/javacg/test/TestOneThread.java b/src/main/java/gr/gousiosg/javacg/test/TestOneThread.java new file mode 100644 index 00000000..7180aff1 --- /dev/null +++ b/src/main/java/gr/gousiosg/javacg/test/TestOneThread.java @@ -0,0 +1,25 @@ +package gr.gousiosg.javacg.test; + +/** + * Created by caipeichao on 16/12/10. + */ +public class TestOneThread { + + public static void main(String[] argv) { + new TestOneThread().run(); + } + + public void run() { + System.out.println("Hello world"); + foo(); + bar(); + } + + public void foo() { + System.out.println("Foo"); + } + + public void bar() { + System.out.println("Bar"); + } +} diff --git a/test/test_one_thread.sh b/test/test_one_thread.sh new file mode 100644 index 00000000..04bdd1d4 --- /dev/null +++ b/test/test_one_thread.sh @@ -0,0 +1,9 @@ +cd "`dirname "$0"`" +cd .. +mvn package -DskipTests +cd target +export CLASSPATH=javacg-0.1-SNAPSHOT-test.jar +java -javaagent:javacg-0.1-SNAPSHOT-dycg-agent.jar="incl=gr.gousiosg.javacg.test.*;" gr.gousiosg.javacg.test.TestOneThread +echo ------------------------ +echo Call trace is: +cat calltrace.json diff --git a/to_xmind.py b/to_xmind.py new file mode 100644 index 00000000..b2a6aa32 --- /dev/null +++ b/to_xmind.py @@ -0,0 +1,124 @@ +import sys + +file=sys.argv[1] + +def main(): + # read traces + traces = list(read_file()) + + # separate threads + thread_traces = separate_threads(traces) + + # make tree for every thread + root = TraceNode('Root') + for thread_id,traces in thread_traces: + t = make_tree(thread_id, traces) + root.add(t) + + # output as xmind + print(xmind(root)) + +def xmind(node): + return '\n'.join(xmind_lines(node)) + +def xmind_lines(node): + lines = [] + lines.append(node.text) + for e in node.children: + for line in xmind_lines(e): + lines.append('\t' + line) + return lines + +def make_tree(name,traces): + root = TraceNode(name) + if not traces: return root + target_depth = traces[0].depth + next_level = [] + for e in traces: + if e.depth != target_depth: + next_level.append(e) + else: + name = simple_method_name(e.method) + make_tree(name, next_level) + next_level = [] + return root + +def simple_method_name(method): + colon = method.rindex(':') + method_name = method[colon+1:] + full_class = method[:colon] + dot = full_class.rindex('.') + simple_class = full_class[dot+1:] + if '$' not in simple_class: return simple_class + dollar = simple_class.rindex('$') + nest_class = simple_class[dollar+1:] + return nest_class + + +def separate_threads(traces): + # all threads + threads = [] + for e in traces: + if e.thread not in threads: + threads.append(e.thread) + + # every thread: + result = [] + for e in threads: + thread_traces = [] + for e2 in traces: + if e2.thread == e: + thread_traces.append(e2) + result.append((e,thread_traces)) + return result + +def read_file(): + with open(file) as f: + for e in f: + e = e.strip() + if not e: continue + yield parse_trace(e) + +def parse_trace(trace): + # direction + result = Trace() + result.direction = trace[0] + + # depth + start = trace.index('[') + end = trace.index(']') + result.depth = trace[start:end+1] + trace = trace[end+1:] + + # thread + start = trace.index('[') + end = trace.index(']') + result.thread = trace[start:end+1] + trace = trace[end+1:] + + # method + start = 0 + end = trace.rindex('=') + result.method = trace[start:end+1] + trace = trace[end+1:] + + # time + result.time = trace + return result + +class Trace: + direction = None + thread = None + depth = None + method = None + time = None + +class TraceNode: + def __init__(self, text): + self.text = text + self.children = [] + + def add(self, node): + self.children.append(node) + +main() From 8c8ac6e8571edbc08b616b2fefb3e3dfbb72a2a3 Mon Sep 17 00:00:00 2001 From: caipeichao Date: Sat, 10 Dec 2016 16:19:45 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=84=E7=90=86?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E7=94=9F=E6=88=90XMIND?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- process_trace.rb => process/process_trace.rb | 0 process/to_xmind.py | 121 ++++++++++++++++++ test/test_one_thread.sh | 3 + to_xmind.py | 124 ------------------- 4 files changed, 124 insertions(+), 124 deletions(-) rename process_trace.rb => process/process_trace.rb (100%) create mode 100644 process/to_xmind.py delete mode 100644 to_xmind.py diff --git a/process_trace.rb b/process/process_trace.rb similarity index 100% rename from process_trace.rb rename to process/process_trace.rb diff --git a/process/to_xmind.py b/process/to_xmind.py new file mode 100644 index 00000000..68fcd9fe --- /dev/null +++ b/process/to_xmind.py @@ -0,0 +1,121 @@ +import sys +import json + +file = sys.argv[1] + + +def main(): + # read traces + traces = list(read_file()) + + # separate threads + thread_traces = separate_threads(traces) + + # make tree for every thread + root = TraceNode('') + for thread_id, traces in thread_traces: + t = make_tree(str(thread_id), traces) + root.add(t) + + # output as xmind + print(xmind(root)) + + +def xmind(node): + return '\n'.join(xmind_lines(node)) + + +def xmind_lines(node): + lines = [] + lines.append(node.text) + for e in node.children: + for line in xmind_lines(e): + lines.append('\t' + line) + return lines + + +def make_tree(name, traces): + root = TraceNode(name) + if not traces: return root + target_depth = traces[0].depth + next_level = [] + for e in traces: + if e.direction == 'in': continue + if e.depth != target_depth: + next_level.append(e) + continue + if e.depth == target_depth: + name = simple_method_name(e.clazz, e.method) + node = make_tree(name, next_level) + root.add(node) + next_level = [] + continue + return root + + +def simple_method_name(full_class, method_name): + dot = full_class.rindex('.') + simple_class = full_class[dot + 1:] + if '$' not in simple_class: return simple_class + '.' + method_name + dollar = simple_class.rindex('$') + nest_class = simple_class[dollar + 1:] + return nest_class + '.' + method_name + + +def separate_threads(traces): + # all threads + threads = [] + for e in traces: + if e.thread not in threads: + threads.append(e.thread) + + # every thread: + result = [] + for e in threads: + thread_traces = [] + for e2 in traces: + if e2.thread == e: + thread_traces.append(e2) + result.append((e, thread_traces)) + return result + + +def read_file(): + with open(file) as f: + for e in f: + e = e.strip() + if not e: continue + yield parse_trace(e) + + +def parse_trace(trace): + trace = json.loads(trace) + result = Trace() + result.time = trace['@timestamp'] + result.method = trace['method'] + result.clazz = trace['class'] + result.depth = trace['depth'] + result.thread = trace['thread'] + result.direction = trace['direction'] + return result + + +class Trace: + direction = None + thread = None + depth = None + clazz = None + method = None + time = None + + +class TraceNode: + def __init__(self, text): + self.text = text + self.children = [] + + def add(self, node): + self.children.append(node) + + +main() diff --git a/test/test_one_thread.sh b/test/test_one_thread.sh index 04bdd1d4..7c3d483b 100644 --- a/test/test_one_thread.sh +++ b/test/test_one_thread.sh @@ -7,3 +7,6 @@ java -javaagent:javacg-0.1-SNAPSHOT-dycg-agent.jar="incl=gr.gousiosg.javacg.test echo ------------------------ echo Call trace is: cat calltrace.json +echo ------------------------ +echo To xmind: +python3 ../process/to_xmind.py calltrace.json diff --git a/to_xmind.py b/to_xmind.py deleted file mode 100644 index b2a6aa32..00000000 --- a/to_xmind.py +++ /dev/null @@ -1,124 +0,0 @@ -import sys - -file=sys.argv[1] - -def main(): - # read traces - traces = list(read_file()) - - # separate threads - thread_traces = separate_threads(traces) - - # make tree for every thread - root = TraceNode('Root') - for thread_id,traces in thread_traces: - t = make_tree(thread_id, traces) - root.add(t) - - # output as xmind - print(xmind(root)) - -def xmind(node): - return '\n'.join(xmind_lines(node)) - -def xmind_lines(node): - lines = [] - lines.append(node.text) - for e in node.children: - for line in xmind_lines(e): - lines.append('\t' + line) - return lines - -def make_tree(name,traces): - root = TraceNode(name) - if not traces: return root - target_depth = traces[0].depth - next_level = [] - for e in traces: - if e.depth != target_depth: - next_level.append(e) - else: - name = simple_method_name(e.method) - make_tree(name, next_level) - next_level = [] - return root - -def simple_method_name(method): - colon = method.rindex(':') - method_name = method[colon+1:] - full_class = method[:colon] - dot = full_class.rindex('.') - simple_class = full_class[dot+1:] - if '$' not in simple_class: return simple_class - dollar = simple_class.rindex('$') - nest_class = simple_class[dollar+1:] - return nest_class - - -def separate_threads(traces): - # all threads - threads = [] - for e in traces: - if e.thread not in threads: - threads.append(e.thread) - - # every thread: - result = [] - for e in threads: - thread_traces = [] - for e2 in traces: - if e2.thread == e: - thread_traces.append(e2) - result.append((e,thread_traces)) - return result - -def read_file(): - with open(file) as f: - for e in f: - e = e.strip() - if not e: continue - yield parse_trace(e) - -def parse_trace(trace): - # direction - result = Trace() - result.direction = trace[0] - - # depth - start = trace.index('[') - end = trace.index(']') - result.depth = trace[start:end+1] - trace = trace[end+1:] - - # thread - start = trace.index('[') - end = trace.index(']') - result.thread = trace[start:end+1] - trace = trace[end+1:] - - # method - start = 0 - end = trace.rindex('=') - result.method = trace[start:end+1] - trace = trace[end+1:] - - # time - result.time = trace - return result - -class Trace: - direction = None - thread = None - depth = None - method = None - time = None - -class TraceNode: - def __init__(self, text): - self.text = text - self.children = [] - - def add(self, node): - self.children.append(node) - -main() From c54154c4fbdd215336a35e51f53d94a87dcc75c9 Mon Sep 17 00:00:00 2001 From: caipeichao Date: Sat, 10 Dec 2016 16:41:28 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E6=8A=9B=E5=BC=82=E5=B8=B8=E8=BF=BD?= =?UTF-8?q?=E8=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gr/gousiosg/javacg/dyn/Instrumenter.java | 5 ++-- .../gousiosg/javacg/test/TestException.java | 26 +++++++++++++++++++ test/{test_one_thread.sh => test.sh} | 11 +++++++- 3 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 src/main/java/gr/gousiosg/javacg/test/TestException.java rename test/{test_one_thread.sh => test.sh} (59%) diff --git a/src/main/java/gr/gousiosg/javacg/dyn/Instrumenter.java b/src/main/java/gr/gousiosg/javacg/dyn/Instrumenter.java index 149345d0..ce4fa192 100644 --- a/src/main/java/gr/gousiosg/javacg/dyn/Instrumenter.java +++ b/src/main/java/gr/gousiosg/javacg/dyn/Instrumenter.java @@ -43,6 +43,8 @@ import javassist.CtBehavior; import javassist.CtClass; import javassist.NotFoundException; +import javassist.expr.ExprEditor; +import javassist.expr.MethodCall; public class Instrumenter implements ClassFileTransformer { @@ -169,9 +171,8 @@ private void enhanceMethod(CtBehavior method, String className) if (method.getName().equals(name)) methodName = ""; - method.insertBefore(String.format("gr.gousiosg.javacg.dyn.CallTrace.push(\"%s\",\"%s\");", className, methodName)); - method.insertAfter("gr.gousiosg.javacg.dyn.CallTrace.pop();"); + method.insertAfter("gr.gousiosg.javacg.dyn.CallTrace.pop();", true); } private static void err(String msg) { diff --git a/src/main/java/gr/gousiosg/javacg/test/TestException.java b/src/main/java/gr/gousiosg/javacg/test/TestException.java new file mode 100644 index 00000000..df488366 --- /dev/null +++ b/src/main/java/gr/gousiosg/javacg/test/TestException.java @@ -0,0 +1,26 @@ +package gr.gousiosg.javacg.test; + +/** + * Created by caipeichao on 16/12/10. + */ +public class TestException { + + public static void main(String[] argv) { + new TestException().run(); + } + + public void run() { + System.out.println("Hello world"); + foo(); + bar(); + } + + public void foo() { + System.out.println("Foo"); + throw new RuntimeException("Bad times"); + } + + public void bar() { + System.out.println("Bar"); + } +} diff --git a/test/test_one_thread.sh b/test/test.sh similarity index 59% rename from test/test_one_thread.sh rename to test/test.sh index 7c3d483b..305c3136 100644 --- a/test/test_one_thread.sh +++ b/test/test.sh @@ -1,9 +1,18 @@ +# check args cd "`dirname "$0"`" +c="$1" +if [ "$c" == "" ] ; then + echo try: + ls ../src/main/java/gr/gousiosg/javacg/test | sed 's/\.java$//g' | xargs -n 1 echo 'bash' "$0" + exit 1 +fi + +# run test cd .. mvn package -DskipTests cd target export CLASSPATH=javacg-0.1-SNAPSHOT-test.jar -java -javaagent:javacg-0.1-SNAPSHOT-dycg-agent.jar="incl=gr.gousiosg.javacg.test.*;" gr.gousiosg.javacg.test.TestOneThread +java -javaagent:javacg-0.1-SNAPSHOT-dycg-agent.jar="incl=gr.gousiosg.javacg.test.*;" gr.gousiosg.javacg.test.$1 echo ------------------------ echo Call trace is: cat calltrace.json