From e3cf53ac0f7cc6afb2a5b30b2ccff82b5800b59d Mon Sep 17 00:00:00 2001 From: Martin Hare Robertson Date: Mon, 12 Apr 2010 17:39:41 +0100 Subject: [PATCH] - Improve comments in the agent package - Cleanup code in agent package --- TestProject/.classpath | 1 + org.intrace/src/org/intrace/agent/Agent.java | 37 +- .../src/org/intrace/agent/AgentSettings.java | 20 +- .../agent/ClassBranchLineAnalysis.java | 113 ++++-- .../org/intrace/agent/ClassTransformer.java | 329 +++++++++++------- .../agent/InstrumentedClassWriter.java | 4 +- .../agent/InstrumentedMethodWriter.java | 83 ++--- .../client/gui/helper/ParsedSettingsData.java | 2 +- .../intrace/shared/AgentConfigConstants.java | 10 +- 9 files changed, 356 insertions(+), 243 deletions(-) diff --git a/TestProject/.classpath b/TestProject/.classpath index 0aac597..5707aa8 100644 --- a/TestProject/.classpath +++ b/TestProject/.classpath @@ -4,5 +4,6 @@ + diff --git a/org.intrace/src/org/intrace/agent/Agent.java b/org.intrace/src/org/intrace/agent/Agent.java index 0922d08..6452ea8 100644 --- a/org.intrace/src/org/intrace/agent/Agent.java +++ b/org.intrace/src/org/intrace/agent/Agent.java @@ -1,7 +1,5 @@ package org.intrace.agent; - -import java.io.IOException; import java.lang.instrument.Instrumentation; import org.intrace.agent.server.AgentServer; @@ -10,57 +8,66 @@ import org.intrace.output.callers.CallersOutput; import org.intrace.output.trace.TraceOutput; /** - * Trace Agent: Installs a Class Transformer to add trace lines. + * InTrace Agent: Installs a Class Transformer to instrument class bytecode. */ public class Agent { /** - * Agent called on JVM init. + * Entry point when loaded using -agent command line arg. + * * @param agentArgs * @param inst - * @throws IOException */ - public static void premain(String agentArgs, Instrumentation inst) throws IOException + public static void premain(String agentArgs, Instrumentation inst) { initialize(agentArgs, inst); } /** - * Agent called after JVM init. + * Entry point when loaded into running JVM. + * * @param agentArgs * @param inst - * @throws IOException */ - public static void agentmain(String agentArgs, Instrumentation inst) throws IOException + public static void agentmain(String agentArgs, Instrumentation inst) { initialize(agentArgs, inst); } /** * Common init function. + * * @param agentArgs * @param inst - * @throws IOException */ - private static void initialize(String agentArgs, Instrumentation inst) throws IOException + private static void initialize(String agentArgs, Instrumentation inst) { - System.out.println("Loaded Tracing Agent."); + System.out.println("## Loaded InTrace Agent."); - if (agentArgs == null) agentArgs = ""; + if (agentArgs == null) + { + agentArgs = ""; + } + // Setup the output handlers AgentHelper.outputHandlers.put(new TraceOutput(), new Object()); AgentHelper.outputHandlers.put(new CallersOutput(), new Object()); + // Parse startup args AgentSettings args = new AgentSettings(agentArgs); AgentHelper.getResponses(agentArgs); + // Construct Transformer ClassTransformer t = new ClassTransformer(inst, args); inst.addTransformer(t, true); - t.traceLoadedClasses(); + // Ensure loaded classes are traced + t.instrumentLoadedClasses(); + + // Start Server thread Thread traceServer = new Thread(new AgentServer(t)); traceServer.setName("TraceServer"); traceServer.setDaemon(true); traceServer.start(); } -} +} \ No newline at end of file diff --git a/org.intrace/src/org/intrace/agent/AgentSettings.java b/org.intrace/src/org/intrace/agent/AgentSettings.java index e950db4..b46f02a 100644 --- a/org.intrace/src/org/intrace/agent/AgentSettings.java +++ b/org.intrace/src/org/intrace/agent/AgentSettings.java @@ -16,7 +16,7 @@ import org.intrace.shared.AgentConfigConstants; public class AgentSettings { private Pattern classRegex = Pattern.compile(".*"); - private boolean tracingEnabled = false; + private boolean instruEnabled = false; private boolean saveTracedClassfiles = false; private boolean verboseMode = false; private boolean allowJarsToBeTraced = false; @@ -29,7 +29,7 @@ public class AgentSettings public AgentSettings(AgentSettings oldInstance) { classRegex = oldInstance.getClassRegex(); - tracingEnabled = oldInstance.isTracingEnabled(); + instruEnabled = oldInstance.isInstrumentationEnabled(); saveTracedClassfiles = oldInstance.saveTracedClassfiles(); verboseMode = oldInstance.isVerboseMode(); allowJarsToBeTraced = oldInstance.allowJarsToBeTraced(); @@ -54,13 +54,13 @@ public class AgentSettings { verboseMode = false; } - else if (arg.toLowerCase().equals(AgentConfigConstants.TRACING_ENABLED + "true")) + else if (arg.toLowerCase().equals(AgentConfigConstants.INSTRU_ENABLED + "true")) { - tracingEnabled = true; + instruEnabled = true; } - else if (arg.toLowerCase().equals(AgentConfigConstants.TRACING_ENABLED + "false")) + else if (arg.toLowerCase().equals(AgentConfigConstants.INSTRU_ENABLED + "false")) { - tracingEnabled = false; + instruEnabled = false; } else if (arg.toLowerCase().equals(AgentConfigConstants.SAVE_TRACED_CLASSFILES + "true")) { @@ -90,9 +90,9 @@ public class AgentSettings return classRegex; } - public boolean isTracingEnabled() + public boolean isInstrumentationEnabled() { - return tracingEnabled; + return instruEnabled; } public boolean saveTracedClassfiles() @@ -115,7 +115,7 @@ public class AgentSettings { String currentSettings = ""; currentSettings += "Class Regex : " + classRegex + "\n"; - currentSettings += "Tracing Enabled : " + tracingEnabled + "\n"; + currentSettings += "Tracing Enabled : " + instruEnabled + "\n"; currentSettings += "Save Traced Class Files : " + saveTracedClassfiles + "\n"; currentSettings += "Trace Classes in JAR Files : " + allowJarsToBeTraced + "\n"; return currentSettings; @@ -124,7 +124,7 @@ public class AgentSettings public Map getSettingsMap() { Map settingsMap = new HashMap(); - settingsMap.put(AgentConfigConstants.TRACING_ENABLED, Boolean.toString(tracingEnabled)); + settingsMap.put(AgentConfigConstants.INSTRU_ENABLED, Boolean.toString(instruEnabled)); settingsMap.put(AgentConfigConstants.CLASS_REGEX, classRegex.pattern()); settingsMap.put(AgentConfigConstants.ALLOW_JARS_TO_BE_TRACED, Boolean.toString(allowJarsToBeTraced)); settingsMap.put(AgentConfigConstants.VERBOSE_MODE, Boolean.toString(verboseMode)); diff --git a/org.intrace/src/org/intrace/agent/ClassBranchLineAnalysis.java b/org.intrace/src/org/intrace/agent/ClassBranchLineAnalysis.java index a7733df..50b9ff9 100644 --- a/org.intrace/src/org/intrace/agent/ClassBranchLineAnalysis.java +++ b/org.intrace/src/org/intrace/agent/ClassBranchLineAnalysis.java @@ -12,56 +12,104 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.commons.EmptyVisitor; /** - * First pass analysis phase + * InTrace uses ASM to instrument class files. However, ASM traverses bytecode + * linearly which means some information is not available when we need it. This + * class implements a first pass analysis phase to collect information which we + * can't collect during the transformation phase. + *

+ * This analysis collects two sets of data. + *

    + *
  • Reverse GOTO Lines + *
  • Method Entry Line + *
+ *

Reverse GOTO Lines

This analysis records the target line number of + * GOTOs that jump backwards in the code. + * + *

Example:

+ * + *
+ *  1. public void method()
+ *  2. {
+ *  3.   do
+ *  4.   {
+ *  5.     // Branch C
+ *  6.     // Branch C
+ *  7.   }
+ *  8.   while (condition)
+ *  9. }
+ * 
+ * + * We want to capture line 5 and line 9. Example 1 gets transformed into the + * following bytecode: + * + *
+ *  5. label1:
+ *  5. // Branch C
+ *  6. // Branch C
+ *  8. if (condition) goto label1
+ * 
+ * + *

Line 5:

+ *
    + *
  • {@link ClassBranchLineAnalysis#visitLineNumber(int, Label)} is called and + * we record a mapping from label1 to line 5. + *
+ * + *

Line 8:

+ *
    + *
  • {@link ClassBranchLineAnalysis#visitJumpInsn(int, Label)} is called with + * a GOTO instruction so we check whether we have already seen the target label. + * In this case, we have so we mark the target line number as a reverse GOTO. + *
+ * + *

Method Entry Line

This analysis records the first source line of a + * method. This is necessary so that the transformation phase can add an entry + * trace line in the call to {@link InstrumentedMethodWriter#visitCode()} and + * know the source line. */ public class ClassBranchLineAnalysis extends EmptyVisitor { - public final Map> methodBranchTraceLines = new HashMap>(); - public final Map methodEntryLine = new HashMap(); - private Set branchTraceLines = new HashSet(); - private final Map methodLabelLineNos = new HashMap(); - private String methodSig; - private boolean traceThisLine = false; - private boolean recordedMethodEntryLine = false; + // Output of this analysis + public final Map> methodReverseGOTOLines = new HashMap>(); + public final Map methodEntryLines = new HashMap(); + + // Intermediate fields + private Set currentMethod_reverseGOTOLines = new HashSet(); + private final Map currentMethod_labelLineNos = new HashMap(); + private String currentMethod_sig; + private boolean currentMethod_recordedEntryLine = false; @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { - methodLabelLineNos.clear(); - methodSig = name + desc; - recordedMethodEntryLine = false; + currentMethod_labelLineNos.clear(); + currentMethod_sig = name + desc; + currentMethod_recordedEntryLine = false; return this; } @Override public void visitLineNumber(int xiLineNo, Label xiLabel) { - if (!recordedMethodEntryLine) + if (!currentMethod_recordedEntryLine) { - methodEntryLine.put(methodSig, xiLineNo); - recordedMethodEntryLine = true; - } - methodLabelLineNos.put(xiLabel, xiLineNo); - if (traceThisLine) - { - branchTraceLines.add(xiLineNo); - traceThisLine = false; + methodEntryLines.put(currentMethod_sig, xiLineNo); + currentMethod_recordedEntryLine = true; } + + currentMethod_labelLineNos.put(xiLabel, xiLineNo); } @Override public void visitJumpInsn(int xiOpCode, Label xiBranchLabel) { - if (xiOpCode != GOTO) + if (xiOpCode == GOTO) { - traceThisLine= true; - } - else - { - Integer lineNo = methodLabelLineNos.get(xiBranchLabel); + Integer lineNo = currentMethod_labelLineNos.get(xiBranchLabel); if (lineNo != null) { - branchTraceLines.add(lineNo); + currentMethod_reverseGOTOLines.add(lineNo); } } } @@ -69,11 +117,12 @@ public class ClassBranchLineAnalysis extends EmptyVisitor @Override public void visitEnd() { - if (methodSig != null) + if (currentMethod_sig != null) { - methodBranchTraceLines.put(methodSig, branchTraceLines); - methodSig = null; - branchTraceLines = new HashSet(); + methodReverseGOTOLines.put(currentMethod_sig, + currentMethod_reverseGOTOLines); + currentMethod_sig = null; + currentMethod_reverseGOTOLines = new HashSet(); } } } diff --git a/org.intrace/src/org/intrace/agent/ClassTransformer.java b/org.intrace/src/org/intrace/agent/ClassTransformer.java index 1ccfeb2..a9bbc73 100644 --- a/org.intrace/src/org/intrace/agent/ClassTransformer.java +++ b/org.intrace/src/org/intrace/agent/ClassTransformer.java @@ -18,20 +18,28 @@ import org.intrace.output.AgentHelper; import org.objectweb.asm.ClassReader; /** - * Uses ASM2 to transform class files to add Trace output. + * Uses ASM2 to transform class files to add Trace instrumentation. */ public class ClassTransformer implements ClassFileTransformer { /** * Map of modified class names to their original bytes */ - private final Set modifiedClasses = - new ConcurrentSkipListSet(); + private final Set modifiedClasses = new ConcurrentSkipListSet(); + + /** + * Instrumentation interface. + */ private final Instrumentation inst; - private final AgentSettings args; + + /** + * Settings for this Transformer + */ + private final AgentSettings settings; /** * cTor + * * @param xiInst * @param xiEnableTracing * @param xiClassRegex @@ -42,81 +50,41 @@ public class ClassTransformer implements ClassFileTransformer public ClassTransformer(Instrumentation xiInst, AgentSettings xiArgs) { inst = xiInst; - args = xiArgs; - if (args.isVerboseMode()) + settings = xiArgs; + if (settings.isVerboseMode()) { - System.out.println(args.toString()); + System.out.println(settings.toString()); } } /** - * Toggle whether tracing is enabled - * @param xiTracingEnabled + * Generate and return instrumented class bytes. + * + * @param xiClassName + * @param classfileBuffer + * @return Instrumented class bytes */ - public void setTracingEnabled(boolean xiOldTracingEnabled) + private byte[] getInstrumentedClassBytes(String xiClassName, + byte[] classfileBuffer) { - if (args.isTracingEnabled() && !xiOldTracingEnabled) - { - traceLoadedClasses(); - } - else if (!args.isTracingEnabled() && xiOldTracingEnabled) - { - recheckModifiedClasses(); - } + ClassReader cr = new ClassReader(classfileBuffer); + ClassBranchLineAnalysis analysis = new ClassBranchLineAnalysis(); + cr.accept(analysis, false); + InstrumentedClassWriter writer = new InstrumentedClassWriter(xiClassName, + cr, analysis); + cr.accept(writer, false); + return writer.toByteArray(); } /** - * Apply Trace transformation to loaded classes. + * Retransform all modified classes. + *

+ * Iterates over all loaded classes and retransforms those which we know we + * have modified. + * * @param xiInst */ - public void traceLoadedClasses() - { - Class[] loadedClasses = inst.getAllLoadedClasses(); - for (Class loadedClass : loadedClasses) - { - if (loadedClass.isAnnotation()) - { - if (args.isVerboseMode()) - { - System.out.println("Ignoring annotation class: " + loadedClass.getCanonicalName()); - } - } - else if (loadedClass.isSynthetic()) - { - if (args.isVerboseMode()) - { - System.out.println("Ignoring synthetic class: " + loadedClass.getCanonicalName()); - } - } - else if (!inst.isModifiableClass(loadedClass)) - { - if (args.isVerboseMode()) - { - System.out.println("Ignoring unmodifiable class: " + loadedClass.getCanonicalName()); - } - } - else if (args.isTracingEnabled() && - isToBeConsideredForCoverage(loadedClass.getName(), loadedClass.getProtectionDomain())) - { - try - { - inst.retransformClasses(loadedClass); - } - catch (Throwable e) - { - // Write exception to stdout - System.out.println(loadedClass.getName()); - e.printStackTrace(); - } - } - } - } - - /** - * Restore original class bytes - * @param xiInst - */ - private void recheckModifiedClasses() + private void retransformModifiedClasses() { Class[] loadedClasses = inst.getAllLoadedClasses(); for (Class loadedClass : loadedClasses) @@ -136,16 +104,40 @@ public class ClassTransformer implements ClassFileTransformer } } - private boolean isToBeConsideredForCoverage(String className, - ProtectionDomain protectionDomain) + /** + * Determine whether a given className is eligible for modification. Any of + * the following conditions will make a class ineligible for instrumentation. + *

    + *
  • Class name which begins with "org.intrace" + *
  • Class name which begins with "org.objectweb.asm" + *
  • The class has already been modified + *
  • Class name ends with "Test" + *
  • Class name doesn't match the regex + *
  • Class is in a JAR and JAR instrumention is disabled + *
+ * + * @param className + * @param protectionDomain + * @return True if the Class with name className should be instrumented. + */ + private boolean isToBeConsideredForInstrumentation( + String className, + ProtectionDomain protectionDomain) { - // Don't modify self - if (className.startsWith("org.intrace") || - className.startsWith("org.objectweb.asm")) + // Don't modify anything if tracing is disabled + if (!settings.isInstrumentationEnabled()) { - if (args.isVerboseMode()) + return false; + } + + // Don't modify self + if (className.startsWith("org.intrace") + || className.startsWith("org.objectweb.asm")) + { + if (settings.isVerboseMode()) { - System.out.println("Ignoring class in gb.instrument package: " + className); + System.out.println("Ignoring class in gb.instrument package: " + + className); } return false; } @@ -153,7 +145,7 @@ public class ClassTransformer implements ClassFileTransformer // Don't modify a class which is already modified if (modifiedClasses.contains(className)) { - if (args.isVerboseMode()) + if (settings.isVerboseMode()) { System.out.println("Ignoring class already modified: " + className); } @@ -165,7 +157,7 @@ public class ClassTransformer implements ClassFileTransformer if (className.endsWith("Test") || p > 0 && className.substring(0, p).endsWith("Test")) { - if (args.isVerboseMode()) + if (settings.isVerboseMode()) { System.out.println("Ignoring class name ending in Test: " + className); } @@ -173,54 +165,63 @@ public class ClassTransformer implements ClassFileTransformer } // Don't modify classes which fail to match the regex - if ((args.getClassRegex() == null) || - !args.getClassRegex().matcher(className).matches()) + if ((settings.getClassRegex() == null) + || !settings.getClassRegex().matcher(className).matches()) { - if (args.isVerboseMode()) + if (settings.isVerboseMode()) { - System.out.println("Ignoring class not matching the active regex: " + className); + System.out.println("Ignoring class not matching the active regex: " + + className); } return false; } // Don't modify a class from a JAR file unless this is allowed CodeSource codeSource = protectionDomain.getCodeSource(); - if (!args.allowJarsToBeTraced() && - (codeSource != null) && - codeSource.getLocation().getPath().endsWith(".jar")) + if (!settings.allowJarsToBeTraced() && (codeSource != null) + && codeSource.getLocation().getPath().endsWith(".jar")) { - if (args.isVerboseMode()) + if (settings.isVerboseMode()) { System.out.println("Ignoring class in a JAR: " + className); } return false; } + + // All checks passed - class can be instrumented return true; } + /** + * java.lang.instrument Entry Point + *

+ * Optionally transform a class file to add instrumentation. + * {@link ClassTransformer#isToBeConsideredForInstrumentation(String, ProtectionDomain)} + * determines whether a class is eligible for instrumentation. + */ @Override - public byte[] transform(ClassLoader loader, - String internalClassName, + public byte[] transform(ClassLoader loader, String internalClassName, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] originalClassfile) - throws IllegalClassFormatException + throws IllegalClassFormatException { String className = internalClassName.replace('/', '.'); - if (args.isTracingEnabled() && - isToBeConsideredForCoverage(className, protectionDomain)) + if (isToBeConsideredForInstrumentation(className, protectionDomain)) { - if (args.isVerboseMode()) + if (settings.isVerboseMode()) { System.out.println("!! Instrumenting class: " + className); } - byte[] newBytes = readAndModifyClassForTracing(className, originalClassfile); - if (args.saveTracedClassfiles()) + byte[] newBytes = getInstrumentedClassBytes(className, originalClassfile); + + if (settings.saveTracedClassfiles()) { try { - File classOut = new File("./genbin/" + internalClassName + "_gen.class"); + File classOut = new File("./genbin/" + internalClassName + + "_gen.class"); File parentDir = classOut.getParentFile(); boolean dirExists = parentDir.exists(); if (!dirExists) @@ -236,8 +237,8 @@ public class ClassTransformer implements ClassFileTransformer } else { - System.out.println("Can't create directory " + parentDir + - " for saving traced classfiles."); + System.out.println("Can't create directory " + parentDir + + " for saving traced classfiles."); } } catch (Exception e) @@ -256,58 +257,134 @@ public class ClassTransformer implements ClassFileTransformer } } - private byte[] readAndModifyClassForTracing(String xiClassName, - byte[] classfileBuffer) + /** + * Consider loaded classes for transformation. Any of the following reasons + * would prevent a loaded class from being eligible for instrumentation. + *

    + *
  • Class is an annotation + *
  • Class is synthetic + *
  • Class is not modifiable + *
  • Class is rejected by + * {@link ClassTransformer#isToBeConsideredForInstrumentation(String, ProtectionDomain)} + *
+ */ + public void instrumentLoadedClasses() { - ClassReader cr = new ClassReader(classfileBuffer); - ClassBranchLineAnalysis analysis = new ClassBranchLineAnalysis(); - cr.accept(analysis, false); - InstrumentedClassWriter writer = new InstrumentedClassWriter(xiClassName, - cr, - analysis); - cr.accept(writer, false); - return writer.toByteArray(); + Class[] loadedClasses = inst.getAllLoadedClasses(); + for (Class loadedClass : loadedClasses) + { + if (loadedClass.isAnnotation()) + { + if (settings.isVerboseMode()) + { + System.out.println("Ignoring annotation class: " + + loadedClass.getCanonicalName()); + } + } + else if (loadedClass.isSynthetic()) + { + if (settings.isVerboseMode()) + { + System.out.println("Ignoring synthetic class: " + + loadedClass.getCanonicalName()); + } + } + else if (!inst.isModifiableClass(loadedClass)) + { + if (settings.isVerboseMode()) + { + System.out.println("Ignoring unmodifiable class: " + + loadedClass.getCanonicalName()); + } + } + else if (isToBeConsideredForInstrumentation( + loadedClass.getName(), + loadedClass + .getProtectionDomain())) + { + try + { + inst.retransformClasses(loadedClass); + } + catch (Throwable e) + { + // Write exception to stdout + System.out.println(loadedClass.getName()); + e.printStackTrace(); + } + } + } } + /** + * Toggle whether instrumentation is enabled + * + * @param xiTracingEnabled + */ + public void setInstrumentationEnabled(boolean xiInstrumentationEnabled) + { + if (xiInstrumentationEnabled) + { + instrumentLoadedClasses(); + } + else if (!xiInstrumentationEnabled) + { + retransformModifiedClasses(); + } + } + + /** + * @return The currently active settings. + */ + public Map getSettings() + { + return settings.getSettingsMap(); + } + + /** + * Handle a message and return a response. + * + * @param message + * @return Response or null if there is no response. + */ public List getResponse(String message) { - AgentSettings oldSettings = new AgentSettings(args); - args.parseArgs(message); + AgentSettings oldSettings = new AgentSettings(settings); + settings.parseArgs(message); - if (args.isVerboseMode() && - (oldSettings.isVerboseMode() != args.isVerboseMode())) + if (settings.isVerboseMode() + && (oldSettings.isVerboseMode() != settings.isVerboseMode())) { - System.out.println(args.toString()); + System.out.println(settings.toString()); } - else if (oldSettings.isTracingEnabled() != args.isTracingEnabled()) + else if (oldSettings.isInstrumentationEnabled() != settings + .isInstrumentationEnabled()) { System.out.println("## Settings Changed"); - setTracingEnabled(oldSettings.isTracingEnabled()); + setInstrumentationEnabled(settings.isInstrumentationEnabled()); } - else if (!oldSettings.getClassRegex().pattern().equals(args.getClassRegex().pattern())) + else if (!oldSettings.getClassRegex().pattern() + .equals(settings.getClassRegex().pattern())) { System.out.println("## Settings Changed"); - recheckModifiedClasses(); - traceLoadedClasses(); + retransformModifiedClasses(); + instrumentLoadedClasses(); } - else if (oldSettings.allowJarsToBeTraced() != args.allowJarsToBeTraced()) + else if (oldSettings.allowJarsToBeTraced() != settings + .allowJarsToBeTraced()) { System.out.println("## Settings Changed"); - recheckModifiedClasses(); - traceLoadedClasses(); + retransformModifiedClasses(); + instrumentLoadedClasses(); } - else if (oldSettings.saveTracedClassfiles() != args.saveTracedClassfiles()) + else if (oldSettings.saveTracedClassfiles() != settings + .saveTracedClassfiles()) { System.out.println("## Settings Changed"); - recheckModifiedClasses(); - traceLoadedClasses(); + retransformModifiedClasses(); + instrumentLoadedClasses(); } return AgentHelper.getResponses(message); } - - public Map getSettings() - { - return args.getSettingsMap(); - } } diff --git a/org.intrace/src/org/intrace/agent/InstrumentedClassWriter.java b/org.intrace/src/org/intrace/agent/InstrumentedClassWriter.java index 6b0a644..2d251bd 100644 --- a/org.intrace/src/org/intrace/agent/InstrumentedClassWriter.java +++ b/org.intrace/src/org/intrace/agent/InstrumentedClassWriter.java @@ -36,8 +36,8 @@ public class InstrumentedClassWriter extends ClassWriter { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); - Set branchTraceLines = analysis.methodBranchTraceLines.get(name + desc); - Integer entryLine = analysis.methodEntryLine.get(name + desc); + Set branchTraceLines = analysis.methodReverseGOTOLines.get(name + desc); + Integer entryLine = analysis.methodEntryLines.get(name + desc); if (branchTraceLines == null) { branchTraceLines = new HashSet(); diff --git a/org.intrace/src/org/intrace/agent/InstrumentedMethodWriter.java b/org.intrace/src/org/intrace/agent/InstrumentedMethodWriter.java index 3dc87c7..dc41b13 100644 --- a/org.intrace/src/org/intrace/agent/InstrumentedMethodWriter.java +++ b/org.intrace/src/org/intrace/agent/InstrumentedMethodWriter.java @@ -12,7 +12,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; /** - * ASM2 MethodVisitor used to add trace to methods. + * ASM2 MethodVisitor used to instrument methods. */ public class InstrumentedMethodWriter extends MethodAdapter { @@ -29,6 +29,7 @@ public class InstrumentedMethodWriter extends MethodAdapter /** * cTor + * * @param xiMethodVisitor * @param xiClassName * @param xiMethodName @@ -37,11 +38,8 @@ public class InstrumentedMethodWriter extends MethodAdapter * @param entryLine */ public InstrumentedMethodWriter(MethodVisitor xiMethodVisitor, - String xiClassName, - String xiMethodName, - String xiDesc, - Set xiBranchTraceLines, - Integer xiEntryLine) + String xiClassName, String xiMethodName, String xiDesc, + Set xiBranchTraceLines, Integer xiEntryLine) { super(xiMethodVisitor); className = xiClassName; @@ -54,12 +52,13 @@ public class InstrumentedMethodWriter extends MethodAdapter @Override public void visitCode() { - generateCallToWriteBranchTrace(TraceType.BEGIN,((entryLine != null ? entryLine : -1))); - traceArgs(); + generateCallToWriteTrace(TraceType.BEGIN, ((entryLine != null ? entryLine + : -1))); + traceMethodArgs(); super.visitCode(); } - private void traceArgs() + private void traceMethodArgs() { Type[] argTypes = Type.getArgumentTypes(methodDescriptor); for (int ii = 0; ii < argTypes.length; ii++) @@ -70,8 +69,8 @@ public class InstrumentedMethodWriter extends MethodAdapter { typeDescriptor = "Ljava/lang/Object;"; } - else if ((argTypes[ii].getSort() == Type.ARRAY) && - (argTypes[ii].getDescriptor().startsWith("[L"))) + else if ((argTypes[ii].getSort() == Type.ARRAY) + && (argTypes[ii].getDescriptor().startsWith("[L"))) { typeDescriptor = "[Ljava/lang/Object;"; } @@ -79,10 +78,9 @@ public class InstrumentedMethodWriter extends MethodAdapter mv.visitLdcInsn(className); mv.visitLdcInsn(methodName); mv.visitVarInsn(Opcodes.ALOAD, ii); - mv.visitMethodInsn(INVOKESTATIC, - HELPER_CLASS, - "arg", - "(Ljava/lang/String;Ljava/lang/String;" + typeDescriptor + ")V"); + mv.visitMethodInsn(INVOKESTATIC, HELPER_CLASS, "arg", + "(Ljava/lang/String;Ljava/lang/String;" + + typeDescriptor + ")V"); } } @@ -90,14 +88,10 @@ public class InstrumentedMethodWriter extends MethodAdapter public void visitLineNumber(int xiLineNumber, Label label) { lineNumber = xiLineNumber; - if (writeTraceLine || - branchTraceLines.contains(xiLineNumber)) + if (writeTraceLine || branchTraceLines.contains(xiLineNumber)) { - generateCallToWriteBranchTrace(TraceType.BRANCH, lineNumber); - if (writeTraceLine) - { - writeTraceLine = false; - } + generateCallToWriteTrace(TraceType.BRANCH, lineNumber); + writeTraceLine = false; } super.visitLineNumber(xiLineNumber, label); } @@ -107,7 +101,7 @@ public class InstrumentedMethodWriter extends MethodAdapter { if (xiOpCode == RETURN) { - generateCallToWriteBranchTrace(TraceType.END, lineNumber); + generateCallToWriteTrace(TraceType.END, lineNumber); } super.visitInsn(xiOpCode); } @@ -119,53 +113,38 @@ public class InstrumentedMethodWriter extends MethodAdapter super.visitJumpInsn(xiOpCode, xiBranchLabel); } - private void generateCallToWriteBranchTrace(TraceType traceType, - int lineNumber) + private void generateCallToWriteTrace(TraceType traceType, int lineNumber) { + mv.visitLdcInsn(className); + mv.visitLdcInsn(methodName); + mv.visitIntInsn(Opcodes.BIPUSH, lineNumber); switch (traceType) { case BEGIN: { - mv.visitLdcInsn(className); - mv.visitLdcInsn(methodName); - mv.visitIntInsn(Opcodes.BIPUSH, lineNumber); - mv.visitMethodInsn(INVOKESTATIC, - HELPER_CLASS, - "enter", - "(Ljava/lang/String;Ljava/lang/String;I)V"); + mv.visitMethodInsn(INVOKESTATIC, HELPER_CLASS, "enter", + "(Ljava/lang/String;Ljava/lang/String;I)V"); } - break; + break; case BRANCH: { - mv.visitLdcInsn(className); - mv.visitLdcInsn(methodName); - mv.visitIntInsn(Opcodes.BIPUSH, lineNumber); - mv.visitMethodInsn(INVOKESTATIC, - HELPER_CLASS, - "branch", - "(Ljava/lang/String;Ljava/lang/String;I)V"); + mv.visitMethodInsn(INVOKESTATIC, HELPER_CLASS, "branch", + "(Ljava/lang/String;Ljava/lang/String;I)V"); } - break; + break; case END: { - mv.visitLdcInsn(className); - mv.visitLdcInsn(methodName); - mv.visitIntInsn(Opcodes.BIPUSH, lineNumber); - mv.visitMethodInsn(INVOKESTATIC, - HELPER_CLASS, - "exit", - "(Ljava/lang/String;Ljava/lang/String;I)V"); + mv.visitMethodInsn(INVOKESTATIC, HELPER_CLASS, "exit", + "(Ljava/lang/String;Ljava/lang/String;I)V"); } - break; + break; } } private enum TraceType { - BEGIN, - BRANCH, - END + BEGIN, BRANCH, END } } diff --git a/org.intrace/src/org/intrace/client/gui/helper/ParsedSettingsData.java b/org.intrace/src/org/intrace/client/gui/helper/ParsedSettingsData.java index 411712f..83b9742 100644 --- a/org.intrace/src/org/intrace/client/gui/helper/ParsedSettingsData.java +++ b/org.intrace/src/org/intrace/client/gui/helper/ParsedSettingsData.java @@ -34,7 +34,7 @@ public class ParsedSettingsData classRegex = settingsMap.get(AgentConfigConstants.CLASS_REGEX); - if ("true".equals(settingsMap.get(AgentConfigConstants.TRACING_ENABLED))) + if ("true".equals(settingsMap.get(AgentConfigConstants.INSTRU_ENABLED))) { instrEnabled = true; } diff --git a/org.intrace/src/org/intrace/shared/AgentConfigConstants.java b/org.intrace/src/org/intrace/shared/AgentConfigConstants.java index 761dd20..af1a683 100644 --- a/org.intrace/src/org/intrace/shared/AgentConfigConstants.java +++ b/org.intrace/src/org/intrace/shared/AgentConfigConstants.java @@ -5,16 +5,16 @@ import java.util.Set; public class AgentConfigConstants { - public static final String CLASS_REGEX = "[regex-"; - public static final String TRACING_ENABLED = "[instru-"; - public static final String SAVE_TRACED_CLASSFILES = "[saveinstru-"; - public static final String VERBOSE_MODE = "[verbose-"; + public static final String CLASS_REGEX = "[regex-"; + public static final String INSTRU_ENABLED = "[instru-"; + public static final String SAVE_TRACED_CLASSFILES = "[saveinstru-"; + public static final String VERBOSE_MODE = "[verbose-"; public static final String ALLOW_JARS_TO_BE_TRACED = "[instrujars-"; public static final Set COMMANDS = new HashSet(); static { COMMANDS.add(CLASS_REGEX + ""); - COMMANDS.add(TRACING_ENABLED + ""); + COMMANDS.add(INSTRU_ENABLED + ""); COMMANDS.add(SAVE_TRACED_CLASSFILES + ""); COMMANDS.add(VERBOSE_MODE + ""); COMMANDS.add(ALLOW_JARS_TO_BE_TRACED + "");