From e4794c323a9268bc2b6fd8f77ad14b8e72e5ced1 Mon Sep 17 00:00:00 2001 From: gadyag Date: Wed, 17 Jan 2018 22:20:20 -0500 Subject: [PATCH 1/3] Support for options to writing output to a file and generate XML instead of text --- .../gr/gousiosg/javacg/stat/ClassVisitor.java | 72 ++++++++++++--- .../javacg/stat/FormatEnumaration.java | 5 + .../gr/gousiosg/javacg/stat/JCallGraph.java | 92 ++++++++++++++++++- .../gousiosg/javacg/stat/MethodVisitor.java | 63 ++++++++++--- 4 files changed, 203 insertions(+), 29 deletions(-) create mode 100644 src/main/java/gr/gousiosg/javacg/stat/FormatEnumaration.java diff --git a/src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java b/src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java index e03d72c6..019b9f14 100644 --- a/src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java +++ b/src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java @@ -36,6 +36,8 @@ import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.MethodGen; +import java.io.PrintStream; + /** * The simplest of class visitors, invokes the method visitor class for each * method found. @@ -45,37 +47,77 @@ public class ClassVisitor extends EmptyVisitor { private JavaClass clazz; private ConstantPoolGen constants; private String classReferenceFormat; - - public ClassVisitor(JavaClass jc) { + private PrintStream output; + private FormatEnumaration format; + + public ClassVisitor(JavaClass jc, PrintStream outputStream, FormatEnumaration format) { clazz = jc; + this.format = format; + this.output = outputStream; constants = new ConstantPoolGen(clazz.getConstantPool()); - classReferenceFormat = "C:" + clazz.getClassName() + " %s"; + switch (format) { + case TXT: + classReferenceFormat = "C:" + clazz.getClassName() + " %s"; + break; + case XML: + classReferenceFormat = "%s"; + break; + default: + throw new RuntimeException("Unsupported format "+format); + } + } public void visitJavaClass(JavaClass jc) { + switch (format) { + case XML: + output.println(""); + break; + } jc.getConstantPool().accept(this); Method[] methods = jc.getMethods(); - for (int i = 0; i < methods.length; i++) + for (int i = 0; i < methods.length; i++) { methods[i].accept(this); + } + switch (format) { + case XML: + output.println(""); + break; + } } public void visitConstantPool(ConstantPool constantPool) { - for (int i = 0; i < constantPool.getLength(); i++) { - Constant constant = constantPool.getConstant(i); - if (constant == null) - continue; - if (constant.getTag() == 7) { - String referencedClass = - constantPool.constantToString(constant); - System.out.println(String.format(classReferenceFormat, - referencedClass)); - } + switch (format) { + case TXT: + for (int i = 0; i < constantPool.getLength(); i++) { + Constant constant = constantPool.getConstant(i); + if (constant == null) + continue; + if (constant.getTag() == 7) { + String referencedClass = + constantPool.constantToString(constant); + output.println(String.format(classReferenceFormat, + referencedClass)); + } + } + case XML: + for (int i = 0; i < constantPool.getLength(); i++) { + Constant constant = constantPool.getConstant(i); + if (constant == null) + continue; + if (constant.getTag() == 7) { + String referencedClass = + constantPool.constantToString(constant); + output.println(String.format(classReferenceFormat, + referencedClass)); + } + } } } public void visitMethod(Method method) { MethodGen mg = new MethodGen(method, clazz.getClassName(), constants); - MethodVisitor visitor = new MethodVisitor(mg, clazz); + MethodVisitor visitor = new MethodVisitor(mg, clazz,output,format); visitor.start(); } diff --git a/src/main/java/gr/gousiosg/javacg/stat/FormatEnumaration.java b/src/main/java/gr/gousiosg/javacg/stat/FormatEnumaration.java new file mode 100644 index 00000000..c9afc34a --- /dev/null +++ b/src/main/java/gr/gousiosg/javacg/stat/FormatEnumaration.java @@ -0,0 +1,5 @@ +package gr.gousiosg.javacg.stat; + +public enum FormatEnumaration { + TXT,XML +} diff --git a/src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java b/src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java index 4d19408d..0dccdc5a 100644 --- a/src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java +++ b/src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java @@ -29,8 +29,12 @@ package gr.gousiosg.javacg.stat; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; import java.util.Enumeration; +import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -46,9 +50,84 @@ public class JCallGraph { public static void main(String[] args) { + FormatEnumaration format = FormatEnumaration.TXT; + PrintStream outputStream = System.out; + List jars = new ArrayList<>(args.length); + if (args.length==0) { + printHelp(); + } + for (int i =0;i%s"; + break; + default: + throw new RuntimeException("Unsupported format "+outputFormat); + } } private String argumentList(Type[] arguments) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < arguments.length; i++) { - if (i != 0) { - sb.append(","); + switch (outputFormat) { + case TXT: + if (i != 0) { + sb.append(","); + } + sb.append(arguments[i].toString()); + break; + case XML: + sb.append(""); + sb.append(arguments[i].getSignature()); + sb.append(""); + break; + default: + throw new RuntimeException("Unsupported format "+outputFormat); } - sb.append(arguments[i].toString()); } return sb.toString(); } @@ -66,13 +92,26 @@ private String argumentList(Type[] arguments) { public void start() { if (mg.isAbstract() || mg.isNative()) return; - for (InstructionHandle ih = mg.getInstructionList().getStart(); + switch (outputFormat) { + case XML: + output.println(""); + output.println(""); + output.println(argumentList(mg.getArgumentTypes())); + output.println(""); + break; + } + for (InstructionHandle ih = mg.getInstructionList().getStart(); ih != null; ih = ih.getNext()) { Instruction i = ih.getInstruction(); if (!visitInstruction(i)) i.accept(this); } + switch (outputFormat) { + case XML: + output.println(""); + break; + } } private boolean visitInstruction(Instruction i) { @@ -84,27 +123,27 @@ private boolean visitInstruction(Instruction i) { @Override public void visitINVOKEVIRTUAL(INVOKEVIRTUAL i) { - System.out.println(String.format(format,"M",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp)))); + output.println(String.format(format,"M",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp)))); } @Override public void visitINVOKEINTERFACE(INVOKEINTERFACE i) { - System.out.println(String.format(format,"I",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp)))); + output.println(String.format(format,"I",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp)))); } @Override public void visitINVOKESPECIAL(INVOKESPECIAL i) { - System.out.println(String.format(format,"O",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp)))); + output.println(String.format(format,"O",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp)))); } @Override public void visitINVOKESTATIC(INVOKESTATIC i) { - System.out.println(String.format(format,"S",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp)))); + output.println(String.format(format,"S",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp)))); } @Override public void visitINVOKEDYNAMIC(INVOKEDYNAMIC i) { - System.out.println(String.format(format,"D",i.getType(cp),i.getMethodName(cp), + output.println(String.format(format,"D",i.getType(cp),i.getMethodName(cp), argumentList(i.getArgumentTypes(cp)))); } } From 7def266547a2786595280738ccf1c2e7612dc6c9 Mon Sep 17 00:00:00 2001 From: gadyag Date: Wed, 24 Jan 2018 18:49:51 -0500 Subject: [PATCH 2/3] Support for options to writing output to a file and generate XML instead of text --- .../gr/gousiosg/javacg/stat/ClassVisitor.java | 91 +++++++++++++++++-- .../gr/gousiosg/javacg/stat/JCallGraph.java | 11 +++ .../gousiosg/javacg/stat/MethodVisitor.java | 75 +++++++++------ 3 files changed, 141 insertions(+), 36 deletions(-) diff --git a/src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java b/src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java index 019b9f14..dbfe7221 100644 --- a/src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java +++ b/src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java @@ -28,11 +28,7 @@ package gr.gousiosg.javacg.stat; -import org.apache.bcel.classfile.Constant; -import org.apache.bcel.classfile.ConstantPool; -import org.apache.bcel.classfile.EmptyVisitor; -import org.apache.bcel.classfile.JavaClass; -import org.apache.bcel.classfile.Method; +import org.apache.bcel.classfile.*; import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.MethodGen; @@ -49,6 +45,7 @@ public class ClassVisitor extends EmptyVisitor { private String classReferenceFormat; private PrintStream output; private FormatEnumaration format; + private ConstantPool currentConstantPool; public ClassVisitor(JavaClass jc, PrintStream outputStream, FormatEnumaration format) { clazz = jc; @@ -60,7 +57,7 @@ public ClassVisitor(JavaClass jc, PrintStream outputStream, FormatEnumaration fo classReferenceFormat = "C:" + clazz.getClassName() + " %s"; break; case XML: - classReferenceFormat = "%s"; + classReferenceFormat = "%s"; break; default: throw new RuntimeException("Unsupported format "+format); @@ -72,6 +69,16 @@ public void visitJavaClass(JavaClass jc) { switch (format) { case XML: output.println(""); + String[] names = jc.getInterfaceNames(); + if (names != null && names.length>0) { + output.println(""); + for (String name:names) { + output.print(""); + output.print(name); + output.println(""); + } + output.println(""); + } break; } jc.getConstantPool().accept(this); @@ -106,10 +113,13 @@ public void visitConstantPool(ConstantPool constantPool) { if (constant == null) continue; if (constant.getTag() == 7) { + output.print(""); String referencedClass = constantPool.constantToString(constant); - output.println(String.format(classReferenceFormat, - referencedClass)); + output.print(xmlEscapeText(referencedClass)); + output.println(""); } } } @@ -124,4 +134,69 @@ public void visitMethod(Method method) { public void start() { visitJavaClass(clazz); } + + /** + * Encode special charaters for XML + * @param t + * @return + */ + static String xmlEscapeText(String t) { + StringBuilder sb = null; + for(int i = 0; i < t.length(); i++){ + char c = t.charAt(i); + switch(c){ + case '<': + if (sb==null) { + sb = new StringBuilder(t.length()+10); + sb.append(t.substring(0,i)); + } + sb.append("<"); + break; + case '>': + if (sb==null) { + sb = new StringBuilder(t.length()+10); + sb.append(t.substring(0,i)); + } + sb.append(">"); + break; + case '\"': + if (sb==null) { + sb = new StringBuilder(t.length()+10); + sb.append(t.substring(0,i)); + } + sb.append("""); + break; + case '&': + if (sb==null) { + sb = new StringBuilder(t.length()+10); + sb.append(t.substring(0,i)); + } + sb.append("&"); + break; + case '\'': + if (sb==null) { + sb = new StringBuilder(t.length()+10); + sb.append(t.substring(0,i)); + } + sb.append("'"); + break; + default: + if(c>0x7e || c<0x20) { + if (sb==null) { + sb = new StringBuilder(t.length()+10); + sb.append(t.substring(0,i)); + } + sb.append("&#"+((int)c)+";"); + }else if (sb != null) { + sb.append(c); + } + } + } + if (sb==null) { + //re-use original string + return t; + } else { + return sb.toString(); + } + } } diff --git a/src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java b/src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java index 0dccdc5a..88af3917 100644 --- a/src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java +++ b/src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java @@ -127,6 +127,12 @@ public static void main(String[] args) { } ClassParser cp; try { + switch (format) { + case XML: + outputStream.println(""); + outputStream.println(""); + break; + } for (String arg : jars) { File f = new File(arg); @@ -151,6 +157,11 @@ public static void main(String[] args) { visitor.start(); } } + switch (format) { + case XML: + outputStream.println(""); + break; + } } catch (IOException e) { System.err.println("Error while processing jar: " + e.getMessage()); e.printStackTrace(); diff --git a/src/main/java/gr/gousiosg/javacg/stat/MethodVisitor.java b/src/main/java/gr/gousiosg/javacg/stat/MethodVisitor.java index 7a2f25f5..9280414c 100644 --- a/src/main/java/gr/gousiosg/javacg/stat/MethodVisitor.java +++ b/src/main/java/gr/gousiosg/javacg/stat/MethodVisitor.java @@ -56,34 +56,35 @@ public MethodVisitor(MethodGen m, JavaClass jc, PrintStream output, FormatEnumar this.output = output; switch (outputFormat) { case TXT: - this.format = "M:" + visitedClass.getClassName() + ":" + mg.getName() + "(" + argumentList(mg.getArgumentTypes()) + ")" + this.format = "M:" + visitedClass.getClassName() + ":" + mg.getName() + "(" + argumentList(mg.getArgumentTypes(),false) + ")" + " " + "(%s)%s:%s(%s)"; break; case XML: - this.format = "%s"; + this.format = ""; break; default: throw new RuntimeException("Unsupported format "+outputFormat); } } - private String argumentList(Type[] arguments) { + private String argumentList(Type[] arguments,boolean flat) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < arguments.length; i++) { - switch (outputFormat) { - case TXT: - if (i != 0) { - sb.append(","); - } - sb.append(arguments[i].toString()); - break; - case XML: - sb.append(""); - sb.append(arguments[i].getSignature()); - sb.append(""); - break; - default: - throw new RuntimeException("Unsupported format "+outputFormat); + if (flat || outputFormat==FormatEnumaration.TXT) { + if (i != 0) { + sb.append(","); + } + sb.append(arguments[i].toString()); + } else { + switch (outputFormat) { + case XML: + sb.append(""); + sb.append(arguments[i].getSignature()); + sb.append(""); + break; + default: + throw new RuntimeException("Unsupported format "+outputFormat); + } } } return sb.toString(); @@ -94,16 +95,20 @@ public void start() { return; switch (outputFormat) { case XML: - output.println(""); - output.println(""); - output.println(argumentList(mg.getArgumentTypes())); - output.println(""); + output.print(""); break; } for (InstructionHandle ih = mg.getInstructionList().getStart(); ih != null; ih = ih.getNext()) { Instruction i = ih.getInstruction(); - +// if (outputFormat== FormatEnumaration.XML && i instanceof ConstantPushInstruction) { +// ConstantPushInstruction pushInstruction = (ConstantPushInstruction)i; +// output.println(""); +// output.println(pushInstruction.getValue()); +// output.println(""); +// } if (!visitInstruction(i)) i.accept(this); } @@ -114,6 +119,11 @@ public void start() { } } + @Override + public void visitLCONST(LCONST obj) { + super.visitLCONST(obj); + } + private boolean visitInstruction(Instruction i) { short opcode = i.getOpcode(); return ((InstructionConst.getInstruction(opcode) != null) @@ -121,29 +131,38 @@ private boolean visitInstruction(Instruction i) { && !(i instanceof ReturnInstruction)); } +// @Override +// public void visitLocalVariableInstruction(LocalVariableInstruction obj) { +// switch (outputFormat) { +// case XML: +// output.println(""+obj.toString(true)+""); +// break; +// } +// } + @Override public void visitINVOKEVIRTUAL(INVOKEVIRTUAL i) { - output.println(String.format(format,"M",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp)))); + output.println(String.format(format,"M",i.getReferenceType(cp), ClassVisitor.xmlEscapeText(i.getMethodName(cp)),argumentList(i.getArgumentTypes(cp),true))); } @Override public void visitINVOKEINTERFACE(INVOKEINTERFACE i) { - output.println(String.format(format,"I",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp)))); + output.println(String.format(format,"I",i.getReferenceType(cp),ClassVisitor.xmlEscapeText(i.getMethodName(cp)),argumentList(i.getArgumentTypes(cp),true))); } @Override public void visitINVOKESPECIAL(INVOKESPECIAL i) { - output.println(String.format(format,"O",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp)))); + output.println(String.format(format,"O",i.getReferenceType(cp),ClassVisitor.xmlEscapeText(i.getMethodName(cp)),argumentList(i.getArgumentTypes(cp),true))); } @Override public void visitINVOKESTATIC(INVOKESTATIC i) { - output.println(String.format(format,"S",i.getReferenceType(cp),i.getMethodName(cp),argumentList(i.getArgumentTypes(cp)))); + output.println(String.format(format,"S",i.getReferenceType(cp),ClassVisitor.xmlEscapeText(i.getMethodName(cp)),argumentList(i.getArgumentTypes(cp),true))); } @Override public void visitINVOKEDYNAMIC(INVOKEDYNAMIC i) { - output.println(String.format(format,"D",i.getType(cp),i.getMethodName(cp), - argumentList(i.getArgumentTypes(cp)))); + output.println(String.format(format,"D",i.getType(cp),ClassVisitor.xmlEscapeText(i.getMethodName(cp)), + argumentList(i.getArgumentTypes(cp),true))); } } From 416fbff53df2cd41df3f6abe9612825999e4945a Mon Sep 17 00:00:00 2001 From: gadyag Date: Thu, 25 Jan 2018 09:46:22 -0500 Subject: [PATCH 3/3] Support for options to writing output to a file and generate XML instead of text --- src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java b/src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java index dbfe7221..d3ca0ae0 100644 --- a/src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java +++ b/src/main/java/gr/gousiosg/javacg/stat/ClassVisitor.java @@ -40,6 +40,8 @@ */ public class ClassVisitor extends EmptyVisitor { + private static final String OBJECT = Object.class.getName(); + private static final String ENUMERATION = Enum.class.getName(); private JavaClass clazz; private ConstantPoolGen constants; private String classReferenceFormat; @@ -79,6 +81,11 @@ public void visitJavaClass(JavaClass jc) { } output.println(""); } + if (OBJECT.equals(jc.getSuperclassName())==false) { + output.print(""); + output.print(jc.getSuperclassName()); + output.println(""); + } break; } jc.getConstantPool().accept(this);