OSDN Git Service

add control flow extractor
authorU-garnet\tamada <tamada@garnet.(none)>
Fri, 30 Apr 2010 11:44:58 +0000 (20:44 +0900)
committerU-garnet\tamada <tamada@garnet.(none)>
Fri, 30 Apr 2010 11:44:58 +0000 (20:44 +0900)
.gitignore [new file with mode: 0644]
opcodes/src/main/java/jp/sourceforge/stigmata/birthmarks/BasicBlock.java [new file with mode: 0755]
opcodes/src/main/java/jp/sourceforge/stigmata/birthmarks/ControlFlowGraph.java [new file with mode: 0755]
opcodes/src/main/java/jp/sourceforge/stigmata/birthmarks/ControlFlowGraphExtractVisitor.java [new file with mode: 0755]
opcodes/src/test/java/jp/sourceforge/stigmata/birthmarks/ControlFlowGraphTest.java [new file with mode: 0755]
opcodes/src/test/resources/resources/MyServer.class [new file with mode: 0755]
opcodes/src/test/resources/resources/MyServer.java [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..b60de5b
--- /dev/null
@@ -0,0 +1 @@
+**/target
diff --git a/opcodes/src/main/java/jp/sourceforge/stigmata/birthmarks/BasicBlock.java b/opcodes/src/main/java/jp/sourceforge/stigmata/birthmarks/BasicBlock.java
new file mode 100755 (executable)
index 0000000..79f04f0
--- /dev/null
@@ -0,0 +1,24 @@
+package jp.sourceforge.stigmata.birthmarks;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.objectweb.asm.tree.AbstractInsnNode;\r
+import org.objectweb.asm.tree.InsnNode;\r
+\r
+public class BasicBlock {\r
+    private List<AbstractInsnNode> nodes = new ArrayList<AbstractInsnNode>();\r
+\r
+    BasicBlock(){\r
+    }\r
+\r
+    public BasicBlock(InsnNode[] nodeArray){\r
+        for(InsnNode node: nodeArray){\r
+            nodes.add(node);\r
+        }\r
+    }\r
+\r
+    void addNode(AbstractInsnNode node){\r
+        nodes.add(node);\r
+    }\r
+}\r
diff --git a/opcodes/src/main/java/jp/sourceforge/stigmata/birthmarks/ControlFlowGraph.java b/opcodes/src/main/java/jp/sourceforge/stigmata/birthmarks/ControlFlowGraph.java
new file mode 100755 (executable)
index 0000000..9dddd84
--- /dev/null
@@ -0,0 +1,114 @@
+package jp.sourceforge.stigmata.birthmarks;\r
+\r
+import java.util.ArrayList;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import org.objectweb.asm.tree.AbstractInsnNode;\r
+import org.objectweb.asm.tree.JumpInsnNode;\r
+import org.objectweb.asm.tree.LabelNode;\r
+import org.objectweb.asm.tree.LookupSwitchInsnNode;\r
+import org.objectweb.asm.tree.MethodNode;\r
+import org.objectweb.asm.tree.TableSwitchInsnNode;\r
+import org.objectweb.asm.tree.TryCatchBlockNode;\r
+\r
+public class ControlFlowGraph {\r
+    private String name;\r
+    private boolean includeException;\r
+    private MethodNode method;\r
+    private BasicBlock[] blocks;\r
+\r
+    public ControlFlowGraph(String name, MethodNode node){\r
+        this(name, node, false);\r
+    }\r
+\r
+    public ControlFlowGraph(String name, MethodNode node, boolean includeException){\r
+        this.includeException = includeException;\r
+        this.name = name;\r
+        this.method = node;\r
+        parse(method);\r
+    }\r
+\r
+    public String getName(){\r
+        return name;\r
+    }\r
+\r
+    public int getBasicBlockSize(){\r
+        return blocks.length;\r
+    }\r
+\r
+    public boolean isIncludingExceptionFlow(){\r
+        return includeException;\r
+    }\r
+\r
+    public void setIncludingExceptionFlow(boolean includeException){\r
+        boolean oldvalue = this.includeException;\r
+        this.includeException = includeException;\r
+        if(oldvalue != includeException){\r
+            parse(method);\r
+        }\r
+    }\r
+\r
+    private void separateBasicBlock(MethodNode node){\r
+        Set<LabelNode> jumpedTarget = new HashSet<LabelNode>();\r
+        int size = node.instructions.size();\r
+\r
+        for(int i = 0; i < size; i++){\r
+            AbstractInsnNode inst = node.instructions.get(i);\r
+            switch(inst.getType()){\r
+            case AbstractInsnNode.JUMP_INSN:\r
+                jumpedTarget.add(((JumpInsnNode)inst).label);\r
+                break;\r
+            case AbstractInsnNode.LOOKUPSWITCH_INSN:\r
+            {\r
+                LookupSwitchInsnNode lookup = (LookupSwitchInsnNode)inst;\r
+                jumpedTarget.add(lookup.dflt);\r
+                for(Object label: lookup.labels){\r
+                    jumpedTarget.add((LabelNode)label);\r
+                }\r
+            }\r
+            case AbstractInsnNode.TABLESWITCH_INSN:\r
+            {\r
+                TableSwitchInsnNode lookup = (TableSwitchInsnNode)inst;\r
+                jumpedTarget.add(lookup.dflt);\r
+                for(Object label: lookup.labels){\r
+                    jumpedTarget.add((LabelNode)label);\r
+                }\r
+            }\r
+            }\r
+        }\r
+        if(isIncludingExceptionFlow()){\r
+            for(Object object: node.tryCatchBlocks){\r
+                jumpedTarget.add(((TryCatchBlockNode)object).handler);\r
+            }\r
+        }\r
+\r
+        List<BasicBlock> blockList = new ArrayList<BasicBlock>();\r
+        BasicBlock block = new BasicBlock();\r
+        for(int i = 0; i < size; i++){\r
+            AbstractInsnNode inst = node.instructions.get(i);\r
+            if(jumpedTarget.contains(inst)){\r
+                blockList.add(block);\r
+                block = new BasicBlock();\r
+            }\r
+\r
+            block.addNode(inst);\r
+\r
+            if(inst.getType() == AbstractInsnNode.JUMP_INSN\r
+                    || inst.getType() == AbstractInsnNode.TABLESWITCH_INSN\r
+                    || inst.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN){\r
+                blockList.add(block);\r
+                block = new BasicBlock();\r
+            }\r
+        }\r
+        this.blocks = blockList.toArray(new BasicBlock[blockList.size()]);\r
+    }\r
+\r
+    /**\r
+     * \83R\83\93\83g\83\8d\81[\83\8b\83t\83\8d\81[\83O\83\89\83t\82ð\8dì\90¬\82·\82é\81D\r
+     */\r
+    private void parse(MethodNode node){\r
+        separateBasicBlock(node);\r
+    }\r
+}\r
diff --git a/opcodes/src/main/java/jp/sourceforge/stigmata/birthmarks/ControlFlowGraphExtractVisitor.java b/opcodes/src/main/java/jp/sourceforge/stigmata/birthmarks/ControlFlowGraphExtractVisitor.java
new file mode 100755 (executable)
index 0000000..ae509b6
--- /dev/null
@@ -0,0 +1,49 @@
+package jp.sourceforge.stigmata.birthmarks;
+
+/*
+ * $Id$
+ */
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ *
+ *
+ * @author tamada
+ * @version $Revision$
+ */
+public class ControlFlowGraphExtractVisitor extends ClassAdapter{
+    private Map<String, MethodNode> opcodesMap = new LinkedHashMap<String, MethodNode>();
+
+    public ControlFlowGraphExtractVisitor(ClassVisitor visitor){
+        super(visitor);
+    }
+
+    public Iterator<String> getMethodNames(){
+        return opcodesMap.keySet().iterator();
+    }
+
+    public ControlFlowGraph getGraph(String name){
+        return buildControlFlow(name, opcodesMap.get(name));
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions){
+        MethodNode node = new MethodNode(access, name, descriptor, signature, exceptions);
+
+        opcodesMap.put(name + descriptor, node);
+
+        return node;
+    }
+
+    private ControlFlowGraph buildControlFlow(String methodName, MethodNode node){
+        return new ControlFlowGraph(methodName, node);
+    }
+}
diff --git a/opcodes/src/test/java/jp/sourceforge/stigmata/birthmarks/ControlFlowGraphTest.java b/opcodes/src/test/java/jp/sourceforge/stigmata/birthmarks/ControlFlowGraphTest.java
new file mode 100755 (executable)
index 0000000..8775c48
--- /dev/null
@@ -0,0 +1,38 @@
+package jp.sourceforge.stigmata.birthmarks;\r
+\r
+import java.util.Iterator;\r
+\r
+import junit.framework.Assert;\r
+\r
+import org.junit.Before;\r
+import org.junit.Test;\r
+import org.objectweb.asm.ClassReader;\r
+import org.objectweb.asm.ClassWriter;\r
+\r
+public class ControlFlowGraphTest {\r
+    private ControlFlowGraphExtractVisitor visitor;\r
+\r
+    @Before\r
+    public void setUp() throws Exception{\r
+        ClassReader reader = new ClassReader(getClass().getResource("/resources/MyServer.class").openStream());\r
+\r
+        visitor = new ControlFlowGraphExtractVisitor(new ClassWriter(0));\r
+        reader.accept(visitor, 0);\r
+    }\r
+\r
+    @Test\r
+    public void testBasic() throws Exception{\r
+        Iterator<String> iterator = visitor.getMethodNames();\r
+\r
+        Assert.assertTrue(iterator.hasNext());\r
+        Assert.assertEquals("<init>(I)V", iterator.next());\r
+        Assert.assertFalse(iterator.hasNext());\r
+\r
+        ControlFlowGraph graph = visitor.getGraph("<init>(I)V");\r
+\r
+        Assert.assertEquals(6, graph.getBasicBlockSize());\r
+\r
+        graph.setIncludingExceptionFlow(true);\r
+        Assert.assertEquals(7, graph.getBasicBlockSize());\r
+    }\r
+}\r
diff --git a/opcodes/src/test/resources/resources/MyServer.class b/opcodes/src/test/resources/resources/MyServer.class
new file mode 100755 (executable)
index 0000000..a2b2a95
Binary files /dev/null and b/opcodes/src/test/resources/resources/MyServer.class differ
diff --git a/opcodes/src/test/resources/resources/MyServer.java b/opcodes/src/test/resources/resources/MyServer.java
new file mode 100644 (file)
index 0000000..fe91ae0
--- /dev/null
@@ -0,0 +1,20 @@
+import java.io.*;
+import java.net.*;
+
+public class MyServer{
+  private int port;
+  private ServerSocket server;
+
+  public MyServer(int defaultPort){
+    try{
+      if(defaultPort > 0){
+        port = defaultPort;
+        server = new ServerSocket(port);
+      }
+      else{
+        server = new ServerSocket();
+      }
+    } catch(IOException e){
+    }
+  }
+}